生活随笔
收集整理的這篇文章主要介紹了
openssl与cryptoAPI交互AES加密解密
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文:?http://blog.csdn.net/zhouyuqwert/article/details/7422467
有讀者指出代碼貼兩遍,修改下。
繼上次只有CryptoAPI的加密后,這次要實現openssl的了
動機:利用CryptoAPI制作windows的IE,火狐和chrome加密控件后,這次得加上與Android的加密信息交互
先前有說openssl移植到android的過程,這里就不再提android如何調用openssl了,
? ? ? ? 而那一篇第9條提到的openssl與cryptoAPI兼容的兩種方式感覺實現都不太好用,這里再次提出一種AES加密的實現方式
寫這邊文章的最主要的原因,用過CryptoAPI的都知道,很多東西都封裝了,如果要與其他加密組件交互,得用其他組件來實現CryptoAPI的思路
環境:windows visual studio 2010,openssl windows(x86)動態庫
在CryptoAPI中進行AES加密解密,有一種實現方式是調用CryptDeriveKey通過提供的字節數組的hash值獲取key
先來看下CryptoAPI實現AES,來個簡單點的版本
[cpp]?view plaincopy print?
void?cryptoAPI_encrypt(string?text,unsigned?char*?pwd,unsigned?char**?encryptText,int?&out_len)?? {?? ????HCRYPTPROV?hCryptProv?=?NULL;???? ????HCRYPTKEY?hKey?=?0;???? ????HCRYPTHASH?hHash?=?0;???? ????int?dwLength?=?0;???? ???? ????if(!CryptAcquireContext(&hCryptProv,???? ????????NULL,???? ????????CSP_NAME,?? ????????PROV_RSA_AES,???? ????????CRYPT_VERIFYCONTEXT))???? ????{???? ????????DWORD?dwLastErr?=?GetLastError();???? ???? ????????if(NTE_BAD_KEYSET?==?dwLastErr)????? ????????{???? ????????????return;???? ????????}???? ????????else{???? ????????????if(!CryptAcquireContext(&hCryptProv,???? ????????????????NULL,???? ????????????????CSP_NAME,???? ????????????????PROV_RSA_AES,???? ????????????????CRYPT_NEWKEYSET))???? ????????????{???? ????????????????return;???? ????????????}???? ????????}???? ????}???? ????if(!CryptCreateHash(hCryptProv,?CALG_MD5,?0,?0,?&hHash))???? ????{???? ????????return;???? ????}???? ???? ????BYTE?*pPwd?=?pwd;??? ?? ????if(!CryptHashData(hHash,?pPwd,?16,?0))???? ????{???? ????????return;???? ????}???? ?? ????if(!CryptDeriveKey(hCryptProv,?CALG_AES_128,?hHash,?CRYPT_EXPORTABLE,?&hKey))???? ????{???? ????????return;???? ????}???? ?? ????int?len?=?text.length();???? ????BYTE?*pData?;???? ????pData?=?(BYTE*)malloc(len*4);???? ????memcpy(pData,text.c_str(),len);?? ????DWORD?dwLen?=?len;???? ???? ????if(!CryptEncrypt(hKey,?NULL,?true,?0,?pData,?&dwLen,?len*4))???? ????{???? ????????return;???? ????}???? ???? ????cout?<<"--------------------------"?<<?endl?<<?"cryptoAPI?encrypt"<<endl;?? ????printBytes(pData,dwLen);???? ????*encryptText?=?pData;?? ????out_len?=?dwLen;?? ????CryptDestroyHash(hHash);?? ????CryptDestroyKey(hKey);?? ????CryptReleaseContext(hCryptProv,0);?? }??
這里將傳進來的字節數組密鑰先進行MD5摘要后,再通過CryptoDeriveKey來得到最后用來加密的密鑰
openssl要以同樣的方式做一次這個步驟,首先是MD5摘要,相對比較簡單
[cpp]?view plaincopy print?
unsigned?char*?openssl_md5(unsigned?char*sessionKey,size_t?n)?? {?? ????unsigned?char?*ret?=?(unsigned?char*)malloc(MD5_DIGEST_LENGTH);?? ????MD5(sessionKey,n,ret);?? ????return?ret;?? }??
然后再來實現CryptoDeriveKey,先來看下
MSDN上對于這個函數的說明
主要看remarks里面的實現步驟:
[plain]?view plaincopy print?
Let?n?be?the?required?derived?key?length,?in?bytes.?The?derived?key?is?the?first?n?bytes?of?the?hash?value?after?the?hash?computation?has?been?completed?by?CryptDeriveKey.?If?the?hash?is?not?a?member?of?the?SHA-2?family?and?the?required?key?is?for?either?3DES?or?AES,?the?key?is?derived?as?follows:?? ?? 1.Form?a?64-byte?buffer?by?repeating?the?constant?0x36?64?times.?Let?k?be?the?length?of?the?hash?value?that?is?represented?by?the?input?parameter?hBaseData.?Set?the?first?k?bytes?of?the?buffer?to?the?result?of?an?XOR?operation?of?the?first?k?bytes?of?the?buffer?with?the?hash?value?that?is?represented?by?the?input?parameter?hBaseData.?? 2.Form?a?64-byte?buffer?by?repeating?the?constant?0x5C?64?times.?Set?the?first?k?bytes?of?the?buffer?to?the?result?of?an?XOR?operation?of?the?first?k?bytes?of?the?buffer?with?the?hash?value?that?is?represented?by?the?input?parameter?hBaseData.?? 3.Hash?the?result?of?step?1?by?using?the?same?hash?algorithm?as?that?used?to?compute?the?hash?value?that?is?represented?by?the?hBaseData?parameter.?? 4.Hash?the?result?of?step?2?by?using?the?same?hash?algorithm?as?that?used?to?compute?the?hash?value?that?is?represented?by?the?hBaseData?parameter.?? 5.Concatenate?the?result?of?step?3?with?the?result?of?step?4.?? 6.Use?the?first?n?bytes?of?the?result?of?step?5?as?the?derived?key.??
非常簡單的英文,不做翻譯了...
直接上openssl代碼實現
[cpp]?view plaincopy print?
?? unsigned?char*?derivedKey(unsigned?char*sessionKey,size_t?n)?? {?? ?????? ????unsigned?char*?buffer?=?(unsigned?char*)malloc(64);?? ?? ????for(int?i?=?0?;?i?<?64;i++)?? ????{?? ????????buffer[i]?=?0x36;?? ????}?? ?? ????int?k?=?n;?? ?? ????for(int?i?=?0?;?i?<?k?;?i++)?? ????{?? ????????buffer[i]?=?buffer[i]?^?sessionKey[i];?? ????}?? ?? ?????? ????unsigned?char*?buffer2?=?(unsigned?char*)malloc(64);?? ?? ????for(int?i?=?0?;?i?<?64;i++)?? ????{?? ????????buffer2[i]?=?0x5C;?? ????}?? ?? ????for(int?i?=?0?;?i?<?k?;?i++)?? ????{?? ????????buffer2[i]?=?buffer2[i]?^?sessionKey[i];?? ????}?? ?????? ????unsigned?char*?ret1?=?openssl_md5(buffer,64);?? ?????? ????unsigned?char*?ret2?=?openssl_md5(buffer2,64);?? ?? ?? ????unsigned?char*?ret?=?(unsigned?char*)malloc(128);?? ????for(int?i?=?0?;?i?<?128;i++)?? ????{?? ????????if(i<64)?? ????????????ret[i]?=?ret1[i];?? ????????else?? ????????????ret[i]?=?ret2[i-64];?? ????}?? ????return?ret;?? }??
最麻煩的地方解決了...剩下再按照CryptoAPI的實現順序實現吧
[cpp]?view plaincopy print?
void?openssl_aes_encrypt(string?text,unsigned?char**?SessionKey_out,unsigned?char*?sEncryptMsg,int?&len)?? {?? ????OpenSSL_add_all_algorithms();?? ?????? ????*SessionKey_out?=?(unsigned?char*)malloc(MD5_SIZE);?? ????RAND_bytes(*SessionKey_out,MD5_SIZE);?? ????unsigned?char*?SessionKey?=?openssl_md5(*SessionKey_out,MD5_SIZE);?? ?????? ????SessionKey?=?derivedKey(SessionKey,MD5_SIZE);?? ?? ????const?unsigned?char*?sMsg?=?(const?unsigned?char*)text.c_str();?? ????int?cbMsg?=?text.length();?? ????int?cbEncryptMsg;?? ?????? ????EVP_CIPHER_CTX?ctx;?? ????EVP_CIPHER_CTX_init(&ctx);?? ????if(EVP_EncryptInit_ex(&ctx,EVP_get_cipherbynid(NID_aes_128_cbc),NULL,SessionKey,NULL))?? ????{?? ????????int?offseti=0;?? ????????int?offseto=0;?? ????????int?offsett=0;?? ????????for(;;)?? ????????{?? ????????????if(cbMsg-offseti<=MAX_ENCRYPT_LEN)?? ????????????{?? ????????????????EVP_EncryptUpdate(&ctx,?sEncryptMsg+offseto,?&offsett,?sMsg+offseti,?cbMsg-offseti);?? ????????????????offseto+=offsett;?? ????????????????break;?? ????????????}?? ????????????else?? ????????????{?? ????????????????EVP_EncryptUpdate(&ctx,?sEncryptMsg+offseto,?&offsett,?sMsg+offseti,?MAX_ENCRYPT_LEN);?? ????????????????offseti+=MAX_ENCRYPT_LEN;?? ????????????????offseto+=offsett;?? ????????????}?? ????????}?? ????????EVP_EncryptFinal_ex(&ctx,?sEncryptMsg+offseto,?&offsett);?? ????????offseto+=offsett;?? ????????cbEncryptMsg=offseto;?? ????}?? ????EVP_CIPHER_CTX_cleanup(&ctx);?? ????std::cout?<<?"openssl?encrypt:"?<<?std::endl;?? ????printBytes(sEncryptMsg,cbEncryptMsg);?? ????len?=?cbEncryptMsg;?? }??
加密的搞定了,可以嘗試下了,同樣的密鑰和同樣的明文,密文輸出結果是一樣的就對了
下面是CrytpoAPI的解密:
[cpp]?view plaincopy print?
void?cryptAPI_decrypt(unsigned?char*?text,int?len,unsigned?char*?pwd)?? {?? ????HCRYPTPROV?hCryptProv?=?NULL;???? ????HCRYPTKEY?hKey?=?0;???? ????HCRYPTHASH?hHash?=?0;???? ????int?dwLength?=?0;???? ???? ????if(!CryptAcquireContext(&hCryptProv,???? ????????NULL,???? ????????CSP_NAME,?? ????????PROV_RSA_AES,???? ????????CRYPT_VERIFYCONTEXT))???? ????{???? ????????DWORD?dwLastErr?=?GetLastError();???? ???? ????????if(NTE_BAD_KEYSET?==?dwLastErr)????? ????????{???? ????????????return;???? ????????}???? ????????else{???? ????????????if(!CryptAcquireContext(&hCryptProv,???? ????????????????NULL,???? ????????????????CSP_NAME,???? ????????????????PROV_RSA_AES,???? ????????????????CRYPT_NEWKEYSET))???? ????????????{???? ????????????????return;???? ????????????}???? ????????}???? ????}???? ???? ???? ????if(!CryptCreateHash(hCryptProv,?CALG_MD5,?0,?0,?&hHash))???? ????{???? ????????return;???? ????}???? ???? ????BYTE?*pPwd?=?pwd;??? ?? ????if(!CryptHashData(hHash,?pPwd,?16,?0))???? ????{???? ????????return;???? ????}???? ?? ????if(!CryptDeriveKey(hCryptProv,?CALG_AES_128,?hHash,?CRYPT_EXPORTABLE,?&hKey))???? ????{???? ????????return;???? ????}???? ?? ????BYTE?*pData?=?text;???? ????DWORD?dwLen?=?len;???? ???? ????if(!CryptDecrypt(hKey,?NULL,?true,?0,?pData,?&dwLen))???? ????{???? ????????return;???? ????}???? ???? ????cout?<<"--------------------------"?<<?endl?<<?"cryptoAPI?decrypt"<<endl;?? ????char*?plainText?=?(char*)malloc(dwLen?+?1);?? ????memcpy(plainText,pData,dwLen);?? ????plainText[dwLen]?=?'\0';?? ????cout?<<?plainText?<<?endl;?? ????CryptDestroyHash(hHash);?? ????CryptDestroyKey(hKey);?? ????CryptReleaseContext(hCryptProv,0);?? }??
嘗試用這個方法解密CryptoAPI的加密和openssl的加密吧,都能輸出明文的
再來最后一個,openssl的解密
[cpp]?view plaincopy print?
void?openssl_aes_decrypt(unsigned?char*?text,int?len,unsigned?char*?SessionKeyP)?? {?? ????unsigned?char*?decryptMsg?=?(unsigned?char*)malloc(len);?? ?? ????OpenSSL_add_all_algorithms();?? ?? ????unsigned?char*?SessionKey?=?openssl_md5(SessionKeyP,MD5_SIZE);?? ?????? ????SessionKey?=?derivedKey(SessionKey,MD5_SIZE);?? ?? ????const?unsigned?char*?sMsg?=?text;?? ????int?cbMsg?=?len;?? ????int?cbEncryptMsg;?? ?????? ????EVP_CIPHER_CTX?ctx;?? ????EVP_CIPHER_CTX_init(&ctx);?? ?????? ????if(EVP_DecryptInit_ex(&ctx,EVP_get_cipherbynid(NID_aes_128_cbc),NULL,SessionKey,NULL))?? ????{?? ????????int?offseti=0;?? ????????int?offseto=0;?? ????????int?offsett=0;?? ????????for(;;)?? ????????{?? ????????????if(cbMsg-offseti<=MAX_ENCRYPT_LEN)?? ????????????{?? ????????????????EVP_DecryptUpdate(&ctx,?decryptMsg+offseto,?&offsett,?sMsg+offseti,?cbMsg-offseti);?? ????????????????offseto+=offsett;?? ????????????????break;?? ????????????}?? ????????????else?? ????????????{?? ????????????????EVP_DecryptUpdate(&ctx,?decryptMsg+offseto,?&offsett,?sMsg+offseti,?MAX_ENCRYPT_LEN);?? ????????????????offseti+=MAX_ENCRYPT_LEN;?? ????????????????offseto+=offsett;?? ????????????}?? ????????}?? ????????EVP_DecryptFinal_ex(&ctx,?decryptMsg+offseto,?&offsett);?? ?? ????????offseto+=offsett;?? ????????cbEncryptMsg=offseto;?? ????}?? ????EVP_CIPHER_CTX_cleanup(&ctx);?? ????std::cout?<<?"openssl?decrypt:"?<<?std::endl;?? ?? ?? ????char*?ret?=?(char*)malloc(cbEncryptMsg?+?1);?? ????memcpy(ret,decryptMsg,cbEncryptMsg);?? ????ret[cbEncryptMsg]?=?'\0';?? ????std::cout?<<?ret?<<?endl;?? }??
測試下:
[cpp]?view plaincopy print?
int?_tmain(int?argc,?_TCHAR*?argv[])?? {?? ????string?text?=?"texttexttexttexttext";?? ????unsigned?char*?key;?? ????unsigned?char*?sEncryptMsg?=?(unsigned?char*)malloc(text.size()?+?MD5_SIZE);?? ????int?len;?? ????openssl_aes_encrypt(text,&key,sEncryptMsg,len);?? ?? ?? ????unsigned?char**?sEncryptMsg_crypto?=?(unsigned?char**)malloc(sizeof(unsigned?char*));?? ????int?len_crypto;?? ????cryptoAPI_encrypt(text,key,sEncryptMsg_crypto,len_crypto);?? ????cout?<<?"-----------------------------"?<<?endl<<"cryptoAPI?decrypt?openssl"<<endl;?? ?????? ?? ????cout?<<?"-----------------------------"?<<?endl<<"cryptoAPI?decrypt?cryptoAPI"<<endl;?? ?????? ?? ????cout?<<?"-----------------------------"?<<?endl<<"oepnssl?decrypt?openssl"<<endl;?? ?????? ?? ????cout?<<?"-----------------------------"?<<?endl<<"oepnssl?decrypt?cryptoAPI"<<endl;?? ?????? ????return?0;?? }??
總結
以上是生活随笔為你收集整理的openssl与cryptoAPI交互AES加密解密的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。