在 Node.js (PBKDF2WithHmacSHA1) 中重写 Java AES 256 GCM 加密

Rewriting Java AES 256 GCM Encryption in Node.js (PBKDF2WithHmacSHA1)

我在 java 中有以下代码用于加密纯文本:

private static final String SECRET_KEY = "SecKeyTest";
private static final String SALT = "thisIsSalt";



public String encrypt(String strToEncrypt) {
    try {
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        IvParameterSpec ivspec = new IvParameterSpec(iv);

        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
        KeySpec spec = new PBEKeySpec(SECRET_KEY.toCharArray(), SALT.getBytes(), 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKeySpec secretKey = new SecretKeySpec(tmp.getEncoded(), "AES");
        
        GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128 , iv);

        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmParameterSpec);
        return Base64.getEncoder().encodeToString(cipher.doFinal(strToEncrypt.getBytes(StandardCharsets.UTF_8)));
    } catch (Exception e) {
        System.out.println("Error while encrypting: " + e.toString());
    }
    return null;
}

我必须使用 NodeJs 重写相同的内容,到目前为止我所做的:

const salt = "thisIsSalt";
const digest = 'sha256';
const aesSecretKey = "SecKeyTest";

module.exports = {

    encrypt: function (plainText){

        const key = crypto.pbkdf2Sync(aesSecretKey, salt, 65536, 32, digest); //key len 32bytes i.e 256bits
        const iv = Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]);

        // AES 256 GCM Mode
        var cipher = crypto.createCipheriv('aes-256-gcm', key, iv);

        // encrypt the given text
        var encrypted = Buffer.concat([cipher.update(plainText, 'utf8'), cipher.final()]);

        // extract the auth tag
        var tag = cipher.getAuthTag();

        // generate output
        return Buffer.concat([Buffer.from(salt), iv, tag, encrypted]).toString('base64');
        
    }


};

对于输入:“你好”:

Java: rgCx2SDSqio15M+0lViNAzW/lUmz

节点:dGhpc0lzU2FsdAAAAAAAAAAAAAAAAAAAAADSqio15M+0lViNAzW/lUmzrgCx2SA=

Java 代码按此顺序隐式连接密文和标签。因此,要在 NodeJS 代码中获得相同的结果,需要进行以下更改:

return Buffer.concat([encrypted, tag]).toString('base64');

但是salt和IV不应该是静态的,而是应该在每次密钥推导和加密时随机生成。由于解密需要 salt 和 IV,并且两者都不是秘密的,因此它们与密文和标签一起传递,通常也连接在一起,例如:salt |四 |密文 |标签。