標籤:rsa演算法 openssl cer公開金鑰
首先最近接到一個項目,這個項目中需要用到RSA的加密解密,因為之前沒有接觸過,在網上找了些資料,然後自己測試後發現其實使用openssl來進行加解密挺簡單的,但是網上百度出來的很多又是一樣的,有時候協助不是很大,所以才想要寫下來自己在搞整個加密過程遇到的一些問題,方便自己以後回頭查看,也可能會幫到遇到同樣的童鞋。
廢話不多說,我接到的這個項目呢,有幾個地方是需要用到RSA的加解密。1、使用.pfx格式的私密金鑰簽名。2、使用.cer的公開金鑰檔案進行加密操作。3、使用給定的指數與模進行公開金鑰加密。下面有些自己從網上整理的代碼,歡迎批評指正。
1、使用.pfx格式的私密金鑰進行簽名(部分代碼來源網上):
/** <pre name="code" class="cpp"><pre name="code" class="cpp">* SrcData:需要加密的字串
* PriPath:私密金鑰檔案(.pfx格式)* PassWd:私密金鑰檔案密碼* SignData:結果 */int SignDataByPri(char *SrcData,char *PriPath,char *PassWd,char *SignData){ int err; unsigned int SigLen; unsigned char SigBuf[128]; EVP_MD_CTX MdCtx; EVP_PKEY *Pkey = NULL; FILE *Fp = NULL; X509 *X509 = NULL; PKCS12 *P12 = NULL; STACK_OF(X509) *Ca = NULL; if(SrcData == NULL || PriPath == NULL){ return false; } SSLeay_add_all_algorithms(); ERR_load_crypto_strings(); if (!(Fp = fopen(PriPath, "rb"))) { printf("讀取密鑰檔案失敗\n"); return false; } P12 = d2i_PKCS12_fp(Fp, NULL); fclose (Fp); if (!P12) { printf("讀取密鑰檔案失敗\n"); return false; } if (!PKCS12_parse(P12, PassWd, &Pkey, &X509, &Ca)) { printf("解包密鑰失敗\n"); PKCS12_free(P12); return false; } PKCS12_free(P12); if (Pkey == NULL) { printf("解包密鑰失敗\n"); return false; } /*簽名資料*/ EVP_SignInit (&MdCtx, EVP_sha1()); //簽名演算法選擇sha1 EVP_SignUpdate (&MdCtx, SrcData, strlen(SrcData)); SigLen = 128; memset(SigBuf,0x00,sizeof(SigBuf)); err = EVP_SignFinal (&MdCtx, SigBuf, &SigLen, Pkey); if (err != 1) { printf("簽名失敗\n"); /*釋放相關變數*/ if (Pkey) { EVP_PKEY_free (Pkey); } if (X509) { X509_free(X509); } return false; } memcpy(SignData, SigBuf, SigLen); /*釋放相關變數*/ if (Pkey) { EVP_PKEY_free (Pkey); } if (X509) { X509_free(X509); } return true;}
2、使用.cer的公開金鑰檔案對字串進行加密操作:
/** src:需要加密的源字串* len:src的長度* path_key:公開金鑰檔案的路徑(.cer格式)*/int RSAencrypt(char *str,int len,char *path_key,char *Enc){ char *p_en; RSA *p_rsa; FILE *file; int flen,rsa_len; PKCS12* p12 = NULL; X509 * x509 = NULL; STACK_OF(X509) *ca = NULL; EVP_PKEY * pkey = NULL; if((file=fopen(path_key,"r"))==NULL){ perror("open key file error"); return 0; } BIO* b; b=BIO_new_file(path_key,"r"); x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); if (x509 == NULL) { printf("讀密鑰檔案 \n"); ERR_print_errors_fp (stderr); return 0; } printf("讀密鑰檔案 [%d]\n",__LINE__); pkey=X509_get_pubkey(x509); //將EVP_KEY轉成RSA KEY (這步很重要) p_rsa = EVP_PKEY_get1_RSA(pkey); rsa_len=RSA_size(p_rsa); p_en=(unsigned char *)malloc(rsa_len+1); memset(p_en,0,rsa_len+1); //網山很多例子這個函數調用時第一個參數使用的是密鑰的長度是因為他們加密方式使用RSA_NO_PADDING,如使用RSA_PKCS1_PADDING,len需要填源字串長度 if(RSA_public_encrypt(len,str,p_en,p_rsa,RSA_PKCS1_PADDING)<0){ printf("加密失敗\n"); return 0; } memcpy(Enc,p_en,rsa_len); fclose(file); free(p_en); return rsa_len;}
3、使用給定的指數與模進行公開金鑰加密
/** type:一般分為10進位和16進位* Bnn:模,進位數與type對應* Bne:通常分為兩種RSA_F4和RSA_3(在rsa.h定義)* in:需要加密的來源資料* out:加密後的密文*/int RSAEncryptByModule(int type,char *Bnn,int Bne,unsigned char *in,unsigned char *out ) { int ret, flen; BIGNUM *bnn, *bne, *bnd; unsigned char *out_buf; bnn = BN_new(); bne = BN_new(); bnd = BN_new(); switch(type){ case 10: BN_dec2bn(&bnn, Bnn); BN_set_word(bne, Bne); break; case 16: BN_hex2bn(&bnn, Bnn); BN_set_word(bne, Bne); break; default: printf("err type\n"); return -1; } RSA *r = RSA_new(); r->n = bnn; r->e = bne; r->d = bnd; flen = RSA_size(r); out_buf = ( unsigned char *)malloc(flen); memset(out_buf, 0, flen); <pre name="code" class="cpp"> //網山很多例子這個函數調用時第一個參數使用的是密鑰的長度是因為他們加密方式使用RSA_NO_PADDING,如使用RSA_PKCS1_PADDING,len需要填源字串長度 ret = RSA_public_encrypt(strlen(in),in,out_buf,r,RSA_PKCS1_PADDING); if (ret < 0) { printf("Encrypt failed!\n"); return ret; } memcpy(out,out_buf,ret); free(out_buf); RSA_free(r); return ret;}
還有一些比如sha1做簽名、base64轉碼等操作就不一一贅述了,網上也很多代碼和解釋。
openssl 加解密學習筆記