速看:CryptoJS.base64 的不同之处,别再死扣源码了「附正确实现」

速看:CryptoJS.base64 的不同之处,别再死扣源码了「附正确实现」,第1张

文章目录
  • 问题现象
  • 分析
  • 解决
  • 参考

当我们在逆向分析 JS 代码时,常见的一个库就是 CryptoJS,它实现了众多算法,可以很方便的对数据进行编码,加密。但是它的 Base64 却与正常的 Base64 有一些不同,本文以一个实际案例,以做说明。

问题现象

调试 js 过程中,发现了如下代码:

se.MD5(JSON.stringify(e.data)).toString(se.enc.Base64) : ""

经过调试分析,确认采用了 CryptoJS,代码很好理解,转换伪代码就是 Base64(MD5(data)),使用 Python 可以很方便实现这个步骤:

data = '{"username":"admin","password":"123456"}'

def md5(data):
    m = hashlib.md5()
    m.update(data.encode('utf-8'))
    return m.hexdigest()

result = base64.b64encode(md5(data).encode())
print(result)

但是最终的结果却不同:

# CryptoJS 方案: ajLsAwT3NLtxEp+rUwIY8A==
# Python   方案: ODNhMTJmZGYwYTI1NTIxOGIwNDc4YWZjM2U2YmY3M2M=
分析

由于最终结果仅通过 md5 以及 base64 编码得来,猜测可能是 CryptoJS 内容对这两种算法进行了魔改,我们便可以将目标锁定在这两种算法上。

因此,首先,我们确认一下 CryptoJS MD5 的结果是否与 Python 一致:

// CryptoJS MD5
se.MD5(JSON.stringify(e.data)).toString();  // 6a32ec0304f734bb71129fab530218f0

// Python MD5
print(md5(data))                            // 6a32ec0304f734bb71129fab530218f0

结果一致,那么大概率问题是发生了 CryptoJS 的 Base64 上边,经过一顿查询资料,最后发现是 加密结果传递类型导致的问题。

在 CryptoJS 中,采用 WordArray 类型来传递数据。在 控制台打 se.MD5(JSON.stringify(e.data)),你就会得到一个 WordArray 对象:

当你调用 WordArray 的 toString() 方法时,你会得到该二进制对象的 16 进制编码的字符串。

toString: function (encoder) {	            
		return (encoder || Hex).stringify(this);	        
}

而当你执行 toString(CryptoJS.enc.Base64) 会将该 16 进制编码的字符串 编码为 Base64,而我们在 Python 中或者在一些网页在线工具进行 Base64 编码时,会默认把这段字符串视为 UTF8 编码格式,这也是问题所在!

# 可以看到这里我们的 MD5 的结果 encode 为 utf8(无参数默认为 utf8 编码)
# 而 CryptoJS 中会把 MD5 的结果视为 16 进制编码字符串

result = base64.b64encode(md5(data).encode())
解决

要解决这个问题,也非常简单,我们把 MD5 的结果结果视为 16 进制编码的不就可以了吗

  1. 在 Python3 中我们可以使用 bytes.fromhex() 方法

    def md5(data):
        m = hashlib.md5()
        m.update(data.encode('utf-8'))
        return m.hexdigest()
    
    result = base64.b64encode(bytes.fromhex(md5(data)))
    print(result)
    
  2. 或者直接返回 md5 编码后的 bytes 数据

    def md5(data):
        m = hashlib.md5()
        m.update(data.encode('utf-8'))
        return m.digest()
    
    result = base64.b64encode(md5(data))
    print(result)
    

而如果你是一名前端程序员,那么如何让 CryptoJS 中的 Base64 返回 UTF8 格式编码后的结果呢?毕竟这样更符合直觉嘛!下面给出部分示例:

// md5 -> utf8 -> base64
CryptoJS.enc.Utf8.parse(CryptoJS.MD5("123456")).toString(CryptoJS.enc.Base64);

// str -> utf8 -> base64
CryptoJS.enc.Utf8.parse("123456").toString(CryptoJS.enc.Base64);
CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse("123456"));
参考
  • CryptoJS.enc.Base64.stringify() 和正常的Base64加密之间的区别

    https://blog.csdn.net/qq_41385602/article/details/122982911

  • Difference between CryptoJS.enc.Base64.stringify() and normal Base64 encryption

    https://www.yuanmacha.com/1325533793.html

  • python3 字符串 hex 相互转换

    https://blog.csdn.net/whatday/article/details/107769032

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/917299.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存