zoukankan      html  css  js  c++  java
  • openssl与cryptoAPI交互AES加密解密

    继上次只有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,来个简单点的版本

    1. void cryptoAPI_encrypt(string text,unsigned char* pwd,unsigned char** encryptText,int &out_len)  
    2. {  
    3.     HCRYPTPROV hCryptProv = NULL;    
    4.     HCRYPTKEY hKey = 0;    
    5.     HCRYPTHASH hHash = 0;    
    6.     int dwLength = 0;    
    7.     
    8.     if(!CryptAcquireContext(&hCryptProv,    
    9.         NULL,    
    10.         CSP_NAME,//CSP_NAME    
    11.         PROV_RSA_AES,    
    12.         CRYPT_VERIFYCONTEXT))    
    13.     {    
    14.         DWORD dwLastErr = GetLastError();    
    15.     
    16.         if(NTE_BAD_KEYSET == dwLastErr)     
    17.         {    
    18.             return;    
    19.         }    
    20.         else{    
    21.             if(!CryptAcquireContext(&hCryptProv,    
    22.                 NULL,    
    23.                 CSP_NAME,    
    24.                 PROV_RSA_AES,    
    25.                 CRYPT_NEWKEYSET))    
    26.             {    
    27.                 return;    
    28.             }    
    29.         }    
    30.     }    
    31.     if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))    
    32.     {    
    33.         return;    
    34.     }    
    35.     
    36.     BYTE *pPwd = pwd;   
    37.   
    38.     if(!CryptHashData(hHash, pPwd, 16, 0))    
    39.     {    
    40.         return;    
    41.     }    
    42.   
    43.     if(!CryptDeriveKey(hCryptProv, CALG_AES_128, hHash, CRYPT_EXPORTABLE, &hKey))    
    44.     {    
    45.         return;    
    46.     }    
    47.   
    48.     int len = text.length();    
    49.     BYTE *pData ;    
    50.     pData = (BYTE*)malloc(len*4);    
    51.     memcpy(pData,text.c_str(),len);  
    52.     DWORD dwLen = len;    
    53.     
    54.     if(!CryptEncrypt(hKey, NULL, true, 0, pData, &dwLen, len*4))    
    55.     {    
    56.         return;    
    57.     }    
    58.     
    59.     cout <<"--------------------------" << endl << "cryptoAPI encrypt"<<endl;  
    60.     printBytes(pData,dwLen);    
    61.     *encryptText = pData;  
    62.     out_len = dwLen;  
    63.     CryptDestroyHash(hHash);  
    64.     CryptDestroyKey(hKey);  
    65.     CryptReleaseContext(hCryptProv,0);  
    66. }  


    这里将传进来的字节数组密钥先进行MD5摘要后,再通过CryptoDeriveKey来得到最后用来加密的密钥

    openssl要以同样的方式做一次这个步骤,首先是MD5摘要,相对比较简单

    1. unsigned char* openssl_md5(unsigned char*sessionKey,size_t n)  
    2. {  
    3.     unsigned char *ret = (unsigned char*)malloc(MD5_DIGEST_LENGTH);  
    4.     MD5(sessionKey,n,ret);  
    5.     return ret;  
    6. }  


    然后再来实现CryptoDeriveKey,先来看下MSDN上对于这个函数的说明

    主要看remarks里面的实现步骤:

    1. 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:  
    2.   
    3. 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.  
    4. 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.  
    5. 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.  
    6. 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.  
    7. 5.Concatenate the result of step 3 with the result of step 4.  
    8. 6.Use the first n bytes of the result of step 5 as the derived key.  

    非常简单的英文,不做翻译了...

    直接上openssl代码实现

    1. //参见 http://msdn.microsoft.com/en-us/library/aa379916(v=vs.85).aspx remarks步骤  
    2. unsigned char* derivedKey(unsigned char*sessionKey/*hash后的值*/,size_t n/*密钥长度*/)  
    3. {  
    4.     /**step 1*/  
    5.     unsigned char* buffer = (unsigned char*)malloc(64);  
    6.   
    7.     for(int i = 0 ; i < 64;i++)  
    8.     {  
    9.         buffer[i] = 0x36;  
    10.     }  
    11.   
    12.     int k = n;  
    13.   
    14.     for(int i = 0 ; i < k ; i++)  
    15.     {  
    16.         buffer[i] = buffer[i] ^ sessionKey[i];  
    17.     }  
    18.   
    19.     /*step 2*/  
    20.     unsigned char* buffer2 = (unsigned char*)malloc(64);  
    21.   
    22.     for(int i = 0 ; i < 64;i++)  
    23.     {  
    24.         buffer2[i] = 0x5C;  
    25.     }  
    26.   
    27.     for(int i = 0 ; i < k ; i++)  
    28.     {  
    29.         buffer2[i] = buffer2[i] ^ sessionKey[i];  
    30.     }  
    31.     /*step 3*/  
    32.     unsigned char* ret1 = openssl_md5(buffer,64);  
    33.     /*step 4*/  
    34.     unsigned char* ret2 = openssl_md5(buffer2,64);  
    35.   
    36.   
    37.     unsigned char* ret = (unsigned char*)malloc(128);  
    38.     for(int i = 0 ; i < 128;i++)  
    39.     {  
    40.         if(i<64)  
    41.             ret[i] = ret1[i];  
    42.         else  
    43.             ret[i] = ret2[i-64];  
    44.     }  
    45.     return ret;  
    46. }  


    最麻烦的地方解决了...剩下再按照CryptoAPI的实现顺序实现吧

    1. void openssl_aes_encrypt(string text,unsigned char** SessionKey_out/*这里主要用作将产生的对称密钥输出*/,unsigned char* sEncryptMsg,int &len)  
    2. {  
    3.     OpenSSL_add_all_algorithms();  
    4.     //产生会话密钥  
    5.     *SessionKey_out = (unsigned char*)malloc(MD5_SIZE);  
    6.     RAND_bytes(*SessionKey_out,MD5_SIZE);//产生随机密钥,输出之后可以给其他方法是用了  
    7.     unsigned char* SessionKey = openssl_md5(*SessionKey_out,MD5_SIZE);  
    8.       
    9.     SessionKey = derivedKey(SessionKey,MD5_SIZE);  
    10.   
    11.     const unsigned char* sMsg = (const unsigned char*)text.c_str();  
    12.     int cbMsg = text.length();  
    13.     int cbEncryptMsg;  
    14.     //加密  
    15.     EVP_CIPHER_CTX ctx;  
    16.     EVP_CIPHER_CTX_init(&ctx);  
    17.     if(EVP_EncryptInit_ex(&ctx,EVP_get_cipherbynid(NID_aes_128_cbc),NULL,SessionKey,NULL))  
    18.     {  
    19.         int offseti=0;//in  
    20.         int offseto=0;//out  
    21.         int offsett=0;//temp  
    22.         for(;;)  
    23.         {  
    24.             if(cbMsg-offseti<=MAX_ENCRYPT_LEN)  
    25.             {  
    26.                 EVP_EncryptUpdate(&ctx, sEncryptMsg+offseto, &offsett, sMsg+offseti, cbMsg-offseti);  
    27.                 offseto+=offsett;  
    28.                 break;  
    29.             }  
    30.             else  
    31.             {  
    32.                 EVP_EncryptUpdate(&ctx, sEncryptMsg+offseto, &offsett, sMsg+offseti, MAX_ENCRYPT_LEN);  
    33.                 offseti+=MAX_ENCRYPT_LEN;  
    34.                 offseto+=offsett;  
    35.             }  
    36.         }  
    37.         EVP_EncryptFinal_ex(&ctx, sEncryptMsg+offseto, &offsett);  
    38.         offseto+=offsett;  
    39.         cbEncryptMsg=offseto;  
    40.     }  
    41.     EVP_CIPHER_CTX_cleanup(&ctx);  
    42.     std::cout << "openssl encrypt:" << std::endl;  
    43.     printBytes(sEncryptMsg,cbEncryptMsg);  
    44.     len = cbEncryptMsg;  
    45. }  


    加密的搞定了,可以尝试下了,同样的密钥和同样的明文,密文输出结果是一样的就对了

    下面是CrytpoAPI的解密:

    1. void cryptAPI_decrypt(unsigned char* text,int len,unsigned char* pwd)  
    2. {  
    3.     HCRYPTPROV hCryptProv = NULL;    
    4.     HCRYPTKEY hKey = 0;    
    5.     HCRYPTHASH hHash = 0;    
    6.     int dwLength = 0;    
    7.     
    8.     if(!CryptAcquireContext(&hCryptProv,    
    9.         NULL,    
    10.         CSP_NAME,//CSP_NAME    
    11.         PROV_RSA_AES,    
    12.         CRYPT_VERIFYCONTEXT))    
    13.     {    
    14.         DWORD dwLastErr = GetLastError();    
    15.     
    16.         if(NTE_BAD_KEYSET == dwLastErr)     
    17.         {    
    18.             return;    
    19.         }    
    20.         else{    
    21.             if(!CryptAcquireContext(&hCryptProv,    
    22.                 NULL,    
    23.                 CSP_NAME,    
    24.                 PROV_RSA_AES,    
    25.                 CRYPT_NEWKEYSET))    
    26.             {    
    27.                 return;    
    28.             }    
    29.         }    
    30.     }    
    31.     
    32.     
    33.     if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))    
    34.     {    
    35.         return;    
    36.     }    
    37.     
    38.     BYTE *pPwd = pwd;   
    39.   
    40.     if(!CryptHashData(hHash, pPwd, 16, 0))    
    41.     {    
    42.         return;    
    43.     }    
    44.   
    45.     if(!CryptDeriveKey(hCryptProv, CALG_AES_128, hHash, CRYPT_EXPORTABLE, &hKey))    
    46.     {    
    47.         return;    
    48.     }    
    49.   
    50.     BYTE *pData = text;    
    51.     DWORD dwLen = len;    
    52.     
    53.     if(!CryptDecrypt(hKey, NULL, true, 0, pData, &dwLen))    
    54.     {    
    55.         return;    
    56.     }    
    57.     
    58.     cout <<"--------------------------" << endl << "cryptoAPI decrypt"<<endl;  
    59.     char* plainText = (char*)malloc(dwLen + 1);  
    60.     memcpy(plainText,pData,dwLen);  
    61.     plainText[dwLen] = '';  
    62.     cout << plainText << endl;  
    63.     CryptDestroyHash(hHash);  
    64.     CryptDestroyKey(hKey);  
    65.     CryptReleaseContext(hCryptProv,0);  
    66. }  


    尝试用这个方法解密CryptoAPI的加密和openssl的加密吧,都能输出明文的

    再来最后一个,openssl的解密

    1. void openssl_aes_decrypt(unsigned char* text,int len,unsigned char* SessionKeyP)  
    2. {  
    3.     unsigned char* decryptMsg = (unsigned char*)malloc(len);  
    4.   
    5.     OpenSSL_add_all_algorithms();  
    6.   
    7.     unsigned char* SessionKey = openssl_md5(SessionKeyP,MD5_SIZE);  
    8.       
    9.     SessionKey = derivedKey(SessionKey,MD5_SIZE);  
    10.   
    11.     const unsigned char* sMsg = text;  
    12.     int cbMsg = len;  
    13.     int cbEncryptMsg;  
    14.     //解密  
    15.     EVP_CIPHER_CTX ctx;  
    16.     EVP_CIPHER_CTX_init(&ctx);  
    17.       
    18.     if(EVP_DecryptInit_ex(&ctx,EVP_get_cipherbynid(NID_aes_128_cbc),NULL,SessionKey,NULL))  
    19.     {  
    20.         int offseti=0;//in  
    21.         int offseto=0;//out  
    22.         int offsett=0;//temp  
    23.         for(;;)  
    24.         {  
    25.             if(cbMsg-offseti<=MAX_ENCRYPT_LEN)  
    26.             {  
    27.                 EVP_DecryptUpdate(&ctx, decryptMsg+offseto, &offsett, sMsg+offseti, cbMsg-offseti);  
    28.                 offseto+=offsett;  
    29.                 break;  
    30.             }  
    31.             else  
    32.             {  
    33.                 EVP_DecryptUpdate(&ctx, decryptMsg+offseto, &offsett, sMsg+offseti, MAX_ENCRYPT_LEN);  
    34.                 offseti+=MAX_ENCRYPT_LEN;  
    35.                 offseto+=offsett;  
    36.             }  
    37.         }  
    38.         EVP_DecryptFinal_ex(&ctx, decryptMsg+offseto, &offsett);  
    39.   
    40.         offseto+=offsett;  
    41.         cbEncryptMsg=offseto;  
    42.     }  
    43.     EVP_CIPHER_CTX_cleanup(&ctx);  
    44.     std::cout << "openssl decrypt:" << std::endl;  
    45.   
    46.   
    47.     char* ret = (char*)malloc(cbEncryptMsg + 1);  
    48.     memcpy(ret,decryptMsg,cbEncryptMsg);  
    49.     ret[cbEncryptMsg] = '';  
    50.     std::cout << ret << endl;  
    51. }  

    测试下:

      1. int _tmain(int argc, _TCHAR* argv[])  
      2. {  
      3.     string text = "texttexttexttexttext";  
      4.     unsigned char* key;  
      5.     unsigned char* sEncryptMsg = (unsigned char*)malloc(text.size() + MD5_SIZE);  
      6.     int len;  
      7.     openssl_aes_encrypt(text,&key,sEncryptMsg,len);  
      8.   
      9.   
      10.     unsigned char** sEncryptMsg_crypto = (unsigned char**)malloc(sizeof(unsigned char*));  
      11.     int len_crypto;  
      12.     cryptoAPI_encrypt(text,key,sEncryptMsg_crypto,len_crypto);  
      13.     cout << "-----------------------------" << endl<<"cryptoAPI decrypt openssl"<<endl;  
      14.     //cryptAPI_decrypt(sEncryptMsg,len,key);  
      15.   
      16.     cout << "-----------------------------" << endl<<"cryptoAPI decrypt cryptoAPI"<<endl;  
      17.     //cryptAPI_decrypt(*sEncryptMsg_crypto,len_crypto,key);  
      18.   
      19.     cout << "-----------------------------" << endl<<"oepnssl decrypt openssl"<<endl;  
      20.     //openssl_aes_decrypt(sEncryptMsg,len,key);  
      21.   
      22.     cout << "-----------------------------" << endl<<"oepnssl decrypt cryptoAPI"<<endl;  
      23.     //openssl_aes_decrypt(*sEncryptMsg_crypto,len_crypto,key);  
      24.     return 0;  
      25. }  
  • 相关阅读:
    查缺补漏中~~
    The number of divisors(约数) about Humble Numbers
    Octorber 21st
    素数回文
    盐水的故事
    居然因为交换错了好几把。。。。,还有坑点是num1可以大于num2
    税收与补贴问题(洛谷1023)
    斐波拉契高精度(洛谷1255)
    高精度模板
    Codeforces#373 Div2
  • 原文地址:https://www.cnblogs.com/adylee/p/3611574.html
Copyright © 2011-2022 走看看