【问题标题】:Making RSA keys from a password in PHP在 PHP 中从密码制作 RSA 密钥
【发布时间】:2019-05-13 18:03:45
【问题描述】:

"Making RSA keys from a password in python " 问题中的问题类似,我想使用给定密码重复创建同一对 RSA 密钥。

上面提到的问题有这个代码作为答案:

from Crypto.Protocol.KDF import PBKDF2
from Crypto.PublicKey import RSA

password = "swordfish"   # for testing
salt = "yourAppName"     # replace with random salt if you can store one

master_key = PBKDF2(password, salt, count=10000)  # bigger count = better

def my_rand(n):
    # kluge: use PBKDF2 with count=1 and incrementing salt as deterministic PRNG
    my_rand.counter += 1
    return PBKDF2(master_key, "my_rand:%d" % my_rand.counter, dkLen=n, count=1)

my_rand.counter = 0
RSA_key = RSA.generate(2048, randfunc=my_rand)

我试图像这样在 PHP 中复制这段代码:

$password = "swordfish";
$salt = "yourAppName";

$master_key = hash_pbkdf2("sha256", $password, $salt, 10, 256);

$counter = 0;
function my_rand($n) {
  $counter++;
  return hash_pbkdf2("sha256", $master_key, "my_rand:" . $counter, 10, 256);
}

$RSA_key = openssl_pkey_new(???);

但我现在不知道如何使用自定义随机函数复制 RSA 密钥生成器,因为 PHP openssl_pkey_new 函数和 phpseclib 都没有添加自定义随机函数的选项。

如何从给定的密码重复生成相同的 RSA 密钥对?

【问题讨论】:

  • 根据密码生成密钥对的目的是什么?是出于学习目的还是出于好奇?我问这个问题是因为我真的对用例感兴趣。
  • 我想这样做的目的是因为我想尝试使用 RSA 制作一个加密的聊天应用程序。此聊天应用程序应允许用户使用用户名 + 密码登录,因此需要从中生成密钥,但要以他们可以多次登录的方式。
  • 但是生成密钥对的过程意味着你想要一个以前没有使用过的密钥,这就是生成两个巨大的质数。如果您将非对称密钥用作共享对称密钥,那么它的目的是什么?您正在做的是使用共享密钥来计算加密密钥 - 您的想法很好,但您的执行存在缺陷。您遇到的称为 Diffie-Hellman 密钥交换,但您的过程很糟糕。我建议您在 Google 上搜索我提到的内容(Diffie-Hellman)并重新考虑您的流程。
  • 重申您所追求的 - 从用户名和密码派生加密密钥绝对是错误的方法。如果您正在创建加密聊天应用程序,您应该通过 DH (Diffie-Hellman) 在双方之间协商一个加密密钥,然后双方创建密钥,而无需实际传输密钥。这样,您每次在参与者之间打开新连接时都可以创建新密钥。基于用户名或密码创建一个相同的非对称密钥是不安全的 - 密钥应该是不可猜测的,而在你的情况下 - 它们不是。
  • 对不起,Mjh,但这在结构上没有有缺陷,即使它确实有大量的 usage issuesimplementation issues。所以,是的,它不应该被使用,但出于你所说的其他原因。如果实施,我会改用椭圆曲线密码学,但这基本上用一罐含有成分的蠕虫代替了一罐蠕虫。

标签: php encryption rsa


【解决方案1】:

TL;DR:您不应该从给定的密码生成 RSA 密钥对


看起来 OpenSSL 和 phpseclib 的创建都考虑到了这一点。这并不奇怪,因为有很多话要说against the solution itself。此外,还有很多实现问题,especially for RSA


如果您仍要继续实施这种不明智的方案,那么您应该查找用于密钥生成的 PHP 实现然后将其与您的解决方案一起存储。这样做的原因是,否则随机数生成、素数查找或 RSA 密钥生成方法可能会在内部发生变化(当您升级库时)并生成不同的密钥对。我不会在 Java 上使用此解决方案,即使它确实允许您插入自己的 RNG 以允许 确定性密钥对生成,这是您的技术术语努力去做。

还有其他方法可以让用户保护其私钥的安全,例如基于密码的密钥加密。这需要存储加密的密钥,但至少这是常见的做法,失败的原因要少得多。

如果您想加密任意大小的消息,您将需要某种混合加密技术 - 就像您必须使用任何其他类型的 RSA 密钥对一样,真的。


请注意,椭圆曲线加密的情况稍好一些。您可以将 PBKDF2 与 SHA-256 结合起来创建一个私钥,然后通过执行基点 G 与该私钥值的点乘来导出公钥。这不太可能失败。您可以使用 ECIES 使用椭圆曲线进行加密,因为 EC 无法直接加密消息密钥。


但是,您仍然会遇到永远无法更改密码的问题,并且您必须使用常量盐来始终生成相同的私钥和公钥。因此,我仍然不推荐该方案,因为它允许离线、多目标攻击使用公钥值或密文来查找密码。

为了确保无法找到密码,它需要非常强 - 强到您可能必须将其存储在某个地方。

【讨论】:

    猜你喜欢
    • 2018-05-31
    • 2013-10-30
    • 1970-01-01
    • 1970-01-01
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    • 2012-06-24
    相关资源
    最近更新 更多