使用 Web Crypto 从 Java 中导出随机 RSA 公钥并将其导入到 Java 脚本中

Exporting a random RSA PublicKey from Java and importing it in JavaScript using Web Crypto

我能够将字节数组从 Java 服务器传输到 JavaScript 服务器(作为 Int32Array 接收)。有了这个,我希望能够传输在 Java 中生成的 PublicKey 并在 JavaScript.

中将其作为 CryptoKey 接收

RSA Public 密钥在 Java 中生成,如下所示:

SecureRandom sr = new SecureRandom();
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048, sr);
KeyPair kp = generator.generateKeyPair();
PublicKey pKey = kp.getPublic();

我尝试的是使用 Key#getEncoded() 将 public 键作为字节数组获取,使用 aformenetioned 方法将其传输到 JavaScript,然后将其导入所以:

const subtle = window.crypto.subtle;
await subtle.importKey("spki", array, { name: "RSA-OAEP", hash: "SHA-256" }, false, [ "encrypt" ])

其中“array”是从 Java 服务器接收到的 Int32Array。但是,这不起作用,而且我总是收到一个非描述性 DOMException,指出“提供给操作的数据不符合要求”。我做了明显的故障排除,检查发送前后数组是否相同,将 TypedArray 转换为 ArrayBuffer,在 base64 中编码和解码作为字节完整性检查,并尝试不同的算法但无济于事。

部分资源:

这是发送前 Java 报告的示例 key#getEncoded() 字节数组(发送后是具有相同内容的 Int32Array([...]))

[48, -126, 1, 32, 48, 11, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 10, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -44, -97, 125, 40, -104, -77, -56, 30, 64, -51, -44, 35, -91, 83, 43, -92, 1, 104, -7, -71, 61, -111, 74, -17, -43, 96, 47, 5, 71, 57, -23, -80, 12, 23, -89, -5, 18, 56, 32, -125, -48, 115, -126, 45, 71, 73, -53, -68, -104, -95, 18, -76, 21, 22, 122, 26, -89, -128, -118, 99, -65, 89, -81, -120, 72, -85, 20, 44, -119, -38, 4, -1, -69, -105, -70, -52, 126, 58, 86, -9, 4, -55, 104, -81, 21, -91, -128, -101, -82, -15, -1, -4, -13, -116, 48, -91, -60, 81, 111, 53, 126, 91, -46, 16, -5, -99, 73, -40, -99, -24, -46, -75, -99, 48, -67, 92, -92, -78, -115, 76, -35, -51, 75, -56, 70, 56, -10, 13, -108, 56, 79, 34, -22, -123, -91, -12, 9, -21, -32, 22, -88, -79, -13, -35, 61, 24, -115, -93, 40, 46, -88, 5, -105, -69, 82, -57, 10, -15, -91, 21, 53, -60, -31, -102, -63, -35, 71, -72, 50, 2, 37, 93, -70, -87, -110, -69, -10, 88, 51, 118, 30, 45, -11, 74, -92, -109, -10, 102, 79, -128, 14, 61, 94, -100, 69, 97, 56, 38, -14, 29, -85, -78, 2, 31, -127, -107, 86, -16, -114, -7, -83, 31, 77, -120, 77, 73, 114, 38, -124, 31, 116, -83, 39, -36, 85, 92, 86, 52, 22, -90, -47, 101, 16, 94, -16, -95, -33, 68, 112, 88, 94, -47, 121, -83, 3, -80, 111, 21, -42, 65, -101, 72, -126, 4, -83, -11, 2, 3, 1, 0, 1]

同样的数据用十六进制表示

30 82 01 20 30 0B 06 09 2A 86 48 86 F7 0D 01 01 0A 03 82 01 0F 00 30 82 01 0A 02 82 01 01 00 D4 9F 7D 28 98 B3 C8 1E 40 CD D4 23 A5 53 2B A4 01 68 F9 B9 3D 91 4A EF D5 60 2F 05 47 39 E9 B0 0C 17 A7 FB 12 38 20 83 D0 73 82 2D 47 49 CB BC 98 A1 12 B4 15 16 7A 1A A7 80 8A 63 BF 59 AF 88 48 AB 14 2C 89 DA 04 FF BB 97 BA CC 7E 3A 56 F7 04 C9 68 AF 15 A5 80 9B AE F1 FF FC F3 8C 30 A5 C4 51 6F 35 7E 5B D2 10 FB 9D 49 D8 9D E8 D2 B5 9D 30 BD 5C A4 B2 8D 4C DD CD 4B C8 46 38 F6 0D 94 38 4F 22 EA 85 A5 F4 09 EB E0 16 A8 B1 F3 DD 3D 18 8D A3 28 2E A8 05 97 BB 52 C7 0A F1 A5 15 35 C4 E1 9A C1 DD 47 B8 32 02 25 5D BA A9 92 BB F6 58 33 76 1E 2D F5 4A A4 93 F6 66 4F 80 0E 3D 5E 9C 45 61 38 26 F2 1D AB B2 02 1F 81 95 56 F0 8E F9 AD 1F 4D 88 4D 49 72 26 84 1F 74 AD 27 DC 55 5C 56 34 16 A6 D1 65 10 5E F0 A1 DF 44 70 58 5E D1 79 AD 03 B0 6F 15 D6 41 9B 48 82 04 AD F5 02 03 01 00 01

感谢任何花时间帮助或回复的人!

首先是一个可行的解决方案:使用Key#getEncoded()生成的DER编码的X.509/SPKI密钥经过Base64编码,然后导入到JavaScript端,如下所示:

(async () => {
    const subtle = window.crypto.subtle;
    var keyAB = b642ab("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuuKRgspvg47d4I3pAzCIWKSim2Rs1QeTVE1Hs+P099PkiuMt5dq5GIaIT1DZTYwJrwtUpxnMcr1TNdWGGfovDLJuIRXUFeST1xOD9+rA4FhVZPO/x6ts2TYKiueEq/qPlXREXw8aVq+msw0nYhHFIAAyrtmj7UR6gD3xxl1ghviIycKqUf7rL98b1d6YkYoNW62aIP/u3cJ5v3Fhnth02Cb02M/fX5gvFKJ3Nj2ARbLygZWbO3U09Vs/hnElxE2k1sKxYRqImJdQM04oQOXVVpafZP7eF9/T+YYDxMLcEKAwH9z0fTt9HaL4gyiDWUT02r6qWF7vI85I1jrPLn71mQIDAQAB")

    var key = await subtle.importKey("spki", new Uint8Array(keyAB), { name: "RSA-OAEP", hash: "SHA-256" }, false, [ "encrypt" ])   
    console.log(key)
})();

function b642ab(base64string){
    return Uint8Array.from(atob(base64string), c => c.charCodeAt(0)).buffer;
}

问题是由您使用的 Int32Array 类型引起的。类型化数组是底层 ArrayBuffer 的类似数组的视图。在 Int32Array 中,每个元素对应 4 个字节。
由于您的 Int32Array 包含与 Key#getEncoded() 相同的 值,因此底层ArrayBuffer 包含 4 倍多的值,因此不再对应于原始键。