【发布时间】:2019-05-03 02:30:05
【问题描述】:
警告 以下内容不作为将密码转换为 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 公钥/私钥对。看起来情况可能并非如此。
替代方法是使用PBKDF2 到deriveBits,可用于手动创建ECDH 密钥对。如果这确实是唯一的选择,将随机位转换为公钥/私钥的常用算法是什么(即参考和公共实现)?如果我必须开发一些东西,我可能会在此处发布兴趣和评论。
编辑:用例的其他详细信息
使用 PBKDF 是为了避免在给定(私有)d 参数时必须生成 ECDH 密钥对的公钥(x 和 y)。 x 和 y 是派生的,因此不需要存储,而且我们的数据存储非常有限——仅适用于私钥,例如192 位,或多或少(PBKDF 也可以平滑位大小,但这是一个问题)。
如果 WebCrypto 在给定(伪)随机 d 参数时计算了 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) 密钥。我希望计算椭圆曲线的x 和y 的功能已经存在于WebCrypto 中,可以通过PBKDF2 deriveKey 获得。
在 Javascript 中自己动手的替代方法是解析 JWK/Base64(URL 变体),然后使用带模运算的大整数函数(例如 Fermat 小定理),最后编写椭圆曲线点加法的函数,加倍和乘法。这就是我所做的 (ECC math here)。但我希望这一切都是不必要的,因为 WebCrypto 中存在执行此操作的代码,我只是希望使用 importKey 或 deriveKey 来使用它。
重申一下:没有用户生成的密码;使用这种方法生成 ECDH 密钥被认为是不明智的。
【问题讨论】:
标签: javascript cryptography diffie-hellman