javascript - 我坚持在 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 中解决这个问题?
解决方案
您在 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
推荐阅读
- java - Spring 数据存储库:列表与流
- python-3.x - 使用 Pandas 读取 excel 文件时如何解决损坏的文件错误
- java - 在 spring 中使用基于 java 的配置而不是 xml 启用绝对排序
- qt - 自定义小部件在 WIdget 窗口中不可见
- java - 在 SpringBoot 应用程序中从缓存中获取时使用 @AutoValue 注释反序列化类
- php - PHP使用for循环插入sql
- datatables - 数据表行重新排序完成,未获得更新的行 ID
- java - 查询以包括 spring 批处理作业参数值以及作业执行数据
- nsattributedstring - 如何在 addAttribute 中更改 NSMutableAttributedString 链接的前景色
- reactjs - React useEffect 进入无限循环