【问题标题】:Encrypt a symmetric AES key with RSA in Crypto++在 Crypto++ 中使用 RSA 加密对称 AES 密钥
【发布时间】:2018-01-09 21:03:38
【问题描述】:

我正在尝试在两个部分之间交换 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++ wiki 例子)

然后我开始加密例程:

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

CryptoPP::RSAES_OAEP_SHA_Encryptor e(publicKey);

我不知道该用哪一个:CryptoPP:: ArraySourceCryptoPP::StringSource

【问题讨论】:

  • 嗯,AES 密钥由字节/位组成,所以ArraySource 应该更合乎逻辑。密钥的加密也称为密钥包装,但在 Internet 上快速搜索不会显示任何直接结果。由于 Crypto++ 是一个软件库,因此在加密字节或密钥方面几乎没有区别,因此这可以解释缺少的示例代码。

标签: c++ encryption cryptography crypto++


【解决方案1】:

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

在此之后,为 RSA 加密器使用 PK_EncryptorFilter;并使用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)));

您也可以使用ByteQueueRedirector 打破了所有权链。另请参阅 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++ wiki 上的 Pipelines 感兴趣。您在上面看到的东西是管道中使用的源、过滤器和接收器。


如果它应该保存加密的对称密钥,那么它太小了:

SecByteBlock cipher(AES::MAX_KEYLENGTH);

查看 Crypto++ wiki 上的 RSA Encryption Schemescipher 需要为 encryptor.CiphertextLength(AES::MAX_KEYLENGTH);,这大致是 RSA 模数的大小减去 OAEP 格式化和填充的大约 50 个字节。


(comment) > 现在我正在尝试添加部分以使用私钥对其进行解密...这是正确的吗?

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)));

(comment) > ...再对比原文...

您可以在几乎恒定的时间内将两个字节缓冲区与VerifyBufsEqual 进行比较。再次,请参阅 Crypto++ wiki。

【讨论】:

  • 谢谢!是的,我想使用“密码”以加密形式保存 aes 密钥,但是对于您的第一个示例和 FileSink,我不再需要它了!我现在正在尝试添加解密部分,即从“sessionkey.enc”中读取密钥,使用私钥对其进行解密,然后将原始密钥和解密密钥进行比较以检查所有过程是否正确。读取和解密密钥,正确吗? ` CryptoPP::StringSource(readed_key, true, new CryptoPP::PK_DecryptorFilter(rng, decryptor, new CryptoPP::FileSource("sessionkey.enc")));` 或者我需要使用 FileSource 以外的其他东西吗?跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-13
  • 1970-01-01
相关资源
最近更新 更多