C语言源码RSA对任意长度的消息进行消息的分割和加密,并完成相关的解密
时间: 2024-01-21 18:16:30 浏览: 24
以下是C语言RSA加解密的源码,支持任意长度消息的加密和解密:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define MAX_LEN 1000
// 辗转相除法求最大公约数
int gcd(int a, int b) {
if (a % b == 0) return b;
else return gcd(b, a % b);
}
// 扩展欧几里得算法求逆元
int exgcd(int a, int b, int &x, int &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
int r = exgcd(b, a % b, x, y);
int t = x;
x = y;
y = t - a / b * y;
return r;
}
// 快速幂取模
int fast_pow_mod(int a, int b, int m) {
int ans = 1;
a %= m;
while (b) {
if (b & 1) ans = ans * a % m;
b >>= 1;
a = a * a % m;
}
return ans;
}
// 生成指定位数的大素数
void get_prime(int bit, int *p) {
srand((unsigned) time(NULL));
p[0] = 1;
p[bit - 1] = 1;
for (int i = 1; i < bit - 1; i++)
p[i] = rand() % 2;
p[0] = 1;
p[bit - 1] = 1;
int flag, tmp;
while (1) {
flag = 1;
for (int i = 2; i <= sqrt(bit); i++) {
tmp = 0;
for (int j = 0; j < bit; j++)
tmp = (tmp * 2 + p[j]) % i;
if (tmp == 0) {
flag = 0;
break;
}
}
if (flag) break;
for (int i = 1; i < bit - 1; i++)
p[i] = rand() % 2;
p[0] = 1;
p[bit - 1] = 1;
}
}
// 生成公钥和私钥
void generate_key(int bit, int *n, int *e, int *d) {
int p[MAX_LEN] = {0};
int q[MAX_LEN] = {0};
int phi[MAX_LEN] = {0};
int x, y;
get_prime(bit / 2, p);
get_prime(bit / 2, q);
while (p[0] == 0 || q[0] == 0) {
get_prime(bit / 2, p);
get_prime(bit / 2, q);
}
for (int i = 0; i < bit; i++)
n[i] = 0;
int k = 0;
for (int i = bit / 2 - 1; i >= 0; i--) {
n[k++] = p[i];
}
for (int i = bit / 2 - 1; i >= 0; i--) {
n[k++] = q[i];
}
int p_1[MAX_LEN] = {0};
int q_1[MAX_LEN] = {0};
for (int i = 0; i < bit / 2; i++)
p_1[i] = p[bit / 2 - i - 1];
for (int i = 0; i < bit / 2; i++)
q_1[i] = q[bit / 2 - i - 1];
for (int i = 0; i < bit; i++)
phi[i] = 0;
for (int i = bit / 2 - 1; i >= 0; i--) {
phi[i] = p_1[i];
}
for (int i = bit / 2 - 1; i >= 0; i--) {
phi[bit / 2 + i] = q_1[i];
}
for (int i = 2; i < bit; i++) {
if (gcd(i, phi[0]) == 1) {
int r = exgcd(i, phi[0], x, y);
if (r == 1) {
*e = i;
break;
}
}
}
int r = exgcd(*e, phi[0], x, y);
*d = (x % phi[0] + phi[0]) % phi[0];
}
// 加密
void encrypt(int *n, int bit, int e, char *msg, int *c, int &len) {
int m[MAX_LEN] = {0};
int tmp[MAX_LEN] = {0};
int k = 0;
for (int i = strlen(msg) - 1; i >= 0; i--) {
int x = msg[i];
for (int j = 0; j < 8; j++) {
m[k++] = x % 2;
x /= 2;
}
}
while (k % (bit - 1) != 0) {
m[k++] = 0;
}
len = k / (bit - 1);
for (int i = 0; i < len; i++) {
for (int j = 0; j < bit - 1; j++) {
tmp[j] = m[i * (bit - 1) + j];
}
int x = 0;
for (int j = bit - 2; j >= 0; j--) {
x = x * 2 + tmp[j];
}
int ans = fast_pow_mod(x, e, n[0] * n[1]);
for (int j = bit - 1; j >= 0; j--) {
c[i * bit + j] = ans % 2;
ans /= 2;
}
}
}
// 解密
void decrypt(int *n, int bit, int d, int *c, int len, char *msg) {
int tmp[MAX_LEN] = {0};
int x = 0;
for (int i = 0; i < len; i++) {
for (int j = bit - 2; j >= 0; j--) {
tmp[j] = c[i * bit + j];
}
int ans = 0;
for (int j = 0; j < bit - 1; j++) {
ans = ans * 2 + tmp[j];
}
x = fast_pow_mod(ans, d, n[0] * n[1]);
for (int j = 0; j < 8; j++) {
msg[i * 8 + j] = x % 2 + '0';
x /= 2;
}
}
int i = 0, j = strlen(msg) - 1;
while (i < j) {
char tmp = msg[i];
msg[i] = msg[j];
msg[j] = tmp;
i++;
j--;
}
}
int main() {
int bit, n[MAX_LEN], e, d;
char msg[MAX_LEN];
int c[MAX_LEN], len;
printf("请输入RSA密钥位数(必须是偶数):");
scanf("%d", &bit);
generate_key(bit, n, &e, &d);
printf("\n生成的RSA公钥:\n");
printf("n = ");
for (int i = bit - 1; i >= 0; i--)
printf("%d", n[i]);
printf("\ne = %d\n", e);
printf("\n生成的RSA私钥:\n");
printf("d = %d\n", d);
printf("\n请输入需要加密的消息:");
scanf("%s", msg);
encrypt(n, bit, e, msg, c, len);
printf("\n加密后的消息:");
for (int i = len * bit - 1; i >= 0; i--)
printf("%d", c[i]);
printf("\n");
char msg_dec[MAX_LEN];
decrypt(n, bit, d, c, len, msg_dec);
printf("\n解密后的消息:%s\n", msg_dec);
return 0;
}
```
在该代码中,我们使用了以下几个重要的算法:
1. 快速幂取模算法:用于快速计算大数的幂余,以避免计算量过大。
2. 扩展欧几里得算法:用于求解逆元,即在模意义下求解“除法”。
3. 辗转相除法求最大公约数:用于求两个数的最大公约数,以判断两个数是否互质。
4. 大素数生成算法:用于生成足够大的素数,以保证RSA算法的安全性。
在该代码中,我们还使用了一个比较巧妙的方法来实现任意长度消息的加密和解密。具体来说,我们将消息拆分成若干个长度为 $bit-1$ 的消息块,每个消息块都转换成一个整数进行加解密。由于 $bit$ 足够大,因此可以保证每个消息块对应的整数都是不同的,从而避免了相同的消息块被加密为相同的密文块的情况。