首页 > 解决方案 > 我坚持在 javascript 中进行 AES 加密,然后在 JAVA spring 中解密

问题描述

我在将 c#' AES 逻辑转换为 javascript 前端和 java spring 后端时遇到问题。

目的是同时使用 C#、Javascript 和 Java。

我需要遵循当前正在使用的 c#'s AES Logic,然后像 C# AES Logic 一样行事。

我已经为 C# 和 Java AES Logic 完成了相同的加密和解密。

所以剩下的只是Javascript AES Logic。

首先,下面是 javascript 逻辑,稍后将使用密码编码。

// Javascript code in angular
import * as CryptoJS from 'crypto-js';
ngOnInit() {
    const message = '123456';
    console.log('original: ' + message);
    const cipherData = this.encrypt(message);
    console.log('cipherData: ' + cipherData);
    const decData = this.decrypt(cipherData);
    console.log('decData1: ' + decData);
    const decData2 = this.decrypt('maCLeNHh+u3A3pi0S31klRQ==');
    console.log('decData2: ' + decData2);
    const decData3 = this.decrypt('ssxlu1wcvG9lBxi3qDxUaOg==');
    console.log('decData3: ' + decData3);
    console.log('============');
    console.log('ssxlu1wcvG9lBxi3qDxUaOg==');
    console.log('MeM+72EBZ1WtB+RMmh1aL0g==');
    const db1 = this.decrypt('MeM+72EBZ1WtB+RMmh1aL0g==');
    if (db1.length > 0) {
      alert('sucess!');
    }
    console.log('db1: ' + db1);
  }

  encrypt(message: string) {
    const AES_CRYPT_KEY = '1234567890abcdefghijklmnopqrstu';
    const charRandom = this.utils.getRandomValue(1);

    let key =  AES_CRYPT_KEY + charRandom;
    // let iv = '0000000000000000';
    let iv  = new Int8Array(16);
    for (let i = 0; i < iv.length; i++) {
      iv[i] = 0;
    }

    key = CryptoJS.enc.Base64.parse(key);
    iv = CryptoJS.enc.Base64.parse(iv.toString());

    const enc = CryptoJS.AES.encrypt(message, key, {
      iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
     });
    const cipherData = charRandom + enc;
    return cipherData;
  }

  decrypt(message: string) {
    const AES_CRYPT_KEY = '1234567890abcdefghijklmnopqrstu';
    const charRandom = message.charAt(0);

    let key = AES_CRYPT_KEY + charRandom;
    // let iv = '0000000000000000';
    let iv  = new Int8Array(16);
    for (let i = 0; i < iv.length; i++) {
      iv[i] = 0;
    }

    key = CryptoJS.enc.Base64.parse(key);
    iv = CryptoJS.enc.Base64.parse(iv.toString());

    const decString = message.substring(1);
    const dec = CryptoJS.AES.decrypt(decString, key, {
      iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
    }).toString(CryptoJS.enc.Utf8);
    return dec;
  }

输出如下。

db1的加密数据是c#用简单密码'123456'制作的真实数据。

db1 解密后什么都没有。

db1 加密数据由 C# AES Logic 使用,javascript 必须像 C# 和 Java 一样加密和解密。

original: 123456
cipherData: ghzSXfMUvMtXIexsQ/yphJA==
decData1: 123456
decData2: 123456
decData3: 123456
============
ssxlu1wcvG9lBxi3qDxUaOg==
MeM+72EBZ1WtB+RMmh1aL0g==
db1: 

以下是后端的 Java 代码。

// AES256Cipher.java
public class AES256Cipher {

    private static final String AES_CRYPT_KEY = "1234567890abcdefghijklmnopqrstu"; // 32bit

    public String AES_Encode(String str)
            throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        String charRandom = RandomStringUtils.randomAlphabetic(1);
        String secretKey = AES_CRYPT_KEY + charRandom;
        byte[] keyData = secretKey.getBytes();

        SecretKey secureKey = new SecretKeySpec(keyData, "AES");
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");
        c.init(Cipher.ENCRYPT_MODE, secureKey, new IvParameterSpec(IV));

        byte[] encrypted = c.doFinal(str.getBytes("UTF-8"));
        String enStr = charRandom + new String(Base64.encodeBase64(encrypted));

        return enStr;
    }

    public String AES_Decode(String str)
            throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
        byte[] IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        String charRandom = String.valueOf(str.charAt(0));
        String secretKey = AES_CRYPT_KEY + charRandom;
        str = str.substring(1);

        byte[] keyData = secretKey.getBytes();
        SecretKey secureKey = new SecretKeySpec(keyData, "AES");
        Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding");

        c.init(Cipher.DECRYPT_MODE, secureKey, new IvParameterSpec(IV));
        byte[] byteStr = Base64.decodeBase64(str.getBytes());

        return new String(c.doFinal(byteStr), "UTF-8");
    }
}

// AES256Cipher.java
public class CryptoTest {

    public static void main(String[] args) throws UnsupportedEncodingException, NoSuchAlgorithmException, GeneralSecurityException {
        AES256Cipher a256 = new AES256Cipher();

        String original = "123456";
        System.out.println(original);

        String enc = a256.AES_Encode(original);
        System.out.println(enc);

        String dec = a256.AES_Decode(enc);
        System.out.println("result1 " + dec);
        String dec2 = a256.AES_Decode("HtH2FwgxvXtPooDM5PPFRVg==");
        System.out.println("result2 " + dec2);
        String dec3 = a256.AES_Decode("p0ODGY9kHu4ttsryh2vW2Sw==");
        System.out.println("result3 " + dec3);

        System.out.println("=====================");
        String db1 = a256.AES_Decode("MeM+72EBZ1WtB+RMmh1aL0g==");
        System.out.println("db1 " + db1);

        System.out.println("=====================");
        String test1 = a256.AES_Decode("ssxlu1wcvG9lBxi3qDxUaOg==");
        System.out.println("test1 " + test1);
    }
}

输出如下。Java逻辑可以解密之前用C#制作的db真实加密密码

123456
fZYLxfQxDHIxdSZdSbVH2Hg==
result1 123456
result2 123456
result3 123456
=====================
db1 123456
=====================
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
    at com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
    at com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
    at javax.crypto.Cipher.doFinal(Cipher.java:2164)
    at com.neoslon.base.common.AES256Cipher.AES_Decode(AES256Cipher.java:72)
    at CryptoTest.main(CryptoTest.java:30)

当我尝试在 Java 上解密 javascript 的加密时,出现错误Exception in thread "**main" javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption**.

我认为javascript中的iv是根本案例。

我试过let iv = '0000000000000000'; 让iv = '0 0 0 0 0 0 0 0 0 0 0 0 0 0 00'; 等等...

如何在 javascript 而不是 Java 中解决这个问题?

标签: javascriptjavaaes

解决方案


您在 JavaScript (CryptoJS.pad.Pkcs7) 中使用了 PKCS7 填充,但希望在 Java 代码中使用 PKCS5 填充 (AES/CBC/PKCS5Padding)。

所以异常消息“javax.crypto.BadPaddingException:给定最终块未正确填充”。是可以预料的。

这两个填充支持不同的块大小: https ://crypto.stackexchange.com/questions/9043/what-is-the-difference-between-pkcs5-padding-and-pkcs7-padding


推荐阅读