大数库openssl实现RSA加密(C语言)
学习记录
使用大数库openssl中的大数运算函数实现RSA加密
这是第一次借用大数库来辅助编程,是一次宝贵的经历,记录一下。
我是直接使用下载好的openssl的文件,将其放入vs2019的工程中就可以使用大数库的函数了
下载地址:https://download.csdn.net/download/weixin_47627174/14503343.
文件截图:
如何将文件放到编译器里(vs2019为例)
1.新建工程,新建添加c文件,右键项目的属性,VC++目录
将包含目录编辑为openssl的include文件,库目录编辑为openssl的lib文件
2.链接器
将附加库目录编辑为openssl的lib和bin文件
3.引用代码
#pragma comment(lib, "libeay32.lib" )
#pragma comment(lib, "ssleay32.lib")
之后使用头文件引用即可
#include</openssl/include/xxx.h>
(建议把openssl文件直接放到D盘根目录比较方便)
4.报错
提示:OPENSSL_Uplink(100F2010,05):no OPENSSL_Applink
解决方法:
extern "C"
{
#include</openssl/include/applink.c>
}
或者
#ifdef __cplusplus
extern "C" {
#endif
#include</openssl/include/applink.c>
#ifdef __cplusplus
}
RSA加密
RSA公钥算法由Rivest、Shamir、Adleman于1978年提出的,是目前公钥密码的国际标准。算法的数学基础是Euler定理,是基于Deffie-Hellman的单项陷门函数的定义而给出的第一个公钥密码的实际实现,其安全性建立在大整数因子分解的困难性之上。
RSA算法的明文空间M=密文空间C=Zn整数
1.生成密钥
2.加密算法
3.解密算法
有关的BN函数
1.初始化函数
函数 | 解释 | 举例 |
---|---|---|
BIGNUM *BN_new(void) | 生成一个BIGNUM结构并返回指针 | BIGNUM *a = BN_new(); |
void BN_free(BIGNUM *a) | 释放一个BIGNUM结构,释放完后a=NULL | BN_free(a); |
2.上下文结构
函数 | 解释 | 举例 |
---|---|---|
BN_CTX *BN_CTX_new(void) | 申请一个新的上下文结构 | BN_CTX *ctx = BN_CTX_new(); |
3.字符串转换
函数 | 解释 | 举例 |
---|---|---|
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret) | 将s中的len位的正整数转化为大数,储存在ret | BN_bin2bn(str, length,M); |
char *BN_bn2hex(const BIGNUM *a) | 将大数转化为十六进制的字符串返回 | BN_bn2hex(a); |
4.计算有关函数
函数 | 解释 | 举例 |
---|---|---|
int BN_one(BIGNUM *a) | 设置a为1 | BN_one (a); |
int BN_is_one(BIGNUM *a) | 判断a是不是1 | if (BN_is_one (a)) |
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b) | 计算a与b的差,值储存在r中, r = a - b;如果成功返回1,否则返回0 | BN_sub(r, a, b); |
int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) | 计算a与b的积,值储存在r中 r = a * b,如果成功返回1,否则返回0 | BN_mul (r, a, b, ctx) |
int BN_gcd(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx) | 计算a与b的最大公约数,值储存在r中, r = gcd(a,b),如果成功返回1,否则返回0 | BN_gcd (r, a, b, ctx); |
BIGNUM *BN_mod_inverse(BIGNUM *r, BIGNUM *a, const BIGNUM *n) | 取a对n取模的逆元存在r中, ((r * a) % n) == 1 | BN_mod_inverse(d, e, fn, ctx) |
nt BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m) | 大数的模指数运算(利用经典模运算实现)r ← a^p modm | BN_mod_exp_simple(M, C, d, n, ctx); |
5.随机函数
函数 | 解释 | 举例 |
---|---|---|
BIGNUM *BN_generate_prime(BIGNUM *ret, int num, int safe, BIGNUM *add, BIGNUM *rem, void (*callback)(int, int, void *), void *cb_arg); | 伪随机生成num位素数,如果ret返回值不为null,则用来储存答案,后面参数不需要的话可以填null | BN_generate_prime(p, bits, NULL,NULL, NULL, NULL,NULL); |
int BN_rand_range(BIGNUM *rnd, BIGNUM *range) | 产生的0<rnd<range | BN_rand_range(e, fn) |
程序代码
#include <stdio.h>
#include</openssl/include/bn.h> //引用大数库中的BN函数
#pragma comment(lib, "libeay32.lib" ) //引用
#pragma comment(lib, "ssleay32.lib")
#ifdef __cplusplus
extern "C" {
#endif
#include</openssl/include/applink.c>
#ifdef __cplusplus
}
#endif
int zhuanhuan(int a)//将十六进制转换为十进制
{
if (a< 60)
{
a= a- '0';
}
if (a> 64)
{
a = a- 'A' + 10;
}
return a;
}
void main()
{
BIGNUM* p=BN_new(); //大素数p
BIGNUM* q = BN_new(); //大素数q
BIGNUM* n= BN_new(); //n=p*q
BIGNUM* fn = BN_new(); //fn=(p-1)*(q-1)
BIGNUM* d = BN_new(); //d=e-1 mod (n)
BIGNUM * e = BN_new(); //整数e,1<e<fn且gcd(fn, e)=1
BIGNUM* r = BN_new();
BIGNUM* M = BN_new(); //明文
BIGNUM* C = BN_new(); //密文
BIGNUM* one = BN_new(); //将one设置为1
BN_one(one);
int length;
char str[100] = "0";
char* show;
int bits = 512; //512bits
int i,j,t;
int sum=0;
printf("请输入要加密的的明文:");
scanf_s("%s",str,sizeof(str));
length = strlen(str); //记录明文的长度
BN_bin2bn(str, length,M); //将明文以十六进制转换为大数
printf("明文:%s\n", str);
BN_generate_prime(p, bits, NULL,NULL, NULL, NULL,NULL); //生成512bits的大素数p
BN_generate_prime(q, bits, NULL, NULL, NULL, NULL, NULL); //生成512bits的大素数q
BN_CTX* ctx = BN_CTX_new(); //上下文结构
BN_mul(n ,p, q, ctx); //n=p*q
BN_sub(p, p, one);
BN_sub(q, q, one);
BN_mul(fn, p, q, ctx); //fn=(p-1)*(q-1)
do
{
BN_rand_range(e, fn); //产生的0 < e < fn的随机数
BN_gcd(r, e, fn, ctx); //r = e, fn最大公约数
} while (!BN_is_one(r)); //判断r是否等于1
BN_mod_inverse(d, e, fn, ctx); //模逆运算
//公钥加密 C = M^e mod n
BN_mod_exp_simple(C, M, e, n , ctx);
show = BN_bn2hex(C); //将密文转换为十六进制
printf("密文:%s\n", show);
//私钥解密 M = C^d mod n。
BN_mod_exp_simple(M, C, d, n, ctx);
show = BN_bn2hex(M);
//printf("%x",show);//测试
printf("\n解密后的明文:%s", show); //将解密后的明文转换为十六进制
printf("\n解密后的明文:");
for (i = 0; i < length; i++) //将解密后的明文转化为对应的ASCII的字符
{
j = *(show + 2*i); //每两位为一个整体
t= *(show +2* i+1);
j=zhuanhuan(j);
t=zhuanhuan(t);
sum = j * 16 + t;
printf("%c", sum); //将ASCII的字符输出
}
//释放结构
BN_CTX_free(ctx);
BN_free(p);
BN_free(q);
BN_free(n);
BN_free(fn);
BN_free(d);
BN_free(e);
BN_free(r);
BN_free(M);
BN_free(C);
}
程序运行结果:
结语:编写程序仍有许多不足,如果其中有任何错误,望能指出,十分感谢!
参考:
https://blog.csdn.net/jnxxhzz/article/details/81235981
https://blog.csdn.net/samsho2/article/details/87902775