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,来个简单点的版本
[cpp] view plain copy print ?- voidcryptoAPI_encrypt(stringtext,unsignedchar*pwd,unsignedchar**encryptText,int&out_len)
- {
- HCRYPTPROVhCryptProv=NULL;
- HCRYPTKEYhKey=0;
- HCRYPTHASHhHash=0;
- intdwLength=0;
- if(!CryptAcquireContext(&hCryptProv,
- NULL,
- CSP_NAME,//CSP_NAME
- PROV_RSA_AES,
- CRYPT_VERIFYCONTEXT))
- {
- DWORDdwLastErr=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;
- }
- intlen=text.length();
- BYTE*pData;
- pData=(BYTE*)malloc(len*4);
- memcpy(pData,text.c_str(),len);
- DWORDdwLen=len;
- if(!CryptEncrypt(hKey,NULL,true,0,pData,&dwLen,len*4))
- {
- return;
- }
- cout<<"--------------------------"<<endl<<"cryptoAPIencrypt"<<endl;
- printBytes(pData,dwLen);
- *encryptText=pData;
- out_len=dwLen;
- CryptDestroyHash(hHash);
- CryptDestroyKey(hKey);
- CryptReleaseContext(hCryptProv,0);
- }
这里将传进来的字节数组密钥先进行MD5摘要后,再通过CryptoDeriveKey来得到最后用来加密的密钥
openssl要以同样的方式做一次这个步骤,首先是MD5摘要,相对比较简单
[cpp] view plain copy print ?- unsignedchar*openssl_md5(unsignedchar*sessionKey,size_tn)
- {
- unsignedchar*ret=(unsignedchar*)malloc(MD5_DIGEST_LENGTH);
- MD5(sessionKey,n,ret);
- returnret;
- }
然后再来实现CryptoDeriveKey,先来看下MSDN上对于这个函数的说明
主要看remarks里面的实现步骤:
[plain] view plain copy print ?- Letnbetherequiredderivedkeylength,inbytes.ThederivedkeyisthefirstnbytesofthehashvalueafterthehashcomputationhasbeencompletedbyCryptDeriveKey.IfthehashisnotamemberoftheSHA-2familyandtherequiredkeyisforeither3DESorAES,thekeyisderivedasfollows:
- 1.Forma64-bytebufferbyrepeatingtheconstant0x3664times.LetkbethelengthofthehashvaluethatisrepresentedbytheinputparameterhBaseData.SetthefirstkbytesofthebuffertotheresultofanXORoperationofthefirstkbytesofthebufferwiththehashvaluethatisrepresentedbytheinputparameterhBaseData.
- 2.Forma64-bytebufferbyrepeatingtheconstant0x5C64times.SetthefirstkbytesofthebuffertotheresultofanXORoperationofthefirstkbytesofthebufferwiththehashvaluethatisrepresentedbytheinputparameterhBaseData.
- 3.Hashtheresultofstep1byusingthesamehashalgorithmasthatusedtocomputethehashvaluethatisrepresentedbythehBaseDataparameter.
- 4.Hashtheresultofstep2byusingthesamehashalgorithmasthatusedtocomputethehashvaluethatisrepresentedbythehBaseDataparameter.
- 5.Concatenatetheresultofstep3withtheresultofstep4.
- 6.Usethefirstnbytesoftheresultofstep5asthederivedkey.
非常简单的英文,不做翻译了...
直接上openssl代码实现
[cpp] view plain copy print ?- //参见http://msdn.microsoft.com/en-us/library/aa379916(v=vs.85).aspxremarks步骤
- unsignedchar*derivedKey(unsignedchar*sessionKey/*hash后的值*/,size_tn/*密钥长度*/)
- {
- /**step1*/
- unsignedchar*buffer=(unsignedchar*)malloc(64);
- for(inti=0;i<64;i++)
- {
- buffer[i]=0x36;
- }
- intk=n;
- for(inti=0;i<k;i++)
- {
- buffer[i]=buffer[i]^sessionKey[i];
- }
- /*step2*/
- unsignedchar*buffer2=(unsignedchar*)malloc(64);
- for(inti=0;i<64;i++)
- {
- buffer2[i]=0x5C;
- }
- for(inti=0;i<k;i++)
- {
- buffer2[i]=buffer2[i]^sessionKey[i];
- }
- /*step3*/
- unsignedchar*ret1=openssl_md5(buffer,64);
- /*step4*/
- unsignedchar*ret2=openssl_md5(buffer2,64);
- unsignedchar*ret=(unsignedchar*)malloc(128);
- for(inti=0;i<128;i++)
- {
- if(i<64)
- ret[i]=ret1[i];
- else
- ret[i]=ret2[i-64];
- }
- returnret;
- }
最麻烦的地方解决了...剩下再按照CryptoAPI的实现顺序实现吧
- voidopenssl_aes_encrypt(stringtext,unsignedchar**SessionKey_out/*这里主要用作将产生的对称密钥输出*/,unsignedchar*sEncryptMsg,int&len)
- {
- OpenSSL_add_all_algorithms();
- //产生会话密钥
- *SessionKey_out=(unsignedchar*)malloc(MD5_SIZE);
- RAND_bytes(*SessionKey_out,MD5_SIZE);//产生随机密钥,输出之后可以给其他方法是用了
- unsignedchar*SessionKey=openssl_md5(*SessionKey_out,MD5_SIZE);
- SessionKey=derivedKey(SessionKey,MD5_SIZE);
- constunsignedchar*sMsg=(constunsignedchar*)text.c_str();
- intcbMsg=text.length();
- intcbEncryptMsg;
- //加密
- EVP_CIPHER_CTXctx;
- EVP_CIPHER_CTX_init(&ctx);
- if(EVP_EncryptInit_ex(&ctx,EVP_get_cipherbynid(NID_aes_128_cbc),NULL,SessionKey,NULL))
- {
- intoffseti=0;//in
- intoffseto=0;//out
- intoffsett=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<<"opensslencrypt:"<<std::endl;
- printBytes(sEncryptMsg,cbEncryptMsg);
- len=cbEncryptMsg;
- }
加密的搞定了,可以尝试下了,同样的密钥和同样的明文,密文输出结果是一样的就对了
下面是CrytpoAPI的解密:
[cpp] view plain copy print ?- voidcryptAPI_decrypt(unsignedchar*text,intlen,unsignedchar*pwd)
- {
- HCRYPTPROVhCryptProv=NULL;
- HCRYPTKEYhKey=0;
- HCRYPTHASHhHash=0;
- intdwLength=0;
- if(!CryptAcquireContext(&hCryptProv,
- NULL,
- CSP_NAME,//CSP_NAME
- PROV_RSA_AES,
- CRYPT_VERIFYCONTEXT))
- {
- DWORDdwLastErr=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;
- DWORDdwLen=len;
- if(!CryptDecrypt(hKey,NULL,true,0,pData,&dwLen))
- {
- return;
- }
- cout<<"--------------------------"<<endl<<"cryptoAPIdecrypt"<<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 plain copy print ?- voidopenssl_aes_decrypt(unsignedchar*text,intlen,unsignedchar*SessionKeyP)
- {
- unsignedchar*decryptMsg=(unsignedchar*)malloc(len);
- OpenSSL_add_all_algorithms();
- unsignedchar*SessionKey=openssl_md5(SessionKeyP,MD5_SIZE);
- SessionKey=derivedKey(SessionKey,MD5_SIZE);
- constunsignedchar*sMsg=text;
- intcbMsg=len;
- intcbEncryptMsg;
- //解密
- EVP_CIPHER_CTXctx;
- EVP_CIPHER_CTX_init(&ctx);
- if(EVP_DecryptInit_ex(&ctx,EVP_get_cipherbynid(NID_aes_128_cbc),NULL,SessionKey,NULL))
- {
- intoffseti=0;//in
- intoffseto=0;//out
- intoffsett=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<<"openssldecrypt:"<<std::endl;
- char*ret=(char*)malloc(cbEncryptMsg+1);
- memcpy(ret,decryptMsg,cbEncryptMsg);
- ret[cbEncryptMsg]='\0';
- std::cout<<ret<<endl;
- }
测试下:
[cpp] view plain copy print ?- int_tmain(intargc,_TCHAR*argv[])
- {
- stringtext="texttexttexttexttext";
- unsignedchar*key;
- unsignedchar*sEncryptMsg=(unsignedchar*)malloc(text.size()+MD5_SIZE);
- intlen;
- openssl_aes_encrypt(text,&key,sEncryptMsg,len);
- unsignedchar**sEncryptMsg_crypto=(unsignedchar**)malloc(sizeof(unsignedchar*));
- intlen_crypto;
- cryptoAPI_encrypt(text,key,sEncryptMsg_crypto,len_crypto);
- cout<<"-----------------------------"<<endl<<"cryptoAPIdecryptopenssl"<<endl;
- //cryptAPI_decrypt(sEncryptMsg,len,key);
- cout<<"-----------------------------"<<endl<<"cryptoAPIdecryptcryptoAPI"<<endl;
- //cryptAPI_decrypt(*sEncryptMsg_crypto,len_crypto,key);
- cout<<"-----------------------------"<<endl<<"oepnssldecryptopenssl"<<endl;
- //openssl_aes_decrypt(sEncryptMsg,len,key);
- cout<<"-----------------------------"<<endl<<"oepnssldecryptcryptoAPI"<<endl;
- //openssl_aes_decrypt(*sEncryptMsg_crypto,len_crypto,key);
- return0;
- }
更多相关文章
- 2种方式进行Spinner数据的添加
- Android(安卓)Service两种启动方式详解(总结版)
- 几种判断应用(Android(安卓)App)前后台状态的方法
- 深度揭秘android摄像头的autoFocus-----循环自动聚焦的实现(Andro
- Android(安卓)的网络编程(3)-HttpURLConnection接口
- TCL 雏鹰飞翔计划 Android篇
- Android开发中怎样调用系统Email发送邮件(多种调用方式)
- Android与Windows Socket通信,TLS双向认证
- Android获取控件宽高的几种方式