【问题标题】:RandomNumberGenerator requirement during RSA encryption and decryption?RSA加密和解密期间的RandomNumberGenerator要求?
【发布时间】:2017-06-21 15:43:41
【问题描述】:

我正在尝试使用公钥加密消息,并在 shell 中使用 crypto++ 使用私钥解密密码:

openssl rsautl -encrypt -inkey id_rsa.pub.pem -pubin -in message -out message.enc

openssl rsautl -decrypt -inkey id_rsa.pem -in message.enc -out message.dec

加密/解密在单独的应用程序中完成。我从https://www.cryptopp.com/wiki/RSA_Cryptography 的示例开始。 我的代码:

std::string publicEncrypt(std::string const& plain) {
    auto cipher = std::string{};
    CryptoPP::RSAES_OAEP_SHA_Encryptor e(getPublicKey());
    CryptoPP::StringSource(plain, true,
        new CryptoPP::PK_EncryptorFilter(CryptoPP::NullRNG(), e,
                new CryptoPP::StringSink(cipher)));
   return cipher;
}

std::string privateDecrypt(std::string const& cipher) {
    auto decrypted = std::string{};
    CryptoPP::RSAES_OAEP_SHA_Decryptor d(getPrivateKey());
    CryptoPP::StringSource(cipher, true,
        new CryptoPP::PK_DecryptorFilter(CryptoPP::NullRNG(), d,
                new CryptoPP::StringSink(decrypted)));
    return decrypted;
}

我的问题:

  1. 为什么 EncryptorFilter/DecryptorFilter 需要随机数生成器 (RNG)?
  2. RNG 必须与加密/解密相同,对吧?那么,进程之间如何共享呢?

按照https://stackoverflow.com/users/608639/jww in Unable to do RSA Encrption/Decryption using Crypto++ (isValidCoding is false) 的建议使用 NullRNG() 会导致

std::exception NullRNG: NullRNG should only be passed to functions that don't need to generate random bytes.

我想我从根本上错过了一些东西。感谢您的提示和建议。

如果我在具有全局 RNG 的单元测试中使用此代码,则一切正常。

【问题讨论】:

  • RNG 是必需的,因为OAEP padding 需要生成随机位串(如果您不使用随机值,例如 NullRNG,您将失去 RSA OAEP 的一些主要安全属性)。我不确定为什么解码需要RNG,因为随机字符串是由算法恢复的,所以不需要生成新的随机位。
  • @puzzlepalace - “我不知道为什么解码需要 RNG,因为随机字符串是由算法恢复的......” - 在私钥操作期间会出现盲点。
  • 是的,就是这样,很好。

标签: c++ rsa public-key-encryption crypto++


【解决方案1】:

为什么 EncryptorFilter/DecryptorFilter 需要随机数生成器 (RNG)?

签名和验证类是cryptlib.h 中设置的抽象接口。一些密码系统使用它们,而另一些则不使用。一个类将专门化并且可以放弃使用生成器。有时,一个类不需要生成器来执行其中一个操作。 NullRNG如果不需要可以使用。

RSA 在公钥操作期间需要 RNG 的原因是消息填充。填充通常是消息格式化功能的一部分。正如@PuzzlePalace 指出的那样,OAEP 填充是随机的而不是确定性的。

RSA 在私钥操作期间需要 RNG 的原因是盲目的。对于 RSA 和其他类似 RSA 的方案(如 Rabin-Williams),盲法只是乘以随机值,以掩盖私钥的反转以恢复原始值。稍后,在签名或解密之后,将致盲值移除,并保留操作结果。

相关,DSA 或 ECDSA不需要在私钥操作期间需要 RNG 的原因是 RFC 6979, Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)。确定性签名不使用随机格式或随机k

公钥和私钥操作需要 RNG 的另一个原因是对密钥的验证检查。例如,可能会检查一个键以确保特定约束成立,例如它的素数或它具有特定的 Jacobi 符号。


加密/解密的 RNG 必须相同,对吗?那么,进程之间如何共享呢?

不,生成器可以不同。唯一的要求是它们产生一个随机流,以合理定义“随机”的含义。没有分裂太多的头发,这意味着生成器产生了一个均匀的分布。

您可以在 wiki 上的 RandomNumberGenerator 上找到有关 Crypto++ 生成器的更多信息。


如果我在具有全局 RNG 的单元测试中使用此代码,则一切正常。

请注意...GlobalRNGTest 命名空间的一部分。定义在test.cpp : 115:

NAMESPACE_BEGIN(CryptoPP)
NAMESPACE_BEGIN(Test)

ANONYMOUS_NAMESPACE_BEGIN
OFB_Mode<AES>::Encryption s_globalRNG;
NAMESPACE_END

RandomNumberGenerator & GlobalRNG()
{
    return dynamic_cast<RandomNumberGenerator&>(s_globalRNG);
}

NAMESPACE_END  // Test
NAMESPACE_END  // CryptoPP

GlobalRNG 是一个确定性生成器,它不是库的一部分。如果您依赖它,您的代码将无法在该字段中编译。

使用 wiki 上RandomNumberGenerator 讨论的其他生成器之一。 AutoSeededRandomPool 是个不错的选择。


按照 https://stackoverflow.com/users/608639/jww 在 Unable to RSA 中的建议使用 NullRNG() 使用 Crypto++ 加密/解密(isValidCoding 为假)导致

std::exception NullRNG: NullRNG should only be passed to functions that don't need to generate random bytes.

该信息不正确。我需要修复它。谢谢。


有趣的是(以一种病态的方式),由于拉宾-威廉姆斯的失明,Crypto++ 采用了CVE-2015-2141。致盲值需要是二次残差;否则攻击者可以准备特殊消息来泄露私钥。

Evgeny Sidorov 的论文全文可通过Breaking the Rabin-Williams digital signature system implementation in the Crypto++ library 获取。以下是修复 Sidorov 攻击后新改进的反函数的样子(来自rw.cpp):

ModularArithmetic modn(m_n), modp(m_p), modq(m_q);
Integer r, rInv;

do
{
    // Do this in a loop for people using small numbers for testing
    r.Randomize(rng, Integer::One(), m_n - Integer::One());
    // Fix for CVE-2015-2141. Thanks to Evgeny Sidorov for reporting.
    // Squaring to satisfy Jacobi requirements suggested by Jean-Pierre Munch.
    r = modn.Square(r);
    rInv = modn.MultiplicativeInverse(r);
} while (rInv.IsZero());

如果您阅读 Sidorov 论文的第 6 节,他建议生成一个随机的 r,然后检查 r 的 Jacobi 符号以确保它是二次余数。如果不是 QR,请尝试新的随机 r。分流使用了该方法,但它表明该方案大大减慢了速度,因为随机的r 以 1/16 的概率满足条件。

但是,我们知道平方 r 确保我们在第一次尝试时满足 Jacobi,因为 r2 mod n 始终是二次余数。平方/乘法只需要log (exp)(而不是n log (n)),因此它比试错法显着加快了速度。在我们发布下一个版本的库之前,我们切换到了平方方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-27
    • 2014-04-19
    • 2018-09-18
    • 1970-01-01
    • 1970-01-01
    • 2014-04-13
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多