本文详解如何使用JS库crypto-js进行AES等对称加密,并解决前后端加解密互通问题。重点解析WordArray二进制数据与UTF8、Base64及Hex格式的转换方法,通过JS与PHP代码对比验证,确保密钥Key和向量IV在跨语言交互中的一致性,实现前端JS解密后端PHP加密数据的完整流程。
crypto-js库简介与安装
在JavaScript中实现加密解密功能,可以使用crypto-js库。这是一个专注于对称加密的工具库,支持AES和DES算法,但不包含RSA等非对称加密方法。安装该库非常简单,只需执行命令npm install crypto-js即可。它提供了MD5、SHA-1、SHA-256、Base64、AES和DES等多种算法的支持。
import crypto from "crypto-js"
let md5binary = crypto.MD5("message");
let hamcmd5binary =crypto.HmacMD5("message");
//以上两个得到的是一个二进制的数据, 要可打印出业,就要使用 16进制模式或者base64方式
//crypto 也有应的转换方法若需将WordArray(即二进制数据对象)转换为其他格式,可以通过显式调用toString方法并指定相应的编码器来实现。
import crypto from "crypto-js"
let md5message = cryptjs.MD5(str); //这里得到的都是摘要的 二进制数据
console.log(md5message); //打印的二进制数据
let hmacmd5message = cryptjs.HmacMD5(str,"haha"); //这里得到的都是摘要的 二进制数据
console.log(hmacmd5message); //打印的二进制数据
let sha1message = cryptjs.SHA1(str); //这里得到的都是摘要的 二进制数据
console.log(sha1message); //打印的二进制数据
let hamcsha1message = cryptjs.HmacSHA1(str,"haha");//这里得到的都是摘要的 二进制数据
console.log(hamcsha1message); //打印的二进制数据
let sha512message = cryptjs.SHA512(str); //这里得到的都是摘要的 二进制数据
console.log(sha512message); //打印的二进制数据
let hmacsha512message = cryptjs.HmacSHA512(str,"haha");//这里得到的都是摘要的 二进制数据
console.log(hmacsha512message);//打印的二进制数据
//上面打印的都是二进制的数据, 不利于传输, 所以, 我们要把它们变成 十六进制数据,或都base64的数据来进行传输
//通过显式调用toString方法并传递编码器,可以将WordArray(二进制)对象转换为其他格式。
//转成 base64 格式的方法
let strbyhex = md5message.toString(cryptjs.enc.Hex); //把二进制数据转成16进制
console.log(strbyhex,"|||||||| js 十六进制结果");
let strbybase64 = md5message.toString(cryptjs.enc.Base64); //把二进制数据转成base64
console.log(strbybase64,"||||||||js base64 结果")为了验证转换的准确性,我们将最后几行代码中二进制转16进制和二进制转Base64的结果,与PHP生成的结果进行对比。
public function testpass(){
$md5binary = hash("md5","message",true); //第三个参数 为false 输出的是十六进制数据 如果是true 输出的是二进制数据
//php 转二进制数据到 十六进制数据
$md5hex = bin2hex($md5binary);
//php 二进制数据到base64
$md5base64 = base64_encode($md5binary);
echo "php十六进制结果";
echo $md5hex;
echo "<br/>";
echo "php base64结果";
echo $md5base64;
}分别运行相关代码以查看输出结果。


