//demo.cpp
// g++ demo.cpp -o demo -lcrypto
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
using namespace std;
//加密
std::string EncodeRSAKeyFile( const std::string& strPemFileName, const std::string& strData )
{
if (strPemFileName.empty() || strData.empty())
{
assert(false);
return "";
}
FILE* hPubKeyFile = fopen(strPemFileName.c_str(), "rb");
if( hPubKeyFile == NULL )
{
assert(false);
return "";
}
std::string strRet;
RSA* pRSAPublicKey = RSA_new();
if(PEM_read_RSA_PUBKEY(hPubKeyFile, &pRSAPublicKey, 0, 0) == NULL)
{
assert(false);
return "";
}
int nLen = RSA_size(pRSAPublicKey);
char* pEncode = new char[nLen + 1];
int ret = RSA_public_encrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pEncode, pRSAPublicKey, RSA_PKCS1_PADDING);
if (ret >= 0)
{
strRet = std::string(pEncode, ret);
}
delete[] pEncode;
RSA_free(pRSAPublicKey);
fclose(hPubKeyFile);
CRYPTO_cleanup_all_ex_data();
return strRet;
}
//解密
std::string DecodeRSAKeyFile( const std::string& strPemFileName, const std::string& strData )
{
if (strPemFileName.empty() || strData.empty())
{
assert(false);
return "";
}
FILE* hPriKeyFile = fopen(strPemFileName.c_str(),"rb");
if( hPriKeyFile == NULL )
{
assert(false);
return "";
}
std::string strRet;
RSA* pRSAPriKey = RSA_new();
if(PEM_read_RSAPrivateKey(hPriKeyFile, &pRSAPriKey, 0, 0) == NULL)
{
assert(false);
return "";
}
int nLen = RSA_size(pRSAPriKey);
char* pDecode = new char[nLen+1];
int ret = RSA_private_decrypt(strData.length(), (const unsigned char*)strData.c_str(), (unsigned char*)pDecode, pRSAPriKey, RSA_PKCS1_PADDING);
if(ret >= 0)
{
strRet = std::string((char*)pDecode, ret);
}
delete [] pDecode;
RSA_free(pRSAPriKey);
fclose(hPriKeyFile);
CRYPTO_cleanup_all_ex_data();
return strRet;
}
int main()
{
//原文
const string one = "skl;dfhas;lkdfhslk;dfhsidfhoiehrfoishfsidf";
cout << "one: " << one << endl;
//密文(二进制数据)
string two = EncodeRSAKeyFile("pubkey.pem", one);
cout << "two: " << two << endl;
//顺利的话,解密后的文字和原文是一致的
string three = DecodeRSAKeyFile("prikey.pem", two);
cout << "three: " << three << endl;
return 0;
}
RSA的API中当使用参数RSA_PKCS1_PADDING时,明文长度不能大于密文长度-11;当使用参数RSA_NO_PADDING时,明文长度需要正好是128。 AES加密部分代码:
std::string EncodeAES( const std::string& password, const std::string& data )AES解密部分代码:
{
AES_KEY aes_key;
if(AES_set_encrypt_key((const unsigned char*)password.c_str(), password.length() * 8, &aes_key) < 0)
{
assert(false);
return "";
}
std::string strRet;
std::string data_bak = data;
unsigned int data_length = data_bak.length();
int padding = 0;
if (data_bak.length() % AES_BLOCK_SIZE > 0)
{
padding = AES_BLOCK_SIZE - data_bak.length() % AES_BLOCK_SIZE;
}
data_length += padding;
while (padding > 0)
{
data_bak += '\0';
padding--;
}
for(unsigned int i = 0; i < data_length/AES_BLOCK_SIZE; i++)
{
std::string str16 = data_bak.substr(i*AES_BLOCK_SIZE, AES_BLOCK_SIZE);
unsigned char out[AES_BLOCK_SIZE];
::memset(out, 0, AES_BLOCK_SIZE);
AES_encrypt((const unsigned char*)str16.c_str(), out, &aes_key);
strRet += std::string((const char*)out, AES_BLOCK_SIZE);
}
return strRet;
}
std::string DecodeAES( const std::string& strPassword, const std::string& strData )AES加密,块大小必须为128位(16字节),如果不是,则要补齐,密钥长度可以选择128位、192位、256位。 不同语言解密补充: 使用python解密的时候,public key可能要求是PKCS#1格式,而openssl是不支持的,openssl默认是x509格式的public key,为此,如果要把上边生成的public key提供给python使用,需要先从x509格式转换为PKCS#1格式。网络上的资料显示,php有一个api支持这种转换,但我没试过。由于我的私钥是2048位的,所以可以很方便的实现x509转PKCS#1,转换是可逆的,说下PKCS#1转x509的方法:首先删除head和foot的“RSA”,然后在第二行开头增加文本“MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A”,最后,对齐文本。如果私钥不是2048的怎么办呢?可以使用php的api转一下了,或者到网上查找转换的资料解决。RSA key Formats。 2013.11.27. 一些资料: http://www.ibm.com/developerworks/cn/linux/l-openssl.html http://www.cnblogs.com/aLittleBitCool/archive/2011/09/22/2185418.html 明文长度限制: http://bbs.chinaunix.net/thread-1860492-1-1.html AES加密例子: http://blog.csdn.net/wklnewlife/article/details/8244893 http://www.lovelucy.info/openssl-aes-encryption.html http://www.thinkemb.com/wordpress/?p=18 编译资料补充: http://developer.covenanteyes.com/building-openssl-for-visual-studio/
{
AES_KEY aes_key;
if(AES_set_decrypt_key((const unsigned char*)strPassword.c_str(), strPassword.length() * 8, &aes_key) < 0)
{
assert(false);
return "";
}
std::string strRet;
for(unsigned int i = 0; i < strData.length()/AES_BLOCK_SIZE; i++)
{
std::string str16 = strData.substr(i*AES_BLOCK_SIZE, AES_BLOCK_SIZE);
unsigned char out[AES_BLOCK_SIZE];
::memset(out, 0, AES_BLOCK_SIZE);
AES_decrypt((const unsigned char*)str16.c_str(), out, &aes_key);
strRet += std::string((const char*)out, AES_BLOCK_SIZE);
}
return strRet;
}