【问题标题】:Exporting a random RSA PublicKey from Java and importing it in JavaScript using Web Crypto从 Java 导出随机 RSA PublicKey 并使用 Web Crypto 将其导入 JavaScript
【发布时间】:2022-01-05 02:57:22
【问题描述】:

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

RSA 公钥是在 Java 中生成的,如下所示:

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

我尝试的是使用 Key#getEncoded() 将公钥作为字节数组获取,使用 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

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

【问题讨论】:

    标签: javascript java websocket rsa webcrypto-api


    【解决方案1】:

    首先是一个可行的解决方案:使用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 倍的值,因此不再对应原来的键。

    【讨论】:

    • 嗯,不完全是。此方法适用于您提供的示例 Base64 字符串,但在从我的 Java 服务器(发布到 toptal.com/developers/hastebin/raw/pijowoxuza)收到的字符串上尝试它,它不起作用。完全相同的“提供给操作的数据不符合要求”错误,没有堆栈跟踪。非常感谢您的帮助!
    • @WasabiThumbs - 问题中发布的代码会生成 X.509/SPKI 格式的公钥。但是,评论链接中发布的密钥是 PKCS#1 格式的公钥,因此实际上无法使用 Java 代码生成!您的问题是否缺少任何相关信息?请注意,WebCrypto 不支持 PKCS#1 格式。因此,您必须直接以 X.509/SPKI 格式生成密钥(例如,使用发布的 Java 代码)或将 PKCS#1 密钥转换为 WebCrypto 支持的格式。
    • 是的,你是对的。自从我的原始帖子试图让它工作以来,我更改了代码。恢复它,然后它工作正常。我的错!非常感谢您的专业知识和帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-12
    • 2018-01-13
    • 1970-01-01
    • 2017-05-14
    • 1970-01-01
    相关资源
    最近更新 更多