如何使用aes-128-cbc算法实现CryptoJS解密?

How to achieve CryptoJS decryption using aes-128-cbc algorithm?

我正在获取使用 Java 生成的加密密钥。我需要使用 CryptoJS 在 AngularJS 应用程序中解密它。我曾使用节点做过类似的事情,但现在在 Angular 中我被卡住了。这个 fiddle http://jsfiddle.net/s5g82rqh/ 是我到目前为止尝试过的,但是它 returns 是空的。

以下是我目前尝试过的方法

 function decrypt_core_AES_CBC(password, ciphertext) {
   var iv  = CryptoJS.lib.WordArray.random(128/8);
   var message = CryptoJS.AES.decrypt(ciphertext, password, { mode:    CryptoJS.mode.CBC, iv: password });

  console.log("The current iv is: " + iv.toString() );
  return CryptoJS.enc.Utf8.stringify(message);
 }


var data = '6615702f2dd672f643fd57623d6362a510a98faf4b1c068fd468b525a5fa5471809852a0f9cb7936ce3d3892c233b8c48ce2608f16ce6fa66005b2d97689fbb4';
var key = '3426D38AB846B62B9C236D288778D997';
var dec = decrypt_core_AES_CBC(key, data);

console.log(dec);

下面是适用于我的 node.js 代码。我在 CryptoJS 中没有成功实现类似的。根据我的理解,加密是作为内置库出现的,哪个节点在其之上有自己的包装器。

var crypto = require('crypto');
var defaultAlgorithm= 'aes-128-cbc';
var defaultFormat= 'hex';
var ivLength= 16;
function decode (data, key, algorithm, format) {

    // Make sure the data is a buffer object
    if (data instanceof Buffer) {
        data = data.toString();
    }

    // Get defaults if needed
    algorithm = algorithm || defaultAlgorithm;
    format = format || defaultFormat;

    ivLength = ivLength * 2;

    // Get the initialization vector
    var iv = new Buffer(data.substring(0, ivLength), 'hex');

    // Remove the iv from the data
    data = data.substring(ivLength);
    var decipher = crypto.createDecipheriv(algorithm, new Buffer(key, 'hex'), iv);
    var decrypted = decipher.update(data, format, 'utf8') + decipher.final('utf8');

    return decrypted;
}

var data ='6615702f2dd672f643fd57623d6362a510a98faf4b1c068fd468b525a5fa5471809852a0f9cb7936ce3d3892c233b8c48ce2608f16ce6fa66005b2d97689fbb4';
var key = '3426D38AB846B62B9C236D288778D997';
var dec = decode(data, key, defaultAlgorithm, defaultFormat);

console.log(dec);

您遇到了三个问题:

  • CryptoJS 支持两种类型的 encryption/decryption:从密码派生的密钥和直接传递的密钥。您想从密钥执行此操作,因此您需要在将十六进制编码的密钥字符串传递给 decrypt() 函数之前将其解析为 CryptoJS 的本机格式:

    key = CryptoJS.enc.Hex.parse(key);
    

    另外,不要混淆密钥和密码。

  • 解密前忘记从密文中切出IV

    var iv = CryptoJS.enc.Hex.parse(ciphertext.slice(0, 32));
    ciphertext = CryptoJS.enc.Hex.parse(ciphertext.slice(32));
    
  • CryptoJS' 需要 CipherParams 对象或 OpenSSL 格式的字符串来解密。由于你只有一个十六进制字符串,所以你必须在使用前解析它并像这样使用它:

    var message = CryptoJS.AES.decrypt({
        ciphertext: ciphertext
    }, key, {
        iv: iv
    });
    

我花了一周的时间才在 Java、PHP 和 Java 脚本中找到 aes-128-cbc 的工作代码。我不得不在各种网站上进行大量搜索。最后,通过多次点击和试用,下面的代码为我解决了。既加密又解密。在 Java 中加密;在 PHP 或 Java 脚本中解密,在 PHP 中加密;在 Java 或 Java 脚本中解密,在 Java 脚本中加密 在 PHP 或 Java 中解密。所有选项都有效

密钥的长度为 16 位字母数字值。使用相同的密钥来加密和解密数据。 IV 是加密时要传递的字母数字的 16 位随机值。

PHP加解密代码:

  function encrypt($key, $iv, $data) {
  
    static $OPENSSL_CIPHER_NAME = "aes-128-cbc"; //Name of OpenSSL Cipher 
    static $CIPHER_KEY_LEN = 16; //128 bits

    if (strlen($key) < $CIPHER_KEY_LEN) {
        $key = str_pad("$key", $CIPHER_KEY_LEN, "0"); //0 pad to len 16
    } else if (strlen($key) > $CIPHER_KEY_LEN) {
        $key = substr($str, 0, $CIPHER_KEY_LEN); //truncate to 16 bytes
    }
    
    $encodedEncryptedData = base64_encode(openssl_encrypt($data, $OPENSSL_CIPHER_NAME, $key, OPENSSL_RAW_DATA, $iv));
    $encodedIV = base64_encode($iv);
    $encryptedPayload = $encodedEncryptedData.":".$encodedIV;
    
    return $encryptedPayload;
}

