用Crypto++的RSA算法進行加解密

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,並且最好內存申請數量大於待加密數據長度的兩倍。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章