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,来个简单点的版本
- 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,//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摘要,相对比较简单
- 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里面的实现步骤:
- 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代码实现
- //参见 http://msdn.microsoft.com/en-us/library/aa379916(v=vs.85).aspx remarks步骤
- unsigned char* derivedKey(unsigned char*sessionKey/*hash后的值*/,size_t n/*密钥长度*/)
- {
- /**step 1*/
- 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];
- }
- /*step 2*/
- 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];
- }
- /*step 3*/
- unsigned char* ret1 = openssl_md5(buffer,64);
- /*step 4*/
- 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的实现顺序实现吧
- 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;//in
- int offseto=0;//out
- int offsett=0;//temp
- 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的解密:
- 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,//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的解密
- 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;//in
- int offseto=0;//out
- int offsett=0;//temp
- 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;
- }
测试下:
- 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;
- //cryptAPI_decrypt(sEncryptMsg,len,key);
- cout << "-----------------------------" << endl<<"cryptoAPI decrypt cryptoAPI"<<endl;
- //cryptAPI_decrypt(*sEncryptMsg_crypto,len_crypto,key);
- cout << "-----------------------------" << endl<<"oepnssl decrypt openssl"<<endl;
- //openssl_aes_decrypt(sEncryptMsg,len,key);
- cout << "-----------------------------" << endl<<"oepnssl decrypt cryptoAPI"<<endl;
- //openssl_aes_decrypt(*sEncryptMsg_crypto,len_crypto,key);
- return 0;
- }
openssl与cryptoAPI交互AES加密解密相关推荐
- android、ios、php之间AES加密解密
使用原因: 因为在项目中,需要在与客户端(IOS,Android)交互的时候,保存一些私有信息,不被别人看到,所以,使用了比较流行的可以反向加解密的AES. PHP 源码 <?php$aes = ...
- php7.1 aes 加密解密,PHP7.1中AES加密解密方法 mcrypt_module_open()替换方案
mcrypt 扩展已经过时了大约10年,并且用起来很复杂.因此它被废弃并且被 OpenSSL 所取代. 从PHP 7.2起它将被从核心代码中移除并且移到PECL中. PHP手册在7.1迁移页面给出了替 ...
- ios java aes_PHP7 AES加密解密函数_兼容ios/andriod/java对等加解密
**PHP7.0 7.1 7.2 7.3 AES对等加解密类 函数文件_兼容ios/andriod/java等** 由于新项目规划要求使用PHP7.2开发环境,但在部分新系统中仍需使用AES加解密方式 ...
- java php aes加密解密_php aes 加密解密可与java对接
php aes 加密解密可与java对接 博主:liu1693 发表时间:2017-02-23 16:52:27 浏览量:100 class Encrypt{ //加密方法 public static ...
- python 加密解密_python实现AES加密解密
本文实例为大家分享了python实现AES加密解密的具体代码,供大家参考,具体内容如下 (1)对于AES加密解密相关知识 (2)实现的功能就是输入0-16个字符,然后经过AES的加密解密最后可以得到原 ...
- AES加密解密算法Java实现
AES加密算法是密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DE ...
- c php aes加密解密,php的AES加密解密
下面是编程之家 jb51.cc 通过网络收集整理的代码片段. 编程之家小编现在分享给大家,也给大家做个参考. $privateKey = "1234567812345678"; $ ...
- 理解AES加密解密的使用方法
很多人对于AES加密并不是很了解,导致互相之间进行加密解密困难. 本文用简单的方式来介绍AES在使用上需要的知识,而不涉及内部算法.最后给出例子来帮助理解AES加密解密的使用方法. AES的麻烦 相比 ...
- C#中使用DES和AES加密解密
代码 using System; using System.Text; using System.Security.Cryptography; using System.IO; namespace M ...
最新文章
- 理解并取证:DLS网络架构和PPPOE数据帧
- try....exception....finally
- PyCairo 中的基本绘图
- java重载方法math_Java语言程序设计(十二)Math数学类,方法重载及变量作用域...
- linux转换大小写的脚本代码,文件名大小写转换的shell脚本
- 百度分享新浪微博无法分享图片的解决方法
- 统计正数和负数的个数然后计算这些数的平均值_计算机中的二进制原来是这样:原码、反码和补码
- 循环map 取得键和值_Java 从 Map 到 HashMap 的一步步实现
- linux基础期末考试免费,linux基础期末考试试题.doc
- 【实用数学手册(第2版)扫描版.pdf】和【免安装Matlab.7.0.绿色破解U盘便携移...】 百度网盘下载地址
- 【企业】走近华为,微观世界
- 测不准原理(还真有此事?)
- 贴片电阻各种封装规格及阻值标注方法
- verilog源码积累:ram和axi slaver
- 记一次NGINX配置问题
- vs2017旗舰版_2017年的所有旗舰手机都有明显的妥协。 这是他们告诉我们有关设计的信息。...
- 不想结婚要小孩了!怎么破?
- 3.4 数据预处理(一) - 数据集成(Data Integration)
- 月球轨道周期变化将造成2030年代地球沿海出现涨潮洪水
- Java高并发秒杀API(四)之高并发优化
热门文章
- 单例模式在多线程中的安全性研究
- 两款爱不释手的markdown编辑工具
- Spring Cloud(二) 配置Eureka Client
- linux 关于减号 - 代替stdin 和stdout 的用法
- 运维基础(13)日志切割工具 Logrotate
- java lambda函数_最常用的 Java 8 中的 Lambda 函数(项目中实用笔记)
- java多线程下载_Java实现多线程下载,支持断点续传
- 与顶级互联网公司技术大佬面对面聊聊RocketMQ
- 课时 11:可观测性:你的应用健康吗?(莫源)
- Kubernetes 新玩法:在 yaml 中编程