继上次只有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. if(!CryptAcquireContext(&hCryptProv,
  8. NULL,
  9. CSP_NAME,//CSP_NAME
  10. PROV_RSA_AES,
  11. CRYPT_VERIFYCONTEXT))
  12. {
  13. DWORD dwLastErr = GetLastError();
  14. if(NTE_BAD_KEYSET == dwLastErr)
  15. {
  16. return;
  17. }
  18. else{
  19. if(!CryptAcquireContext(&hCryptProv,
  20. NULL,
  21. CSP_NAME,
  22. PROV_RSA_AES,
  23. CRYPT_NEWKEYSET))
  24. {
  25. return;
  26. }
  27. }
  28. }
  29. if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))
  30. {
  31. return;
  32. }
  33. BYTE *pPwd = pwd;
  34. if(!CryptHashData(hHash, pPwd, 16, 0))
  35. {
  36. return;
  37. }
  38. if(!CryptDeriveKey(hCryptProv, CALG_AES_128, hHash, CRYPT_EXPORTABLE, &hKey))
  39. {
  40. return;
  41. }
  42. int len = text.length();
  43. BYTE *pData ;
  44. pData = (BYTE*)malloc(len*4);
  45. memcpy(pData,text.c_str(),len);
  46. DWORD dwLen = len;
  47. if(!CryptEncrypt(hKey, NULL, true, 0, pData, &dwLen, len*4))
  48. {
  49. return;
  50. }
  51. cout <<"--------------------------" << endl << "cryptoAPI encrypt"<<endl;
  52. printBytes(pData,dwLen);
  53. *encryptText = pData;
  54. out_len = dwLen;
  55. CryptDestroyHash(hHash);
  56. CryptDestroyKey(hKey);
  57. CryptReleaseContext(hCryptProv,0);
  58. }

这里将传进来的字节数组密钥先进行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. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 5.Concatenate the result of step 3 with the result of step 4.
  7. 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. for(int i = 0 ; i < 64;i++)
  7. {
  8. buffer[i] = 0x36;
  9. }
  10. int k = n;
  11. for(int i = 0 ; i < k ; i++)
  12. {
  13. buffer[i] = buffer[i] ^ sessionKey[i];
  14. }
  15. /*step 2*/
  16. unsigned char* buffer2 = (unsigned char*)malloc(64);
  17. for(int i = 0 ; i < 64;i++)
  18. {
  19. buffer2[i] = 0x5C;
  20. }
  21. for(int i = 0 ; i < k ; i++)
  22. {
  23. buffer2[i] = buffer2[i] ^ sessionKey[i];
  24. }
  25. /*step 3*/
  26. unsigned char* ret1 = openssl_md5(buffer,64);
  27. /*step 4*/
  28. unsigned char* ret2 = openssl_md5(buffer2,64);
  29. unsigned char* ret = (unsigned char*)malloc(128);
  30. for(int i = 0 ; i < 128;i++)
  31. {
  32. if(i<64)
  33. ret[i] = ret1[i];
  34. else
  35. ret[i] = ret2[i-64];
  36. }
  37. return ret;
  38. }

