CryptoJS.enc.Base64.stringify()和正常的Base64加密之间的区别

最近接触了加密传输,尝试使用CryptoJS,发现在进行base64处理时,使用window.btoa和CryptoJS.enc.Base64.stringify得到的结果并不一致,并且使用在线加密工具和window.btoa一致

import CryptoJS from 'crypto-js'
import sha1 from 'crypto-js/sha1'
import Base64 from 'crypto-js/enc-base64'

const rawStr = 'message'
  console.log(
    window.btoa(sha1(rawStr)), // NmY5YjlhZjNjZDZlOGI4YTczYzJjZGNlZDM3ZmU5ZjU5MjI2ZTI3ZA==
    Base64.stringify(sha1(rawStr)), // b5ua881ui4pzws3O03/p9ZIm4n0=
  )

搜索了很多关于CryptoJS的资料,最后发现是加密结果传递类型导致的问题

在CryptoJS中,采用WordArray类型来传递数据。

在控制台中打印 sha1(rawStr),会得到一个对象:

简单理解就是words是一个byte数组

比较巧合的一点是, WordArray的这个对象具有toString()方法,所以在js中是可以直接隐式转换成字符串的,但是默认是Hex编码(16进制)。我们可以看下CryptoJS对于toString的实现

toString: function (encoder) {
	            return (encoder || Hex).stringify(this);
	        },
// 这里encoder是指诸如CryptoJs.enc.Base64这样的工具类
// 所以建议使用对应工具类的stringify获取最终字符串

回到正题,对于window.btoa(sha1(rawStr)),会先将sha1(rawStr)得到的结果隐式转换成字符串"6f9b9af3cd6e8b8a73c2cdced37fe9f59226e27d"(这里说一下sha1得到的结果是只能用Hex编码表示的,因为包含不能打印的字符,用16进制方便人看),所以就相当于

window.btoa('6f9b9af3cd6e8b8a73c2cdced37fe9f59226e27d') // NmY5YjlhZjNjZDZlOGI4YTczYzJjZGNlZDM3ZmU5ZjU5MjI2ZTI3ZA==

但是widow.btoa会将'6f9b9af3cd6e8b8a73c2cdced37fe9f59226e27d'视为是UTF8编码的结果(在线解密工具也是如此),所以只需在使用CryptoJS.enc.Base64之前,做一下UTF8转换就可以了

console.log(
    '对照组',
    window.btoa(sha1(rawStr)), // NmY5YjlhZjNjZDZlOGI4YTczYzJjZGNlZDM3ZmU5ZjU5MjI2ZTI3ZA==
    Base64.stringify(sha1(rawStr)), // b5ua881ui4pzws3O03/p9ZIm4n0=
    Base64.stringify(CryptoJS.enc.Utf8.parse(sha1(rawStr).toString())) // NmY5YjlhZjNjZDZlOGI4YTczYzJjZGNlZDM3ZmU5ZjU5MjI2ZTI3ZA==
  )

相对应的,在window.btoa之前做一下Hex->UTF8转换也可以,但由于sha1无法用UTF8表示,这里其实无法实现

因此这两种结果理论上都是正确的,两种base64加密方法本身是一致的,只是看实际需求选择了。

相关资料:

CryptoJS.enc.Base64.stringify()与普通Base64加密之间的区别 - javascript代码 - 源码查

SHA1加密后转为字符串为什么需要Hex编码?--CSDN问答


版权声明:本文为qq_41385602原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。