警告:以下内容不旨在支持将密码转换为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是为了避免在给定({private} x
参数的情况下必须生成ECDH密钥对的公钥(y
和d
)。 x
和y
是派生的,因此不需要存储,并且我们的数据存储区非常有限-仅适用于私钥,例如或多或少为192位(PBKDF也可以平滑位大小,但这是一个问题)。
如果WebCrypto在给定(伪)随机x
参数时计算了y
和d
,则可以实现/说明所需的结果 ,如下所示:< / p>
>>> 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的Little定理),最后编写用于添加椭圆曲线点的函数,加倍和乘法。这就是我所做的(ECC math here)。但是我希望这一切都是不必要的,因为WebCrypto中存在执行此操作的代码,而我只是希望使用importKey
或deriveKey
来使用它。
只需重申一下:没有用户生成的密码;使用此类生成ECDH密钥被认为是不明智的。
答案 0 :(得分:2)
“微妙”。好人!
在阅读了上面链接中SubtleCrypto的密钥生成说明后,我将其弹出到Chrome的浏览器控制台中,并且工作正常。您可能需要对其进行调整以适合您的情况,尤其是有关keyUsages的部分:
(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);
})();
答案 1 :(得分:2)
布莱恩
不可能使用WebCrypto从密码确定性地创建密钥对。
对不起。
您可以使用Javascript中的密码确定性地创建密钥对,然后导入该密钥对,只要它以正确的表示形式提供secp256r1密钥即可。
那里有一些JavaScript库,它们支持从密码确定性地创建密钥对。对于这些库的正确性或安全性,或者对于secp256r1,我无法发表任何声明。当然,密钥生成是使用加密时要考虑的最重要方面之一,而基于弱的熵源这样做是不好的。
如果尽管导入了给定类型的密钥很简单,但您还是决定继续采用这种方法,请参见:https://github.com/diafygi/webcrypto-examples#ecdsa---importkey
TL; DR,您的里程会因这种方法而异,但有可能。
瑞安
答案 2 :(得分:1)
从更新中我们仍然无法确定用例是什么,我们可以告诉(我认为)您的目标是出于某种原因节省存储空间。 ECC密钥非常小,很难想象用例会是什么样,尤其是在Web应用程序中,这种应用程序需要使用较弱的方法来存储如此少量的存储。也就是说,先前的答案保持不变,无法直接使用webcrypto进行所需的操作。