简体   繁体   English

Java(Cipher)和JavaScript(crypto-js)之间的加密互操作

[英]Encryption interop between Java (Cipher) & JavaScript (crypto-js)

I've been tasked to fix an interoping encryption algorithm that was working perfectly fine from before but suddenly went haywire for reasons unknown, no one has touched any of the code for both of the languages (Java & JS). 我的任务是修复一种互操作的加密算法,该算法以前一直工作得很好,但是由于未知的原因突然陷入困境,没人碰过两种语言(Java和JS)的任何代码。

I'm not really well verse with cryptography so I don't know what possible solutions to look for or work with. 我对密码学不是很熟悉,所以我不知道寻找或使用哪种可能的解决方案。 The task was basically to have this encryption code on Java translated to JavaScript that would both have a resulting Base64 string that was to be decrypted through Java. 基本上,任务是将Java上的此加密代码转换为JavaScript,这两个代码都将具有通过Java解密的结果Base64字符串。

The following are the code snippets for the encryption being done with Java & JS and decryption process on Java: 以下是使用Java和JS进行加密以及在Java上进行解密过程的代码片段:

Java Encryption 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 Encryption 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 Decryption 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;
}

Currently the results return null on the encrypted string using the JavaScript encryption function when being decrypted so it's probably encrypting correctly (?) I'm not sure what I'm missing or doing wrong here... 当前,当解密时,结果使用JavaScript加密函数在加密的字符串上返回null ,因此它可能正确加密了(?)我不确定在这里丢失或做错了什么...

Seems you are missing IV (initialization vector). 似乎您缺少IV(初始化向量)。

don't really know what an IV is or if it's needed here, the encryption Java code doesn't state it anywhere 真的不知道IV是什么,或者这里是否需要IV,加密的Java代码没有在任何地方声明它

The IV is an initialization vector allowing to reuse a key to encrypt multiple messages (or blocks), please have a look at the CBC block mode as you are using it. IV是一个初始化向量,它允许重用密钥来加密多个消息(或块),请在使用它时查看CBC块模式

I am not sure for JavaScript API, but at least I can give you example in Java. 我不确定使用JavaScript API,但至少可以举一个Java的例子。 As well you can have a look at my blog about crypto examples 您也可以看看我的有关加密货币示例的博客

Java Encryption 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 )  */

For CBC mode the IV must be random. 对于CBC模式,IV必须是随机的。 If you don't specify the IVParameter, it will be generated and you can read it from cipher.getIV(); 如果不指定IVParameter,它将被生成,并且您可以从cipher.getIV();读取它cipher.getIV(); . The IV can be public, it is usually prepended before the ciphertext, as the IV is needed to decrypt the ciphertext itself. IV可以是公共的,通常在密文之前,因为IV需要解密密文本身。

Java Decryption 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());

In this example there's no Mac (message authentication code included), you can have a look at the linked example. 在此示例中,没有Mac(包括消息身份验证代码),您可以查看链接的示例。

For JavaScript you should have a look at the used API, but the principle stays the same (you have to generate, use, pass and provide the IV too somehow). 对于JavaScript,您应该查看所使用的API,但是原理保持不变(您也必须以某种方式生成,使用,传递和提供IV)。 This blog seems to contain be more complete code. 该博客似乎包含更完整的代码。

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
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM