如何使用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);
}
我正在获取使用 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);
}