大數庫openssl實現RSA加密(C語言)
技術標籤:openssl密碼學opensslrsac語言密碼學
大數庫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整數
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