最麻烦的地方解决了...剩下再按照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. SessionKey = derivedKey(SessionKey,MD5_SIZE);
  9. const unsigned char* sMsg = (const unsigned char*)text.c_str();
  10. int cbMsg = text.length();
  11. int cbEncryptMsg;
  12. //加密
  13. EVP_CIPHER_CTX ctx;
  14. EVP_CIPHER_CTX_init(&ctx);
  15. if(EVP_EncryptInit_ex(&ctx,EVP_get_cipherbynid(NID_aes_128_cbc),NULL,SessionKey,NULL))
  16. {
  17. int offseti=0;//in
  18. int offseto=0;//out
  19. int offsett=0;//temp
  20. for(;;)
  21. {
  22. if(cbMsg-offseti<=MAX_ENCRYPT_LEN)
  23. {
  24. EVP_EncryptUpdate(&ctx, sEncryptMsg+offseto, &offsett, sMsg+offseti, cbMsg-offseti);
  25. offseto+=offsett;
  26. break;
  27. }
  28. else
  29. {
  30. EVP_EncryptUpdate(&ctx, sEncryptMsg+offseto, &offsett, sMsg+offseti, MAX_ENCRYPT_LEN);
  31. offseti+=MAX_ENCRYPT_LEN;
  32. offseto+=offsett;
  33. }
  34. }
  35. EVP_EncryptFinal_ex(&ctx, sEncryptMsg+offseto, &offsett);
  36. offseto+=offsett;
  37. cbEncryptMsg=offseto;
  38. }
  39. EVP_CIPHER_CTX_cleanup(&ctx);
  40. std::cout << "openssl encrypt:" << std::endl;
  41. printBytes(sEncryptMsg,cbEncryptMsg);
  42. len = cbEncryptMsg;
  43. }

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

下面是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. if(!CryptAcquireContext(&hCryptProv,
  8. NULL,
  9. CSP_NAME,//CSP_NAME
  10. PROV_RSA_AES,
  11. CRYPT_VERIFYCONTEXT))
  12. {
  13. DWORD dwLastErr = GetLastError();
  14. if(NTE_BAD_KEYSET == dwLastErr)
  15. {
  16. return;
  17. }
  18. else{
  19. if(!CryptAcquireContext(&hCryptProv,
  20. NULL,
  21. CSP_NAME,
  22. PROV_RSA_AES,
  23. CRYPT_NEWKEYSET))
  24. {
  25. return;
  26. }
  27. }
  28. }
  29. if(!CryptCreateHash(hCryptProv, CALG_MD5, 0, 0, &hHash))
  30. {
  31. return;
  32. }
  33. BYTE *pPwd = pwd;
  34. if(!CryptHashData(hHash, pPwd, 16, 0))
  35. {
  36. return;
  37. }
  38. if(!CryptDeriveKey(hCryptProv, CALG_AES_128, hHash, CRYPT_EXPORTABLE, &hKey))
  39. {
  40. return;
  41. }
  42. BYTE *pData = text;
  43. DWORD dwLen = len;
  44. if(!CryptDecrypt(hKey, NULL, true, 0, pData, &dwLen))
  45. {
  46. return;
  47. }
  48. cout <<"--------------------------" << endl << "cryptoAPI decrypt"<<endl;
  49. char* plainText = (char*)malloc(dwLen + 1);
  50. memcpy(plainText,pData,dwLen);
  51. plainText[dwLen] = '\0';
  52. cout << plainText << endl;
  53. CryptDestroyHash(hHash);
  54. CryptDestroyKey(hKey);
  55. CryptReleaseContext(hCryptProv,0);
  56. }

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

测试下:

    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. unsigned char** sEncryptMsg_crypto = (unsigned char**)malloc(sizeof(unsigned char*));
    9. int len_crypto;
    10. cryptoAPI_encrypt(text,key,sEncryptMsg_crypto,len_crypto);
    11. cout << "-----------------------------" << endl<<"cryptoAPI decrypt openssl"<<endl;
    12. //cryptAPI_decrypt(sEncryptMsg,len,key);
    13. cout << "-----------------------------" << endl<<"cryptoAPI decrypt cryptoAPI"<<endl;
    14. //cryptAPI_decrypt(*sEncryptMsg_crypto,len_crypto,key);
    15. cout << "-----------------------------" << endl<<"oepnssl decrypt openssl"<<endl;
    16. //openssl_aes_decrypt(sEncryptMsg,len,key);
    17. cout << "-----------------------------" << endl<<"oepnssl decrypt cryptoAPI"<<endl;
    18. //openssl_aes_decrypt(*sEncryptMsg_crypto,len_crypto,key);
    19. return 0;
    20. }

