在Chromium中用WebCrypto生成RSA密钥对。

问题描述 投票:1回答:1

以下代码在Firefox 76.0.1中工作。

"use strict"
let RSAKeys
(async () => {
  RSAKeys = await crypto.subtle.generateKey({
      name: "RSA-OAEP",
      modulusLength: 3072,
      publicExponent: new Uint8Array([1, 0, 1]),
      hash: "SHA-256"},
    true,
// Chromium bug causes it to falsely complain that the array is empty. Sometimes adding "encrypt" helps.
    ["wrapKey"])
})()

但在Chromium 80中,我得到:

Uncaught (in promise) DOMException: 当创建一个键时,Usages不能为空。

["wrapKey"] 显然不是一个空数组,所以这似乎是一个浏览器的错误。可能是 这个. 你能确认吗?更重要的是,你知道有什么变通方法吗?(添加 encrypt 的用法有帮助,但只是第一次,然后就出现了同样的错误)。) 它必须是一个支持封装密钥的非对称密码。根据表中的 规范的相关章节,RSA-OAEP是唯一的可能。

google-chrome rsa chromium webcrypto-api
1个回答
1
投票

我可以重现这个问题 版本85.0.4162.0。关键用法 ["wrapKey"] 产生了发布的错误信息。但我无法重现,添加键的使用方法 加密 (即 ["wrapKey", "encrypt"])解决了这个问题(甚至不是第一次)。然而,如果加上关键用法 拆解键 (即 ["wrapKey", "unwrapKey"])的错误不再发生。

SubtleCrypto.generateKey() 返回一个 CryptoKeyPair 对于 "RSA-OAEP" 包含RSA密钥对。如果你在 火狐 浏览器控制台,在用密钥用途生成的密钥对上 ["wrapKey", "unwrapKey"]可以看出,公钥的密钥用途是 ["wrapKey"] 和私钥的是 ["unwrapKey"]. 这两种方式都是合理的,因为公钥用于封装,私钥用于解包。

enter image description here

但是,如果你看一下 火狐 浏览器控制台,在用密钥用途生成的密钥对上 ["wrapKey"]你可以看到,公钥的用途是不变的。["wrapKey"]而私钥则是 虚空:

enter image description here

所以 通过相应的错误信息(显然是指空密钥用法的私钥)来防止生成没有密钥用法的密钥。与 , 火狐 显然是允许的。

现在是一个 BUG?其实在没有密钥用途的情况下,创建一个密钥意义不大,因为它不能被使用!

火狐浏览器的例子: 如果在Firefox浏览器中执行以下代码,确实生成了密钥对,并且因为密钥的使用而封装了一个密钥。wrapkey 的公钥,但解包失败,出现了一个 InvalidAccessError 如果关键用法 拆解键 的私钥不见了。

var test = async () => {

  try {
      
    var mode = document.querySelector('input[name="keyUsages"]:checked').value;
    var keyUsages = (mode === "wrap") ? ["wrapKey"] : ["wrapKey", "unwrapKey"] 
			  
    // Create RSA key pair
    var RSAKeys = await crypto.subtle.generateKey(
      {name: "RSA-OAEP", modulusLength: 3072, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}},
      true,
      keyUsages);
				
    // Create key to wrap
    var keyToWrap = await window.crypto.subtle.generateKey(
      {name: "AES-GCM", length: 128},
      true,
      ["encrypt", "decrypt"]);
				
    // Wrap key
    var wrappedKey = await window.crypto.subtle.wrapKey(
      "raw",
      keyToWrap,
      RSAKeys.publicKey,
      {name: "RSA-OAEP", hash: {name: "SHA-256"}});
			  
    // Unwrap key
    var unwrappedKey = await window.crypto.subtle.unwrapKey(
      "raw", 	
      wrappedKey, 	
      RSAKeys.privateKey, 
      {name: "RSA-OAEP", modulusLength: 3072, publicExponent: new Uint8Array([0x01, 0x00, 0x01]), hash: {name: "SHA-256"}},
      {name: "AES-GCM", length: 128},
      false, 
      ["encrypt", "decrypt"]); 
				
    document.getElementById("result").innerHTML = "Secret key for " + unwrappedKey.algorithm.name + " unwrapped.";
    console.log(unwrappedKey);
 
    } catch(e) {
      document.getElementById("result").innerHTML = e.name + ": " + e.message;
    }
}
.as-console-wrapper { max-height: 7.0em !important; }
<!DOCTYPE html>
<html>
<body height="200">
    <input type="radio" name="keyUsages" value="wrap" checked="true"> ["wrapKey"] 
    <input type="radio" name="keyUsages" value="wrapUnwrap"> ["wrapKey", "unwrapKey"] 
    <button onclick="test()">Run</button><br/> 
    <p id="result"></p>
</body>
</html>

因此,我不会把它归类为一个错误(但这只是我的观点)。

© www.soinside.com 2019 - 2024. All rights reserved.