OpenSSL庫過於龐大,一個exe靜態鏈接後,會變成2MB。於是尋找別的算法庫。最後找到了Crypto++。程序編譯後,Release版本只會增大200KB,還是很不錯的。
cryptest中的代碼,會自動把二進制轉爲字符串,很讓人頭大。幸好找到了以Crypto++實現RSA加解密二進制數據,講解了二進制操作的方法。
因爲那篇文章已經有幾年歷史,有幾個API有一些變動。
生產RSA密鑰對(默認4096):
#include <randpool.h>
#include <files.h>
#include <rsa.h>
void GenerateRSAKey(uint8_t* pSeed, uint64_t u64SeedLen, uint8_t* pPrivateKey, uint64_t& u64PrivateKeyLen, uint8_t* pPublicKey, uint64_t& u64PublicKeyLen)
{
CryptoPP::RandomPool randomPool;
randomPool.IncorporateEntropy(pSeed, (size_t)u64SeedLen);
CryptoPP::RSAES_OAEP_SHA_Decryptor decryptor(randomPool, 4096);
CryptoPP::ArraySink decArr(pPrivateKey, (size_t)u64PrivateKeyLen);
decryptor.AccessMaterial().Save(decArr);
decArr.MessageEnd();
u64PrivateKeyLen = decArr.TotalPutLength();
CryptoPP::RSAES_OAEP_SHA_Encryptor encryptor(decryptor);
CryptoPP::ArraySink encArr(pPublicKey, (size_t)u64PublicKeyLen);
encryptor.AccessMaterial().Save(encArr);
encArr.MessageEnd();
u64PublicKeyLen = encArr.TotalPutLength();
}
加密:
#include <randpool.h>
#include <files.h>
#include <rsa.h>
void RSAEncryptData(uint8_t* pSeed, uint64_t u64SeedLen, uint8_t* pPublicKey, uint64_t u64PublicKeyLen, uint8_t* pPlainData, uint64_t u64PlainDataLen, uint8_t* pCipherData, uint64_t& u64CipherDataLen)
{
CryptoPP::ArraySource keyArr(pPublicKey, (size_t)u64PublicKeyLen, true);
CryptoPP::RSAES_OAEP_SHA_Encryptor enc;
enc.AccessKey().Load(keyArr);
CryptoPP::RandomPool randomPool;
randomPool.IncorporateEntropy(pSeed, (size_t)u64SeedLen);
uint64_t putLen = 0;
uint64_t fixedLen = enc.FixedMaxPlaintextLength();
for (uint64_t i = 0; i < u64PlainDataLen; i += fixedLen)
{
uint64_t len = fixedLen < (u64PlainDataLen - i) ? fixedLen : (u64PlainDataLen - i);
CryptoPP::ArraySink* dstArr = new CryptoPP::ArraySink(pCipherData + putLen, (size_t)(u64CipherDataLen - putLen));
CryptoPP::ArraySource source(pPlainData + i, (size_t)len, true, new CryptoPP::PK_EncryptorFilter(randomPool, enc, dstArr));
putLen += dstArr->TotalPutLength();
}
u64CipherDataLen = putLen;
}
解密:
#include <randpool.h>
#include <files.h>
#include <rsa.h>
void RSADecryptData(uint8_t* pSeed, uint64_t u64SeedLen, uint8_t* pPrivateKey, uint64_t u64PrivateKeyLen, uint8_t* pCipherData, uint64_t u64CipherDataLen, uint8_t* pPlainData, uint64_t& u64PlainDataLen)
{
CryptoPP::ArraySource keyArr(pPrivateKey, (size_t)u64PrivateKeyLen, true);
CryptoPP::RSAES_OAEP_SHA_Decryptor dec;
dec.AccessKey().Load(keyArr);
CryptoPP::RandomPool randomPool;
randomPool.IncorporateEntropy(pSeed, (size_t)u64SeedLen);
uint64_t putLen = 0;
uint64_t fixedLen = dec.FixedCiphertextLength();
for (uint64_t i = 0; i < u64CipherDataLen; i += fixedLen)
{
uint64_t len = fixedLen < (u64CipherDataLen - i) ? fixedLen : (u64CipherDataLen - i);
CryptoPP::ArraySink* dstArr = new CryptoPP::ArraySink(pPlainData + putLen, (size_t)(u64PlainDataLen - putLen));
CryptoPP::ArraySource source(pCipherData + i, (size_t)len, true, new CryptoPP::PK_DecryptorFilter(randomPool, dec, dstArr));
putLen += dstArr->TotalPutLength();
}
u64PlainDataLen = putLen;
}
你會發現上面的加密解密代碼有幾處new,沒有delete,因爲Filter在析構的時候會順帶釋放。
測試代碼:
uint8_t seed[] = "jhsgfjwebnr";
uint8_t publicKey[4096] = { 0 };
uint64_t publicKeyLen = 4096;
uint8_t privateKey[4096] = { 0 };
uint64_t privateKeyLen = 4096;
GenerateRSAKey(seed, sizeof(seed), privateKey, privateKeyLen, publicKey, publicKeyLen);
char str[] = "HelloWorld";
uint8_t pOut[2048] = { 0 };
uint64_t OutLen = 2048;
RSAEncryptData(seed, sizeof(seed), publicKey, publicKeyLen, (uint8_t*)str, sizeof(str), pOut, OutLen);
RSADecryptData(seed, sizeof(seed), privateKey, privateKeyLen, pOut, OutLen, pOut, OutLen);
pOut[OutLen] = 0;
在密鑰長度爲4096的時候,pOut需要不少於512,並且最好內存申請數量大於待加密數據長度的兩倍。