经过对比,结果一致,没有问题。
JS与PHP数据格式转换验证
对称加密
crypto-js同样适用于对称加密场景。以AES对称加密为例,该过程需要密钥(key)和向量(iv)。Crypto-js支持AES-128、AES-192和AES-256三种变体,系统会根据传入密钥的大小自动选择对应的变体。若使用密码短语,库会自动生成256位密钥。当然,开发者也可以手动定义密钥key和iv向量。在此之前,我们需要先了解JS中Base64、16进制和UTF8之间的转换机制。
JS与PHP中UTF8字符串转Base64的方法。
let str = "这是一个测式";
let words = cryptjs.enc.Utf8.parse(str); //先把字符串转成words数型的二进制数组
let base64words = cryptjs.enc.Base64.stringify(words); //把二进制数组转成 base64字符串
console.log(base64words); //输出 6L+Z5piv5LiA5Liq5rWL5byP我们可以使用PHP的base64_encode函数来验证JS端生成的Base64结果。
$a = "这是一个测式";
echo base64_encode($a); //输出的结果 6L+Z5piv5LiA5Liq5rWL5byPJS与PHP中将Base64字符转换回UTF8字符串的方法。
let baseStr = "6L+Z5piv5LiA5Liq5rWL5byP";
let wordsbyBase64 = cryptjs.enc.Base64.parse(baseStr); //把base64字符串转成 words数组(二进制数组)
let res = cryptjs.enc.Utf8.stringify(wordsbyBase64);
console.log(res); //结果 这是一个测式使用PHP的base64_decode函数进行验证。
$a = "6L+Z5piv5LiA5Liq5rWL5byP";
echo base64_decode($a); // 结果 这是一个测式JS与PHP中将UTF8字符串转换为16进制数据的方法。
let str1 = "这是一个字符串转成十六进制的测试";
let words16bystr = cryptjs.enc.Utf8.parse(str1);
let hexstr = cryptjs.enc.Hex.stringify(words16bystr);
console.log(hexstr); //得到结果 e8bf99e698afe4b880e4b8aae5ad97e7aca6e4b8b2e8bdace68890e58d81e585ade8bf9be588b6e79a84e6b58be8af95使用PHP进行验证。
$str = "这是一个字符串转成十六进制的测试";
$strto16 = bin2hex($str);
echo $strto16; //结果 e8bf99e698afe4b880e4b8aae5ad97e7aca6e4b8b2e8bdace68890e58d81e585ade8bf9be588b6e79a84e6b58be8af95此处存在一个疑问:明明处理的是字符串,为什么PHP转换时使用了bin2hex函数?通常该函数用于二进制数据转Hex。随后,我使用PHP的gettype函数检查发现,无论是字符串还是二进制数据,在PHP中均被识别为string类型。这表明PHP底层将字符串视为二进制数据处理(此观点仅供参考,可能存在理解偏差)。
$str = "这是一个字符串转成十六进制的测试";
echo gettype($str); // 显示 string
echo "<br/>";
//为了得到一个二进制的乱码一样的数据, 我们可以使用 hash函数得到
//hash 第三个参数如果设为 true ,就可以得到一个二进制数据
$binary = hash("md5","123456",true);
echo $binary; // 显示 � �9I�Y��V�W��>
echo gettype($binary); // 显示 string 但这个明显是一些乱码从上述示例可见,$str和$binary在PHP中属于同一类型(string),底层均视为二进制数据。然而,为何一个显示正常而另一个显示乱码?原因在于$str包含的中文字符在字符码表中有对应的编码,而$binary是一串无序的二进制数,部分字节可能在中文码表中无对应字符,从而显示为乱码。由于部分数据会显示乱码,因此在传输时建议使用Base64编码,将二进制数据转换为Base64格式传输,以确保数据不丢失。
JS与PHP中将16进制数据转换回UTF8字符串的方法。
let str2 = "e8bf99e698afe4b880e4b8aae5ad97e7aca6e4b8b2e8bdace68890e58d81e585ade8bf9be588b6e79a84e6b58be8af95";
let hextowords = cryptjs.enc.Hex.parse(str2); //把十六进制转成 words (二进制数组)
let str2back = cryptjs.enc.Utf8.stringify(hextowords); //把二进制转成utf8
console.log(str2back);使用PHP进行验证。
$hexstr = 'e8bf99e698afe4b880e4b8aae5ad97e7aca6e4b8b2e8bdace68890e58d81e585ade8bf9be588b6e79a84e6b58be8af95';
$str = hex2bin($hexstr);
echo $str;JS与PHP AES加解密互通示例
基于上述基础知识,我们接下来进行一个综合示例。
由后端PHP使用对称加密对一段文字进行加密,返回给前端JS,同时返回加密所需的iv。随后,前端JS使用crypto-js进行解密,验证是否正确。这是一个JS AES加解密的示例。
crypto-js.AES.encrypt参数中的key和iv均以WordArray(二进制)形式传入,因此需要理解Utf8.parse方法的用法。Crypto-js支持AES-128、AES-192和AES-256,会根据传入密钥的大小自动选择变体。因此,在下例中,由于key1只有16位,系统会自动选用AES-128。
//加密
let secretStr = "这是一个测试AES";
let key1 = cryptjs.enc.Utf8.parse("1234567812345678"); //十六位的
let encrypted1 = cryptjs.AES.encrypt(secretStr,key1,{
iv:cryptjs.enc.Utf8.parse("abcdefghijklmnop"),
mode:cryptjs.mode.CBC, //aes加密模式cbc 这个参数要前后端一至使用统一的加密模式
padding:cryptjs.pad.Pkcs7 //使用 Pkcs7的方式填充 //这个php 加密时默认就是这种方式
});
console.log(encrypted1); //加密的结果是一个对象
console.log(encrypted1.key); //对象中有 key , iv 等信息
console.log(cryptjs.enc.Utf8.stringify(encrypted1.key)) //打印出key 的utf8字符串
console.log(encrypted1.toString()) //使用toString 方法可以得到加密后的字符串
//加密的结果是: YzXNRYB6/mmevnBiZPLRPu4Knk+qUVNyhUKonAB2Wjg= 这明显是一个base64格式的
//解密
let result = cryptjs.AES.decrypt(encrypted1.toString(),key1,{
iv:cryptjs.enc.Utf8.parse("abcdefghijklmnop"),
mode:cryptjs.mode.CBC,
padding:cryptjs.pad.Pkcs7
})
console.log(result); //解密后得到的是一个 wordArray 二进制的对象
console.log(cryptjs.enc.Utf8.stringify(result)); //把二进制对象转成 utf8的字符
//解密的结果是 这是一个测试AESPHP端的AES加解密实现。
$str = "这是一个测试AES";
$algo = "AES-128-CBC";
dump(openssl_cipher_iv_length($algo)); //这里我们可以先看一下 AES-128-CBC 的所需要的 iv 长度 结果是16,所以我们自定义了一个iv 是16个字符
$key = "1234567812345678";
$iv = "abcdefghijklmnop";
$encrypt = openssl_encrypt($str,$algo,$key,OPENSSL_RAW_DATA,$iv);
echo $encrypt; //显示结果 YzXNRYB6/mmevnBiZPLRPu4Knk+qUVNyhUKonAB2Wjg=
echo "<br/>";
$decrypt = openssl_decrypt($encrypt,$algo,$key,OPENSSL_RAW_DATA,$iv);
echo $decrypt;从上述结果可以看出,JS和PHP的加密结果一致,说明前端JS与后端PHP可以实现加解密的互通。
至此,关于JS使用crypto-js进行对称加密解密的文章介绍完毕。如需了解更多JS加密解密相关内容,请搜索本站以前的文章或继续浏览下面的相关文章,希望大家以后多多支持本站!