Java 和 JavaScript 之间使用 OAEP 的 RSA 加密

And*_*ing 1 javascript java encryption rsa

我试图用 JavaScript 加密一个短字符串并用 Java 解密它。解密失败,我认为这是因为两个平台之间的块模式和/或填充不同。我尝试在Java和JavaScript中加密相同的字符串,得到不同的结果,这表明确实存在差异。这是创建密钥的 Java 代码:

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair keyPair = kpg.generateKeyPair();
Run Code Online (Sandbox Code Playgroud)

这是我用来测试加密的 Java 代码:

Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic());
byte[] bytes = cipher.doFinal("asdf".getBytes());
Run Code Online (Sandbox Code Playgroud)

我将公钥发送到 JavaScript 进程,并将其转换为 ArrayBuffer,变量名为publicKey。我已经验证了 JavaScript 端的密钥与 Java 端的密钥匹配(通过导出它crypto.subtle.exportKey并检查字节)。这是我用来测试加密的 JavaScript 代码:

crypto.subtle.importKey('spki', publicKey,
                        {hash: 'SHA-256', name: 'RSA-OAEP'}, true,
                        ['encrypt'])
      .then((key) => {
        crypto.subtle.encrypt({name: 'RSA-OAEP'}, key,
                              new TextEncoder().encode('asdf'))
              .then((buffer) => {

              });
      });
Run Code Online (Sandbox Code Playgroud)

Java 中的字节数组和 JavaScript 中的数组缓冲区的内容是不一样的。我不确定的设置是Cipher#getInstanceJava 端的参数importKeyencryptJavaScript 端的参数。是否有任何设置可以使用内置类在 Java 和 JavaScript 之间工作?或者我应该查看第三方库(例如,Bouncy Castle)?

Chi*_*hip 6

这是旧的,但如果您想在 javascript 中使用微妙的加密并控制 java 解密,这里有一个替代解决方案。

假设您使用问题中的原始 JS 代码进行加密,以下是您在 Java 中解密的方法:

Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
cipher.init(Cipher.DECRYPT_MODE, privKey, oaepParams);
byte[] decrypted = cipher.doFinal(encryptedBytes)

Run Code Online (Sandbox Code Playgroud)

密码的问题RSA/ECB/OAEPWithSHA-256AndMGF1Padding在于它默认使用 SHA-1 作为 MGF1 填充。Javascript 使用 SHA-256,这会导致不匹配。通过指定 MGF1ParamterSpec,我们可以强制 Java 使用与 Javascript 默认相同的哈希算法。


小智 5

除了@Chip 的回答 - 这确实很有帮助 - 我想添加以下案例:

假设您想在 Javascript (webcrypto) 中使用以下内容进行解密:

window.crypto.subtle.decrypt(
        {
            name: "RSA-OAEP",
            hash: { name: "SHA-512" }
            //label: Uint8Array([...]) //optional
        },
        privateRsaKey, //CryptoKey object containing private RSA key
        encdata //ArrayBuffer containing to be decrypted data
    )
    .catch(function(err){
        console.error(err);
    })

Run Code Online (Sandbox Code Playgroud)

然后你必须使用以下 OAEPParameterSpec 在 Java 中进行加密(反之亦然,但我没有尝试过):

OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-512", "MGF1", 
        new MGF1ParameterSpec("SHA-512"), PSource.PSpecified.DEFAULT);
Run Code Online (Sandbox Code Playgroud)

由于@Chip仅引用了MGF1 Padding I,我认为必须使用

OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-512", "MGF1", 
        new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);
Run Code Online (Sandbox Code Playgroud)

但显然必须将两个哈希函数更改为 SHA-512,如我的第一个 OAEPParameterSpec 代码块中所示。