这几天本人在 Python 做某网站登陆的时候,发现其登陆时用户名和密码被加密了
F12 仔细看了一下,发现是调用了一个 js 的 rsa 加密库,页面 dom 中有 rsa 公钥
于是乎,用了 3 分钟刷刷的潇洒的写了个 py 脚本,结果对比后傻眼了。。。
web 页面调用 js 库中的加密方式是 nopadding,也就是说,每次加密的结果都一样
而我的 py 脚本每次都不一样!!至于为什么会不一样,以及 padding 的作用请自行百度
于是乎,百度各种 python 库,也没有合适的解决方法
python 库 Crypto 倒是有一个网友给出了方法,但是安装这个库需要安装 Microsoft Visual C++ Build Tools
滚蛋,强行绑架的感觉,还是自己想办法搞定吧。
于是乎...
先分析了两个主要 js 文件,Bigint.js 、Barrett.js ,一脸懵逼,一头雾水,不知道再干嘛,仿佛在造一些轮子。。。暂且放过
然后找到了一篇介绍 rsa 加密中 padding 的文章:https://blog.csdn.net/guyongqiangx/article/details/74930951
主要知道了一个事情:
"填充后数据" = "00" + "数据块类型" + "填充字符串" + "00" + "原始数据"
然后又翻看了 python 的 rsa 库源码,其中有一个函数 _pad_for_encryption()
,很可疑,正是在做上述填充数据的事:
此函数位于 python 的 rsa 库 /pkcs1.py 文件中
def _pad_for_encryption(message, target_length):
r"""Pads the message for encryption, returning the padded message.
:return: 00 02 RANDOM_DATA 00 MESSAGE
>>> block = _pad_for_encryption(b'hello', 16)
>>> len(block)
16
>>> block[0:2]
b'\x00\x02'
>>> block[-6:]
b'\x00hello'
"""
max_msglength = target_length - 11
msglength = len(message)
if msglength > max_msglength:
raise OverflowError('%i bytes needed for message, but there is only'
' space for %i' % (msglength, max_msglength))
# Get random padding
padding = b''
padding_length = target_length - msglength - 3
# We remove 0-bytes, so we'll end up with less padding than we've asked for,
# so keep adding data until we're at the correct length.
while len(padding) < padding_length:
needed_bytes = padding_length - len(padding)
# Always read at least 8 bytes more than we need, and trim off the rest
# after removing the 0-bytes. This increases the chance of getting
# enough bytes, especially when needed_bytes is small
new_padding = os.urandom(needed_bytes + 5)
new_padding = new_padding.replace(b'\x00', b'')
padding = padding + new_padding[:needed_bytes]
assert len(padding) == padding_length
return b''.join([b'\x00\x02',
padding,
b'\x00',
message])
重点看 return 的数据,和上面所述的填充方法完全一致。
既然是 nopadding,那就把填充的值全部设置为\x00,填充方式也选\x00,把上述方法关键位置给改掉
完事,重新运行代码,加密后的数据确实不变了,每次都一样,但是和 web 页面中 js 库的还是不一样
突然想到,去看看这个 js 库的官方文档!!
找了又找,终于找到:http://www.ohdave.com/rsa/
介绍中有一个带注释版本 js 文件:http://www.ohdave.com/rsa/RSA.js
里面开头就介绍了 padding 的填充方式:
* Plaintext In
* ------------
*
* d5 d4 d3 d2 d1 d0
*
*
* NoPadding
* ---------
*
* 00 00 00 00 00 00 00 00 00 /.../ 00 00 d0 d1 d2 d3 d4 d5
果然有猫腻,这里的实现,是把需要加密的字符串反转,然后其他位全部填充\x00
既然知道了具体的填充方法,那就再改动一下 python 的 rsa 库_pad_for_encryption()
函数
果然
加密的结果和 web 中的 js 库加密的结果一样(使用相同的公钥)
最后撤销对 python 的 rsa 库文件修改,导入 rsa 库中的相关函数,封装成自己的函数,直接调用自己函数即可
当然,既然 nopadding 模式的搞定了,也可以搞定其他方式的填充了,但是本人暂时用不到,就没有再继续研究
有兴趣的可以自行研究
至此结束。。
py 文件,js 文件上传 github,需要的自己去看 https://github.com/founddev/evething/tree/master/rsa
本文由 founddev 原创,转载请注明出处!!