js 加密解密可以使用 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 也有应的转换方法
通过显式调用toString方法并传递编码器,可以将WordArray(二进制数据)对象转换为其他格式。
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); //把二进制数据转成base64console.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;}
分别运行代码看结果
对比没有问题
对称加密
cryptojs 也可以用来做对称加密,就拿 AES 对称加密来说
AES 对称加密是 需要有 密钥key 向量 iv
CryptoJS支持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 来验证一下
$a = "这是一个测式";echo base64_encode($a); //输出的结果 6L+Z5piv5LiA5Liq5rWL5byP
js 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); // 显示 stringecho "<br/>";//为了得到一个二进制的乱码一样的数据, 我们可以使用 hash函数得到//hash 第三个参数如果设为 true ,就可以得到一个二进制数据$binary = hash("md5","123456",true);echo $binary; // 显示 � �9I�Y��V�W��>echo gettype($binary); // 显示 string 但这个明显是一些乱码
从上面的例子中, 我们看到 其实 $str 和 $binary 都是一个类型的(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); //把二进制转成utf8console.log(str2back);
php 验证
$hexstr = 'e8bf99e698afe4b880e4b8aae5ad97e7aca6e4b8b2e8bdace68890e58d81e585ade8bf9be588b6e79a84e6b58be8af95';$str = hex2bin($hexstr);echo $str;
有了上面的基础, 我们下面来做一个例子
由后端php 使用 对称加密,加密一段文字, 然后返回给前端js , 同时要返回 加密的 iv, 然后前端 js 使用 cryptojs 来进行解密, 看是否正确
js AES 加解密
cryptjs.AES.encrypt 参数中的 key 和 iv 都是 以 wordsArray (二进制) 传入的,所以要明白 Utf8.parse 的方法
CryptoJS支持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的字符//解密的结果是 这是一个测试AES
php 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也是可以互通加解密的