Javascript 使用WebCrypto从PBKDF2生成ECDH密钥

Javascript 使用WebCrypto从PBKDF2生成ECDH密钥,javascript,cryptography,diffie-hellman,Javascript,Cryptography,Diffie Hellman,警告以下内容并不表示认可将密码转换为ECDH密钥。从高熵、加密安全的PRNG创建ECDH密钥 我想获取一个秘密并从中生成一个ECDH公钥/私钥 在浏览器中,通常的方法是使用PBKDF2(或其他确定性字节)在WebCrypto中生成ECDH公钥/私钥对 下面的示例代码应该可以做到这一点,但它会在Chrome中引发DOM异常: // Generate a random KDF key. const priv = new Uint8Array(24) crypto.getRandomValues(pr

警告以下内容并不表示认可将密码转换为ECDH密钥。从高熵、加密安全的PRNG创建ECDH密钥

我想获取一个秘密并从中生成一个ECDH公钥/私钥

在浏览器中,通常的方法是使用PBKDF2(或其他确定性字节)在WebCrypto中生成ECDH公钥/私钥对

下面的示例代码应该可以做到这一点,但它会在Chrome中引发DOM异常:

// Generate a random KDF key.
const priv = new Uint8Array(24)
crypto.getRandomValues(priv)
const kdfKey = await crypto.subtle.importKey(
  'raw', priv, { name: 'PBKDF2' }, false, ['deriveKey'])

// Derive the ECDH key.
const salt = new Uint8Array(16)
const iterations = 2000
const hash = { name: 'SHA-512' }
const curve = { name: 'ECDH', namedCurve: 'P-384' }
const usages = ['deriveKey']

crypto.getRandomValues(salt)

const ecdhKey = await crypto.subtle.deriveKey({
  name: 'PBKDF2', salt, iterations, hash
}, kdfKey, curve, true, usages) // throws.
当算法是
AES-GCM
(即当曲线被替换为
{name:'AES-GCM',length:256}
)时,上述方法有效,但其他算法也会抛出异常,因此我怀疑我遗漏了什么。。。微妙的

我希望WebCrypto适合接受随机位并生成ECDH公钥/私钥对。看起来情况可能并非如此

另一种方法是使用可用于手动创建ECDH密钥对的
PBKDF2
deriveBits
。如果这确实是唯一的选择,那么将随机位转换为公钥/私钥(即引用和公共实现)的常用算法是什么?如果我必须开发一些东西,我可能会在这里发布兴趣与评论

编辑:用例的其他详细信息 使用PBKDF是为了避免在给定(私有)
d
参数时必须生成ECDH密钥对的公钥(
x
y
)。
x
y
是派生的,因此不需要存储,而且我们的数据存储非常有限-仅适用于私钥,例如192位左右(PBKDF也可以平滑位大小,但这只是一个旁白)

当给定(伪)随机
d
参数时,如果WebCrypto计算
x
y
,则可获得/说明如下所示的预期结果:

>>> curve = { name: 'ECDH', namedCurve: 'P-256' }
>>> k = await crypto.subtle.generateKey(curve, true, ['deriveKey'])
>>> pri = await crypto.subtle.exportKey('jwk', k.privateKey)
>>> delete pri.x
>>> delete pri.y
>>> k2 = await crypto.subtle.importKey('jwk', pri)
    ^^ errors
在许多示例中,PBKDF用于生成(AES)密钥。我希望通过PBKDF2
deriveKey
可以使用WebCrypto中已有的椭圆曲线计算
x
y
的功能

Javascript中自己动手的替代方法是解析JWK/Base64(URL变体),然后使用带模运算的大整数函数(例如Fermat的小定理),最后编写椭圆曲线点加法、倍增和乘法函数。这就是我所做的()。但我希望这一切都是不必要的,因为WebCrypto中有这样做的代码,我只是希望使用
importKey
deriveKey
来使用它

只是重申一下:没有用户生成的密码;使用这种方法来生成ECDH密钥被认为是不明智的。

“微妙的。”很好

在阅读了上面链接中sublecrypto的密钥生成说明后,我将其放入了Chrome上的浏览器控制台,它运行良好。您可能需要对其进行调整以适应您的情况,尤其是关于关键用法的部分:

(async function() {
    const algo = {
        "name": "RSASSA-PKCS1-v1_5",
        "modulusLength": 256,
        "publicExponent": new Uint8Array([0x01, 0x00, 0x01]),
        "hash": {
            "name": "SHA-256"
        }
    };
    const extractable = true;
    const keyUsages = ["sign","verify"];
    const result = await crypto.subtle.generateKey(algo, extractable, keyUsages);
    console.log(result);
})();
布莱恩

不可能使用WebCrypto从密码确定地创建密钥对

对不起

您可以确定地从Javascript中的密码创建密钥对,然后导入该密钥对,只要它是正确表示形式的secp256r1密钥

有一些javascript库支持从密码确定地创建密钥对。我不能就这些库的正确性或安全性发表任何声明,或者是否有针对secp256r1的库这样做。当然,密钥生成是使用密码时考虑的最重要的方面之一,而基于弱的熵源这样做是不好的。p> 如果您决定继续采用这种方法,尽管导入给定类型的密钥非常简单,请参阅:

TL;DR您的里程数将随此方法而变化,但这是可能的


Ryan

从更新中,我们仍然无法确定用例是什么,我们可以确定(我认为)出于某种原因,您的目标是节省存储空间。ECC密钥非常小,很难想象用例会是什么,特别是在web应用程序中,如此小的存储量需要使用较弱的方法。也就是说,前面的答案是一样的,不可能直接用webcrypto做你想做的事情。

谢谢你的帖子。因此,给定一个秘密(要么
Uint8Array
要么
string
),如何使用给定的函数(重新)生成
ECDH
密钥对?生成随机ECDH密钥很简单,即
微妙。generateKey(curve,false,['deriveKey')
其中
curve
是例如
{name:'ECDH','namedCurve:'P-384'}
,但不清楚如何导入、派生或确定地生成密钥对。非常感谢Ryan。我也这么怀疑,你的建议是我的应急计划。您是否有任何关于标准的参考,说明为什么PBKDF2可以用于创建AES而不是ECDH密钥?通常,您不会发现标准说明为什么某些东西通常不是一个好主意。这就是说,在密钥生成的情况下,您需要一个难以猜测的密钥,这种随机性甚至会影响到ECDH。PBDKF2是一种试图从母猪耳朵中取出一个丝绸钱包的尝试。你从密码中得到的信息熵很差,50k次的PBDKF2迭代总比没有好,但除非输入已经是一个好的密钥,否则它不会给你一个好的密钥。这里有一篇文章链接到一篇关于大脑钱包不安全性的论文-。脑钱包是源自密码短语的ECC密钥(secp256k1)。你可以阅读它来了解为什么这不是推荐的内容。还有一个链接,这里的公认答案很好地解释了你将如何进行基本概念。一旦你做到了,你就可以