Java 和打字稿生成差异 PBKDF2 哈希

mah*_*454 5 javascript java typescript angular java-11

我想使用加密的 AES-GCM 数据(用于密码的 PBKDF2 哈希)在 java 和 typescript 之间进行通信。
我为 pbkdf2 使用了随机字节:

randomBytes(Base64): wqzowTahVBaxuxcN8vKAEUBEo0wOfcg4e6u4M9tPDFk=   
Run Code Online (Sandbox Code Playgroud)

这是我的 java PBKDF2 代码:

    private String salt = "1234";
    private static final String KEY_ALGORITHM = "AES";
    private Key generateKey(byte[] randomBytes) throws Exception {
        var randomPassword = new String(randomBytes);
        KeySpec keySpec = new PBEKeySpec(randomPassword.toCharArray(), salt.getBytes(), 10000, 256);
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        var kdf2SecurePassword = secretKeyFactory.generateSecret(keySpec).getEncoded();
        return new SecretKeySpec(kdf2SecurePassword, KEY_ALGORITHM);
    }   
Run Code Online (Sandbox Code Playgroud)

这是打字稿代码:

  private static importKey(randomBytes: ArrayBuffer) {
    return crypto.subtle.importKey(
      'raw',
      randomBytes,
      {name: 'PBKDF2', length: 256},
      true,
      ['deriveKey']
    );
  }

  private generateAESKey(baseKey, salt) {
    const encSalt = new TextEncoder().encode(salt);
    const algorithm = {
      name: 'PBKDF2',
      hash: 'SHA-256',
      iterations: 10000,
      salt: encSalt
    };
    return crypto.subtle.deriveKey(
      algorithm,
      baseKey,
      {name: 'AES-GCM', length: 256},
      true,
      ['encrypt', 'decrypt']
    );
  }     
Run Code Online (Sandbox Code Playgroud)

结果在 java 和 typescript :

Java Key       : hrG2Hw/bec9JoI+EcemfUxR/5lGw718kYOcCWRRbulk=
typescript Key : EGPcTUQUmYpNHoCDuD7rkIVaHkPSqEZYan4HnWfhFSc=     
Run Code Online (Sandbox Code Playgroud)

为什么我有不同的结果?
代码的哪一部分有问题?

更新
有趣,我尝试使用 linuxnettle-pbkdf2命令生成 pbkdf2 密钥,结果与 javascript 输出完全匹配:

USERNAME@HOSTNAME:~$ echo -n "wqzowTahVBaxuxcN8vKAEUBEo0wOfcg4e6u4M9tPDFk=" | base64 -d | nettle-pbkdf2 -i 10000 -l 32 --raw "1234"  | base64
EGPcTUQUmYpNHoCDuD7rkIVaHkPSqEZYan4HnWfhFSc=    
Run Code Online (Sandbox Code Playgroud)

mah*_*454 1

经过在互联网上的大量研究并比较了 3 种编程语言(Java、Javascript、Python)和 linu nettle-pbkdf2 命令。
我注意到 Java JCE 和 Bouncycastle 在 PBKDF2 算法实现中存在错误。

这是Python示例代码:

#!/usr/bin/python3
import base64
import hashlib

b64 = "wqzowTahVBaxuxcN8vKAEUBEo0wOfcg4e6u4M9tPDFk="
bytePass = base64.b64decode(b64)
key = hashlib.pbkdf2_hmac('sha256', bytePass, '1234'.encode(), 10000, 32)
keyB64 = base64.b64encode(key)
print(keyB64)      
Run Code Online (Sandbox Code Playgroud)

javascript 和 linux nettle-pbkdf2 命令的结果相同:

EGPcTUQUmYpNHoCDuD7rkIVaHkPSqEZYan4HnWfhFSc=      
Run Code Online (Sandbox Code Playgroud)

在java中,当我将randomBytes更改为简单的字符串时Password123456,结果是javajavascriptpython是类似的。

Java       : nCpOvPbsb62/jfYIlPClEEGNzpD7Wt/qwkIC00Rkx24=
JavaScript : nCpOvPbsb62/jfYIlPClEEGNzpD7Wt/qwkIC00Rkx24= 
Python     : nCpOvPbsb62/jfYIlPClEEGNzpD7Wt/qwkIC00Rkx24= 
Run Code Online (Sandbox Code Playgroud)

注意:实际上我的示例代码中的 randomBits 是 ECDH 共享秘密。我认为Java无法计算PBKDF2上的某些位或实现有问题。

无论如何,我从PBKDF2迁移到Argon2

更新
此 PBKDF2 源代码在 java 中工作没有任何问题:PBKDF2 源代码