我的任务是修复一个中断加密算法,该算法从以前完全正常工作但由于未知的原因突然变得混乱,没有人接触到这两种语言的任何代码(Java和JS)。
我对密码学的解释并不是很好,所以我不知道寻找或使用哪些可能的解决方案。任务基本上是将Java上的加密代码转换为JavaScript,这两个代码都将产生一个通过Java解密的Base64字符串。
以下是使用Java和JS进行加密的代码片段以及Java上的解密过程:
Java加密
public static String encryptMsg(String message) {
@SuppressLint("GetInstance") Cipher cipher = null;
try {
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] cipherText = cipher.doFinal(message.getBytes(UTF_CHARSET));
return Base64.encodeToString(cipherText, Base64.DEFAULT);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
e.printStackTrace();
} catch (NullPointerException e) {
//Do nothing, nothing to encrypt
}
return null;
}
JavaScript加密
function encryptData(data, key) {
const options = {
mode: Crypto.mode.ECB,
padding: Crypto.pad.Pkcs7
}
const secret = Crypto.enc.Utf8.parse(key)
const encrypted = Crypto.AES.encrypt(data, secret, options)
return encrypted.ciphertext.toString(Crypto.enc.Base64)
}
Java解密
public static String decryptMsg(String base64cipherText) {
@SuppressLint("GetInstance") Cipher cipher = null;
try {
cipher = Cipher.getInstance(TRANSFORMATION);
cipher.init(Cipher.DECRYPT_MODE, secret);
String decryptString = new String(cipher.doFinal(Base64.decode(base64cipherText, Base64.DEFAULT)), UTF_CHARSET);
return decryptString;
} catch (NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException e) {
e.printStackTrace();
} catch (NullPointerException e) {
//Do nothing, nothing to decrypt
}
return null;
}
目前结果在解密时使用JavaScript加密函数在加密字符串上返回null
,因此它可能正确加密(?)我不确定我在这里缺少什么或做错了...
似乎你缺少IV(初始化向量)。
我真的不知道IV是什么,或者在这里需要它,加密Java代码并没有在任何地方说明它
IV是一个初始化向量,允许重用密钥来加密多个消息(或块),请在使用它时查看CBC block mode。
我不确定JavaScript API,但至少我可以用Java给你一个例子。你也可以看看我的blog about crypto examples
Java加密
SecureRandom rnd = new SecureRandom();
byte[] iv = new byte[SYMMETRIC_BLOCK_SIZE / 8];
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
SecretKey symmetricKey = new SecretKeySpec(encryptionParams.getKey(), SYMMETRIC_KEY_ALG);
Cipher cipher = Cipher.getInstance(SYMMETRIC_CIPHER_NAME);
cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivParamSpec);
byte[] encrypted = cipher.doFinal(encryptionParams.getPlaintext());
/* and encoded form can contain form of base64( IV + ciphertext ) */
对于CBC模式,IV必须是随机的。如果您没有指定IVParameter,它将被生成,您可以从cipher.getIV();
中读取它。 IV可以是公共的,它通常在密文之前加上,因为需要IV来解密密文本身。
Java解密
/* if IV is prepended before the ciphertext, it can be fetched as sub-array
of the decoded message */
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance(SYMMETRIC_CIPHER_NAME);
cipher.init(Cipher.DECRYPT_MODE, symmetricKey, ivParamSpec);
byte[] decrypted = cipher.doFinal(encryptionParams.getCiphertext());
在此示例中,没有Mac(包括消息验证代码),您可以查看链接的示例。
对于JavaScript,您应该查看使用过的API,但原则保持不变(您必须以某种方式生成,使用,传递和提供IV)。 This blog似乎包含更完整的代码。
var iv = CryptoJS.lib.WordArray.random(128/8);
var encrypted = CryptoJS.AES.encrypt(msg, key, {
iv: iv,
padding: CryptoJS.pad.Pkcs7,
mode: CryptoJS.mode.CBC
});