使用C#实现RSA加密算法(支持中文加密)
1. 简介
信息安全技术选修课上要求自己造轮子实现现代非对称加密算法RSA,自己写了以下试试,感觉还行,分享给有需要的大家。 素数,公钥与私钥都是随机生成的,用base64编码解决了中文加密的问题,没有做签名,但是想加的话也很容易。
2. 需要提前掌握的相关知识
BASE64编码 一文彻底看懂base64编码RSA相关数学知识
3. 原理简述
RSA公开密钥密码体制的原理是: 根据数论,寻求两个大素数比较简单,而将它们的乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥
RSA算法的具体描述如下: 公私钥生成流程图: 加密流程图: 解密流程图: 字符流处理流程图: ![字符流处理流程图](https://img-blog.csdnimg.cn/20210521110428795.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzA1NTU5,size_16,color_FFFFFF,t_70)
4.代码实现
4.1 RSA工具类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EXP3_APP
{
class RSATools
{
public static bool isPrim(long num)
//以6为步进单元判断其是否为素数
{
//两个较小数另外处理
if (num == 2 || num == 3)
return true;
//不在6的倍数两侧的一定不是质数
if (num % 6 != 1 && num % 6 != 5)
return false;
long tmp = (long)Math.Sqrt(num);
//在6的倍数两侧的也可能不是质数
for (long i = 5; i y != 0 ? gcd(y, x % y) : x;
//采用递归的形式,判断两个数是否互质
public static long inverse(long number1, long number3)
//利用欧几里得算法计算m,d的逆元
{
long x1 = 1, x2 = 0, x3 = number3, y1 = 0, y2 = 1, y3 = number1;
long q;
long number4 = 0;
long t1, t2, t3;
while (y3 != 0)
{
if (y3 == 1)
{
number4 = y2;
break;
}
else
{
q = (x3 / y3);
t1 = x1 - q * y1;
t2 = x2 - q * y2;
t3 = x3 - q * y3;
x1 = y1; x2 = y2; x3 = y3;
y1 = t1; y2 = t2; y3 = t3;
}
}
if (number4 < 0)
number4 = number4 + number3;
return number4;
}
public static long getMod(long a, long b, long c)
//利用快速指数模运算,计算m^e mod n
{
//指数 e --> a 底数 m --> b 模数 n --> c
long number3 = 1;
while (a != 0)
{
if (a % 2 == 1)
{
a = a - 1;
number3 = (number3 * b) % c;
}
else
{
a = (a / 2);
b = (b * b) % c;
}
}
return number3;
}
public static long getN(long p, long q) => p * q;
public static long getEuler_N(long p, long q) => (p - 1) * (q - 1);
//求N的欧拉函数
public static void getP_Q(out long p, out long q)
{
Random random = new Random();
while (true)
{
p = random.Next(1000);
q = random.Next(2000);
if (isPrim(p) && isPrim(q)) return;
}
}
public static byte[] longToBytes(long a)
{
byte[] b = new byte[8];
b[0] = (byte)(a);
b[1] = (byte)(a >> 8 & 0xFF);
b[2] = (byte)(a >> 16 & 0xFF);
b[3] = (byte)(a >> 24 & 0xFF);
b[4] = (byte)(a >> 32 & 0xFF);
b[5] = (byte)(a >> 40 & 0xFF);
b[6] = (byte)(a >> 48 & 0xFF);
b[7] = (byte)(a >> 56 & 0xFF);
return b;
}
public static long BytesToLong(byte[] input)
{
uint num = (uint)(((input[0] | (input[1] privateKey; set => privateKey = value; }
public long N { get => n; set => n = value; }
public long Euler_N { get => euler_N; set => euler_N = value; }
public void InitPublicKey()
//初始化公钥
{
RSATools.getP_Q(out p, out q);
euler_N = RSATools.getEuler_N(p, q);
long e;
n = RSATools.getN(p, q);
Random radom = new Random();
while (true)
{
e = radom.Next(655300);
if (e > 1 && e < euler_N && RSATools.gcd(e, euler_N) == 1 && RSATools.isPrim(e)) break;
}
publicKey = new long[2];
publicKey[0] = e;
publicKey[1] = n;
}
public void InitPrivateKey()
//初始化私钥
{
long d = RSATools.inverse(publicKey[0], euler_N);
privateKey = new long[2];
privateKey[0] = d;
privateKey[1] = n;
}
//加密操作
public long encrypt(long plaintext,long[]p_k) => RSATools.getMod(p_k[0], plaintext, p_k[1]);
//解密操作
public long decrypt(long ciphertext) => RSATools.getMod(privateKey[0], ciphertext, privateKey[1]);
public string getCiphertext(string plaintext, long[] p_k)
//加密明文得到密文
{
long[] p_long = RSATools.UTF8ToLong(plaintext);
long[] c_long = new long[p_long.Length];
for (int i = 0; i < p_long.Length; i++)
{
c_long[i] = encrypt(p_long[i],p_k);
}
string c_text = RSATools.longToBase64(c_long);
return c_text;
}
public string getPlaintext(string ciphertext)
//解密密文得到明文
{
long[] c_long = RSATools.Base64ToLong(ciphertext);
long[] p_long = new long[c_long.Length];
for (int i = 0; i < c_long.Length; i++)
{
p_long[i] = decrypt(c_long[i]);
}
string p_text = RSATools.longToUTF8(p_long);
return p_text;
}
}
}
4.3 可视化界面
前面的RSA类已经完全封装,如果不需要可视化以下代码可省略
4.4 可视化事务处理
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace EXP3_APP
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
RSA a, b;
public MainWindow()
{
InitializeComponent();
a = new RSA();
b = new RSA();
}
private void InitPublicKey_A_Click(object sender, RoutedEventArgs e)
{
a.InitPublicKey();
PublicKey_A.Text = a.PublicKey[0].ToString() + "-" + a.PublicKey[1].ToString();
A_P.Text = a.P.ToString();
A_Q.Text = a.Q.ToString();
A_N.Text = a.Euler_N.ToString();
}
private void InitPublicKey_B_Click(object sender, RoutedEventArgs e)
{
b.InitPublicKey();
PublicKey_B.Text = b.PublicKey[0].ToString() + "-" + b.PublicKey[1].ToString();
B_P.Text = b.P.ToString();
B_Q.Text = b.Q.ToString();
B_N.Text = b.Euler_N.ToString();
}
private void InitPrivateKey_A_Click(object sender, RoutedEventArgs e)
{
a.InitPrivateKey();
PrivateKey_A.Text= a.PrivateKey[0].ToString() + "-" + a.PrivateKey[1].ToString();
}
private void InitPrivateKey_B_Click(object sender, RoutedEventArgs e)
{
b.InitPrivateKey();
PrivateKey_B.Text = b.PrivateKey[0].ToString() + "-" + b.PrivateKey[1].ToString();
}
private void Encrypt_Click(object sender, RoutedEventArgs e)
{
Ciphertext.Text= a.getCiphertext(Plaintext.Text,b.PublicKey);
}
private void Decrypt_Click(object sender, RoutedEventArgs e)
{
Plaintext.Text = b.getPlaintext(Ciphertext.Text);
}
}
}
5. 结果展示
![结果展示](https://img-blog.csdnimg.cn/20210521110327706.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0NzA1NTU5,size_16,color_FFFFFF,t_70)
|