关于前端AES加密与后台不同的问题。

后台为php,使用opensslaes进行加密,加密结果与http://tool.chacuo.net/cryptaes结果是一致的。

现在的问题是前端使用CryptoJS怎么弄都不一样。要么与后台加密的数据不一致,要么CryptoJS加的密不能用CryptoJS来解密。

问题出在哪里呢,如果大家有更好的方案麻烦一并写出。太苦恼了。

php代码:

$data = '1000001';
$key = 'ABC123';
$iv = '1111111111111111';

// 结果是:2oXkUjqbc1JnSpWEemVfzg==
// 结果和http://tool.chacuo.net/cryptaes一致
$encrypt_string = openssl_encrypt($data, 'AES-128-CBC', $key, 1,  $iv);

js代码,前提引入了CryptoJS:

//十六位十六进制数作为秘钥
var aeskey = CryptoJS.enc.Utf8.parse("ABC123");
//十六位十六进制数作为秘钥偏移量
var aesiv = CryptoJS.enc.Utf8.parse(1111111111111111);

// 加密
function encrypt(data) {
    var srcs = CryptoJS.enc.Utf8.parse(data);
    var encrypted = CryptoJS.AES.encrypt(srcs, aeskey, {
        iv: aesiv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    //返回base64加密结果
    return encrypted.toString();
}

//解密
function decrypt(data) {
    // data是base64编码数据
    var decrypt = CryptoJS.AES.decrypt(data, aeskey, {
        iv: aesiv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    var decryptedStr = decrypt.toString();
    return decryptedStr;
}

// 结果是:IkNtZY1m41sEkgIqsuZBoQ==
// 结果相差太大
console.log(encrypt('1000001'));
阅读 7.6k
4 个回答

前后端代码都贴出来

我看了CryptoJS的文档:
CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key.
就是说他的加密算法是根据你的key的长度自动选择,所以你首先要固定key的长度:

/**
 * 密码 `\x00` 填充
 * @param {string} key     密码
 * @param {Number} keySize 填充长度, 值: 128, 256
 */
function fillKey(key, keySize) {
    keySize = keySize || 128;
    var filledKey = Buffer.alloc(keySize / 8);
    var keys = Buffer.from(key);
    if (keys.length < filledKey.length) {
        for (var i = 0; i < filledKey.length; i++) {
            filledKey[i] = keys[i];
        }
    }

    return filledKey;
}

然后重设置你的key:

//十六位十六进制数作为秘钥
var aeskey = CryptoJS.lib.WordArray.create(fillKey("ABC123", 128));

我测试了一下,加密现在是对上了,但是解密不是很对,看源代码发现应该是toString的处理问题:

//解密
function decrypt(data) {
    // data是base64编码数据
    var decrypt = CryptoJS.AES.decrypt(data, aeskey, {
        iv: aesiv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    
    return decrypt.toString(CryptoJS.enc.Utf8);
}

好了,现在没有问题了
PS:个人建议加密的方法里去掉var srcs = CryptoJS.enc.Utf8.parse(data);
虽然没出问题,但是我看encrypt方法要求传的是string,而parse之后得到的是WordArray

长度问题,后端加密应该是默认 16 位的,你加密字符串截取 16 位加密,太长的话加密结果就会和后端不匹配

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题