使用Crypto++将对称AES密钥用RSA加密

4

我正在尝试在两个部分之间交换AES密钥。该AES密钥将使用接收者的RSA publicKey进行加密,然后写入文件。

我正在使用Crypto++库,以下是我的程序开头:

//generate key pair
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::RSAES_OAEP_SHA_Decryptor priv(rng, 4096);

RSA::PrivateKey privateKey(params);
RSA::PublicKey publicKey(params);

//generate aes key (256bits)
SecByteBlock key(AES::MAX_KEYLENGTH);
rnd.GenerateBlock(key, key.size());

你将认出Crypto++维基百科的例子

然后我开始加密过程:

CryptoPP::SecByteBlock cipher(CryptoPP::AES::MAX_KEYLENGTH), decrypted_data(CryptoPP::AES::MAX_KEYLENGTH);

CryptoPP::RSAES_OAEP_SHA_Encryptor e(publicKey);

我不知道该使用哪个: CryptoPP::ArraySource 还是 CryptoPP::StringSource


一个AES密钥由字节/位组成,因此ArraySource更为合理。密钥的加密也称为密钥包装,但在互联网上快速搜索并没有直接的结果。由于Crypto++是一个软件库,加密字节或密钥几乎没有区别,这就解释了为什么缺少此方面的示例代码。 - Maarten Bodewes
1个回答

3

...之后我不知道该使用什么:CryptoPP :: ArraySource?CryptoPP :: StringSource?

在此之后,使用PK_EncryptorFilter进行RSA加密器;并使用ArraySource对您要加密的密钥进行加密。 ArraySource只是StringSource的typedef,因此您实际上只是使用了StringSource

代码将类似于以下内容。 我没有运行示例,请修复拼写错误。

SecByteBlock key(AES::MAX_KEYLENGTH);
rng.GenerateBlock(key, key.size());
...

RSAES_OAEP_SHA_Encryptor encryptor(publicKey);
...

ArraySource as(key, key.size(), true, /* pump all data */
    new PK_EncryptorFilter(rng, encryptor,
        new FileSink("session-key.enc")));

您可以使用类似以下方式将其写入到std::string中:
std::string session_key;
ArraySource as(key, key.size(), true, /* pump all data */
    new PK_EncryptorFilter(rng, encryptor,
        new StringSink(session_key)));

你还可以使用 ByteQueue 来进行更高级的操作。 Redirector 打破了所有权链。另请参见Crypto++ wiki上的 Redirector
ByteQueue queue;
ArraySource as(key, key.size(), true, /* pump all data */
    new PK_EncryptorFilter(rng, encryptor,
        new Redirector(queue)));

ByteQueue很酷,因为它们包装了SecByteBlock。一旦在ByteQueue中,您可以使用TransferToCopyTo移动字节:

ByteQueue queue;
ArraySource as(key, key.size(), true, /* pump all data */
    new PK_EncryptorFilter(rng, encryptor,
        new Redirector(queue)));

// Copy bytes to a file
FileSink sink1("session-key.enc");
queue.CopyTo(sink1);

// Copy bytes to std::out
HexEncoder encoder(new FileSink(std::cout));
queue.CopyTo(encoder);

// Transfer bytes to a SecByteBlock.
SecByteBlock block(queue.MaxRetrievable());
ArraySink sink2(block, block.size());
queue.TransferTo(sink2);
// No bytes remain in the queue

你可能也会对Crypto++维基上的Pipelines感兴趣。你在上面看到的是管道中使用的源、过滤器和汇。
如果这个变量应该保存加密后的对称密钥,那么它太小了:
SecByteBlock cipher(AES::MAX_KEYLENGTH);

请看Crypto++维基上的RSA加密方案。cipher需要设置为encryptor.CiphertextLength(AES::MAX_KEYLENGTH);,大致等于RSA模量大小减去OAEP格式化和填充的50个字节。保留HTML标签。

(comment) > Now I am trying to add the part to decrypt it using the private key... Is this correct ?

StringSource(readed_key, true,
    new PK_DecryptorFilter(rng, decryptor, new 
        FileSource("sessionkey.enc")));

好的,过滤器部分是正确的(PK_DecryptorFilter 部分)。在 Crypto++ 中,数据从源流向汇。因此,一般模式如下所示。它被称为 Pipeline

Source(..., new Filter(..., new Filter(..., new Sink(...))));

通常您需要像以下这样的内容。 Redirector 打破了所有权链。另请参见 Crypto++ wiki 上的 Redirector
// decrypted, in-memory
SecByteBlock session_key(AES::MAX_KEYLENGTH);
ArraySink sink(session_key, session_key.size());

FileSource fs("sessionkey.enc", true,
    new PK_DecryptorFilter(rng, decryptor, 
        new Redirector(sink)));

(注释) > ... 然后比较原始数据 ...

您可以使用VerifyBufsEqual在几乎恒定的时间内比较两个字节缓冲区。同样,请参阅Crypto++维基百科。


谢谢!是的,我想使用“cipher”以加密形式保存AES密钥,但是通过您的第一个示例和FileSink,我不再需要它了!现在我正在尝试添加解密部分,也就是说从“sessionkey.enc”中读取密钥,使用私钥进行解密,然后比较原始密钥和解密后的密钥以检查整个过程是否正确。读取和解密密钥,是这样正确吗? CryptoPP::StringSource(readed_key, true, new CryptoPP::PK_DecryptorFilter(rng, decryptor, new CryptoPP::FileSource("sessionkey.enc")));,还是我需要使用除FileSource之外的其他内容? - EinderJam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接