异想天开

What's the true meaning of light, Could you tell me why

openssl学习

日期:2014-10-28 11:56:34
  
最后更新日期:2014-11-11 15:23:01
【技术】
1.openssl库rsa加密和解密 RSA算法就是通常所说的公钥加密,私钥解密算法。实际开发中通常并不直接用RSA算法加密数据,因为实施RSA算法时,对加密的数据块长度有限制。man手册看到:
[code lang="cpp"]
#man RSA_public_encrypt
flen must be less than RSA_size(rsa) - 11 for the PKCS #1 v1.5 based padding modes, less
than RSA_size(rsa) - 41 for RSA_PKCS1_OAEP_PADDING and exactly RSA_size(rsa) for
RSA_NO_PADDING. The random number generator must be seeded prior to calling
RSA_public_encrypt().
[/code]
RSA_size(rsa)就是你的密钥是1024位的,还是2048位的。限制长度如上所示,与选择的padding有关,若padding方式为PKCS #1 v1.5,rsa密钥长度为1024bit即128byte那么限制长度为128byte-11即117byte。所以通常用RSA算法来加密AES/DES的密钥,传递给对方。另外的方法,如openrtmfp程序,session握手时,传递的数据块某一段的hash值,作为AES/DES的密钥。openssl即是一个二进制程序,又是一个API库。利用openssl产生公钥,私钥的方法。 [code lang="cpp"]
openssl genrsa -out privatekey.pem 1024
openssl rsa -in privatekey.pem -pubout > public.key
[/code]
openssl命令以及API众多,需要慢慢熟悉。aes/des加密和解密见另外一篇博文:《openssl库demo》:
1.1RSA加密部分demo,来自于参考1: [code lang="cpp"]
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;
}
[/code]
1.2RSA私钥解密部分demo,同样来自于参考1: [code lang="cpp"]
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;
}
[/code]

1.3桩测试函数 [code lang="cpp"]
std::string hex_str(std::string &str)
{
static char map_c[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
std::string ret_str;
for ( unsigned int i=0; i<str.length();++i){
char ch=str[i];
char ch_1=map_c[ch&0xF0 >> 4];
char ch_2=map_c[ch&0x0F];
ret_str +=ch_1;
ret_str +=ch_2;
}
return ret_str;
}
std::string encode_str=EncodeRSAKeyFile("./public.key","hello world");
std::string decode_str=DecodeRSAKeyFile("./privatekey.pem",encode_str);
std::cout<<"encode str:"<<hex_str(encode_str) <<std::endl << "decode str:"<< decode_str <<std::endl;
[/code]
2.openssl库Diffie-Hellman key exchange Diffie-Hellman原理见另外博文:《Diffie-Hellman密钥交换》。
2.1计算自己的public key的demo,代码来源于openrtmfp [code lang="cpp"]
DH* BeginDiffieHellman(UInt8* pubKey) {
static unsigned char g_dh1024p[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};

DH* pDH = DH_new();
pDH->p = BN_new();
pDH->g = BN_new();

BN_set_word(pDH->g, 2); //group DH 2
BN_bin2bn(g_dh1024p,KEY_SIZE,pDH->p); //prime number
if(!DH_generate_key(pDH))
std::cout<<"Generation DH key failed!"<<std::endl;

// It's our key public part
BN_bn2bin(pDH->pub_key,pubKey);
return pDH;
}
[/code]
2.2计算shared key的demo,代码来源于openrtmfp [code lang="cpp"]
void ComputeDiffieHellmanSecret(DH* pDH,const UInt8* farPubKey,UInt16 farPubKeySize,UInt8* sharedSecret) {
BIGNUM *bnFarPubKey = BN_bin2bn(farPubKey,farPubKeySize,NULL);
if(DH_compute_key(sharedSecret, bnFarPubKey,pDH)<=0)
std::cout<<"Diffie Hellman exchange failed : dh compute key error"<<std::endl;
BN_free(bnFarPubKey);
}
[/code]

2.3桩测试函数 [code lang="cpp"]
UInt8 pubkey_s[512],pubkey_c[512],shared_s[512],shared_c[512];
DH * pdh=BeginDiffieHellman(pubkey_s);
DH* premote=BeginDiffieHellman(pubkey_c);
//server compute sharekey
std::cout<<"server pub key:"<<BN_bn2hex(pdh->pub_key)<<std::endl;
std::cout<<"client pub key:"<<BN_bn2hex(premote->pub_key)<<std::endl;
ComputeDiffieHellmanSecret(pdh,pubkey_c,KEY_SIZE,shared_s);
std::string shared_str_s((char*)shared_s,KEY_SIZE);
std::cout<<"share key:"<<hex_str(shared_str_s)<<std::endl;
//client compute sharedkey
ComputeDiffieHellmanSecret(premote,pubkey_s,KEY_SIZE,shared_c);
std::string shared_str_c((char*)shared_c,KEY_SIZE);
std::cout<<"share key:"<<hex_str(shared_str_c)<<std::endl;
[/code]

3.openssl库hmac类函数 [code lang="cpp"]
//一个函数原型
unsigned char *HMAC(const EVP_MD *evp_md, const void *key,
int key_len, const unsigned char *d, int n,
unsigned char *md, unsigned int *md_len);
//调用例子,若md_len不为null,则md长度返回给md_len
HMAC(EVP_sha256(),sharedSecret,KEY_SIZE,mdp1,AES_KEY_SIZE,requestKey,NULL);
[/code]
该函数作用为用sharedSecret作密钥,用sha256作哈希算法,将数据mdp1算出哈希值requestKey。
参考1:
http://blog.csdn.net/chary8088/article/details/21124495