1. 程式人生 > 其它 >大數庫openssl實現RSA加密(C語言)

大數庫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整數

1.生成金鑰

2.加密演算法

3.解密演算法

有關的BN函式
1.初始化函式

函式解釋舉例
BIGNUM *BN_new(void)生成一個BIGNUM結構並返回指標BIGNUM *a = BN_new();
void BN_free(BIGNUM *a)釋放一個BIGNUM結構,釋放完後a=NULLBN_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位的正整數轉化為大數,儲存在retBN_bin2bn(str, length,M);
char *BN_bn2hex(const BIGNUM *a)將大數轉化為十六進位制的字串返回BN_bn2hex(a);

4.計算有關函式

函式解釋舉例
int BN_one(BIGNUM *a)設定a為1BN_one (a);
int BN_is_one(BIGNUM *a)判斷a是不是1if (BN_is_one (a))
int BN_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b)計算a與b的差,值儲存在r中, r = a - b;如果成功返回1,否則返回0BN_sub(r, a, b);
int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx)計算a與b的積,值儲存在r中 r = a * b,如果成功返回1,否則返回0BN_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,否則返回0BN_gcd (r, a, b, ctx);
BIGNUM *BN_mod_inverse(BIGNUM *r, BIGNUM *a, const BIGNUM *n)取a對n取模的逆元存在r中, ((r * a) % n) == 1BN_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 modmBN_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,則用來儲存答案,後面引數不需要的話可以填nullBN_generate_prime(p, bits, NULL,NULL, NULL, NULL,NULL);
int BN_rand_range(BIGNUM *rnd, BIGNUM *range)產生的0<rnd<rangeBN_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