openssl与cryptoAPI交互AES加密解密的更多相关文章

  1. ruby AES加密解密

    最近和京东合作做一个项目,在接口对接传递参数时,参数需要通过AES加密解密. 本来想到用gem 'aescrypt'处理,但是aescrypt的编码方式用的base64,而京东那边用的是16进制.所以 ...

  2. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  3. 非对称技术栈实现AES加密解密

    非对称技术栈实现AES加密解密 正如前面的一篇文章所述,https协议的SSL层是实现在传输层之上,应用层之下,也就是说在应用层上看到的请求还是明码的,对于某些场景下要求这些http请求参数是非可读的 ...

  4. C#中使用DES和AES加密解密

    C#中使用DES和AES加密解密 2008-01-12 09:37 using System;using System.Text;using System.Security.Cryptography; ...

  5. C#, Java, PHP, Python和Javascript几种语言的AES加密解密实现[转载]

    原文:http://outofmemory.cn/code-snippet/35524/AES-with-javascript-java-csharp-python-or-php c#里面的AES加密 ...

  6. java使用AES加密解密 AES-128-ECB加密

    java使用AES加密解密 AES-128-ECB加密 import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; impo ...

  7. AES加密解密——AES在JavaWeb项目中前台JS加密,后台Java解密的使用

    一:前言 在软件开发中,经常要对数据进行传输,数据在传输的过程中可能被拦截,被监听,所以在传输数据的时候使用数据的原始内容进行传输的话,安全隐患是非常大的.因此就要对需要传输的数据进行在客户端进行加密 ...

  8. AES加密解密 助手类 CBC加密模式

    "; string result1 = AESHelper.AesEncrypt(str); string result2 = AESHelper.AesDecrypt(result1); ...

  9. php与java通用AES加密解密算法

    AES指高级加密标准(Advanced Encryption Standard),是当前最流行的一种密码算法,在web应用开发,特别是对外提供接口时经常会用到,下面是我整理的一套php与java通用的 ...

随机推荐

  1. 一个for列出横纵坐标

    h = i % * hCount; v = Math.floor(i / hCount);

  2. 遇到double 数目过大,转String变成科学计数法

    问题: java中,当double数目过大,转出String时,变成了科学记数法的表示. 总结: 1.项目的存储用的是mysql,mysql的类型和java类型之间存在映射关系,以前关注不多.现在总结 ...

  3. /cdrom /media /mnt

    /media : Mount point for removeable media Purpose This directory contains subdirectories which are u ...

  4. jq中 offset()方法, scrollTop()方法以及scrollLeft()方法

    offset()方法是用来获取元素在当前视窗的相对偏移,其中返回的对象包含两个属性,即top和left,它只对可见元素有效. scrollTop()方法是用来获取元素的滚动条距离顶端的距离. scro ...

  5. hdu 1548 (dijkstra解法)(一次AC就是爽)

    恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 A strange lift Time Limit: 200 ...

  6. hilbert矩阵

    希尔伯特矩阵 希尔伯特矩阵是一种数学变换矩阵 Hilbert matrix,矩阵的一种,其元素A(i,j)=1/(i+j-1),i,j分别为其行标和列标. 即: [1,1/2,1/3,……,1/n] ...

  7. Oracle数据库Linux下的导出EXP

    先转一篇 ================================我是分割线================================ 时间:2013-06-22 13:48来源:未知 ...

  8. linux笔记_文件搜索命令

    一.locate命令 locate命令属于mlocate包,如果执行locate filename提示命令未找到执行安装mlocate包 # yum -y install mlocate 安装后执行l ...

  9. 机器翻译 2010年NOIP全国联赛提高组

    题目描述 Description 小晨的电脑上安装了一个机器翻译软件,他经常用这个软件来翻译英语文章. 这个翻译软件的原理很简单,它只是从头到尾,依次将每个英文单词用对应的中文含义 来替换.对于每个英 ...

  10. android中ListView_SimpleAdapter

    1.首先看下main_activity.xml.其实里面就放了一个ListView. <LinearLayout xmlns:android="http://schemas.andro ...