function decrypt($key, $data) {
    // $key = $request['key'];
    // $data = $request['data'];

     static $OPENSSL_CIPHER_NAME = "aes-128-cbc"; //Name of OpenSSL Cipher 
     static $CIPHER_KEY_LEN = 16; //128 bits

    if (strlen($key) < $CIPHER_KEY_LEN) {
        $key = str_pad("$key", $CIPHER_KEY_LEN, "0"); //0 pad to len 16
    } else if (strlen($key) > $CIPHER_KEY_LEN) {
        $key = substr($str, 0, $CIPHER_KEY_LEN); //truncate to 16 bytes
    }
    
    $parts = explode(':', $data); //Separate Encrypted data from iv.
    $decryptedData = openssl_decrypt(base64_decode($parts[0]), $OPENSSL_CIPHER_NAME, $key, OPENSSL_RAW_DATA, base64_decode($parts[1]));
    
    return $decryptedData;
    }

Java加解密代码

  import android.util.Base64;
  import android.util.Log;

  import javax.crypto.Cipher;
  import javax.crypto.spec.IvParameterSpec;
  import javax.crypto.spec.SecretKeySpec;

public class Java_AES_Cipher {

private static String CIPHER_NAME = "AES/CBC/PKCS5PADDING";
private static int CIPHER_KEY_LEN = 16; //128 bits

/**
 * Encrypt data using AES Cipher (CBC) with 128 bit key
 *
 *
 * @param key  - key to use should be 16 bytes long (128 bits)
 * @param iv - initialization vector
 * @param data - data to encrypt
 * @return encryptedData data in base64 encoding with iv attached at end after a :
 */
public static String encrypt(String key, String iv, String data) {
    try {
        if (key.length() < Java_AES_Cipher.CIPHER_KEY_LEN) {
            int numPad = Java_AES_Cipher.CIPHER_KEY_LEN - key.length();

            for(int i = 0; i < numPad; i++){
                key += "0"; //0 pad to len 16 bytes
            }

        } else if (key.length() > Java_AES_Cipher.CIPHER_KEY_LEN) {
            key = key.substring(0, CIPHER_KEY_LEN); //truncate to 16 bytes
        }


        IvParameterSpec initVector = new IvParameterSpec(iv.getBytes("ISO-8859-1"));
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("ISO-8859-1"), "AES");

        Cipher cipher = Cipher.getInstance(Java_AES_Cipher.CIPHER_NAME);
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, initVector);

        byte[] encryptedData = cipher.doFinal((data.getBytes()));

        String base64_EncryptedData = Base64.encodeToString(encryptedData, Base64.DEFAULT);
        String base64_IV = Base64.encodeToString(iv.getBytes("ISO-8859-1"), Base64.DEFAULT);

        base64_EncryptedData = base64_EncryptedData.replaceAll(System.getProperty("line.separator"), "");
        base64_IV = base64_IV.replaceAll(System.getProperty("line.separator"), "");

        Log.i("Java_AES_Cipher","Encrypted data is "+ base64_EncryptedData + ":" + base64_IV);

        return base64_EncryptedData + ":" + base64_IV;

    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return null;
}

/**
 * Decrypt data using AES Cipher (CBC) with 128 bit key
 *
 * @param key - key to use should be 16 bytes long (128 bits)
 * @param data - encrypted data with iv at the end separate by :
 * @return decrypted data string
 */

public static String decrypt(String key, String data) {
    try {

        if (key.length() < Java_AES_Cipher.CIPHER_KEY_LEN) {
            int numPad = Java_AES_Cipher.CIPHER_KEY_LEN - key.length();

            for(int i = 0; i < numPad; i++){
                key += "0"; //0 pad to len 16 bytes
            }

        } else if (key.length() > Java_AES_Cipher.CIPHER_KEY_LEN) {
            key = key.substring(0, CIPHER_KEY_LEN); //truncate to 16 bytes
        }

        String[] parts = data.split(":");

        if (parts.length<2)
        {
            Log.i("Java_AES_Cipher","Length "+ parts.length);
            return data;
        }

        IvParameterSpec iv = new IvParameterSpec(Base64.decode(parts[1], Base64.DEFAULT));
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("ISO-8859-1"), "AES");

        Cipher cipher = Cipher.getInstance(Java_AES_Cipher.CIPHER_NAME);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

        byte[] decodedEncryptedData = Base64.decode(parts[0], Base64.DEFAULT);

        byte[] original = cipher.doFinal(decodedEncryptedData);

        return new String(original);
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    return null;
}

Java加解密脚本代码

   <script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.9-1/crypto-js.js"></script>


  function encrypt (messageText,key, iv){
    var message = messageText;
    var key = CryptoJS.enc.Utf8.parse(key);
    var iv  = CryptoJS.enc.Utf8.parse(iv);

var encrypted = CryptoJS.AES.encrypt(
    message,key,
    {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    }
);
this.encrypted = CryptoJS.enc.Base64.stringify(encrypted.ciphertext);
console.log('encrypted:'+encrypted);
return encrypted;
   }


  function decrypt(keyBase64, messagebase64) {
        const digest = messagebase64.split(':');

        const crypttext = CryptoJS.enc.Base64.parse(digest[0])
        const ivBase64 = CryptoJS.enc.Base64.parse(digest[1])

        const decrypted = CryptoJS.AES.decrypt(
            {
            ciphertext: crypttext
            },
            CryptoJS.enc.Utf8.parse(keyBase64),
            {
            iv: ivBase64,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
            }
        );
        console.log('decrypted: '+decrypted.toString(CryptoJS.enc.Utf8));
        return decrypted.toString(CryptoJS.enc.Utf8);
}