Python实现前端JS库jsrsasign RSA加密方法

背景

项目需求通过Python从某网站获取信息,该网站登录页面使用了较为少见的前端加密方式,即对登录请求携带的用户名密码等参数进行加密后传输,加密后数据如图所示:
在这里插入图片描述
因此,想要通过接口直接访问网站数据,便需要将登录信息以同样方式加密后发送给后端,以获取token供后续操作;

前端代码分析

从登录页面源代码中可以看到,登录接口在发送请求前,将将登录信息通过 p.KJUR.crypto.Cipher.encrypt()这个函数进行了转码,再将其作为请求体发送;
在这里插入图片描述
而这个函数经过搜索得知,属于前端库jsrsasign(官网地址:https://kjur.github.io/jsrsasign/)的RSA加密函数。
为了验证这个函数与目标页面使用的加密方式一致,我在本地构建一个网页,并引入jsrsasign库,使用其对目标页面获取的公钥和登录信息进行加密,并将生成的加密后数据通过postman发送给登录接口
在这里插入图片描述
在这里插入图片描述
可见校验通过,成功获取到了token信息,至此,可以确认目标网页使用的加密方式为RSA加密,通过jsrsasign库提供的函数加密。
那么想要通过Python获取到网页信息,便需要在Python端复现该加密方式,复现方式有两个方向:

  1. 在Python端通过JS相关拓展库直接调用jsrsasign库,并通过其获取加密后信息。这种方式简单快捷,但对环境依赖性较强,需要nodejs等环境,不利于迁移至其他平台环境;
  2. 找到jsrsasign库使用的加密算法,将其转换为Python实现。本文选择的是这个方向;

Python实现

首先尝试使用Python的Crypto库实现RSA加密,代码如下:

import base64
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pksc1_v1_5
from Crypto.PublicKey import RSA

def encrpt(password, public_key):
    rsakey = RSA.importKey(public_key)
    cipher = Cipher_pksc1_v1_5.new(rsakey)
    cipher_text = base64.b64encode(cipher.encrypt(password.encode()))
    return cipher_text.decode()

# 加载服务器公钥文件
public_server_key = b"""-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyMGvoJM6NvtbnKNB0zBh
***************************...
g/NXXD/LZaWsLTNy51DCWGxBvszYJ7CcW2pkX/BasMez0GRQeiC/OHmfueO+3Fit
iOuXXY9JzgdOFxgXGRGfJwECAwEAAQ==
-----END PUBLIC KEY-----
"""
print(encrpt("Test",public_server_key))

但是加密后数据经过base64转码后为如下格式,与前端转码出来格式不一致;
在这里插入图片描述
后续尝试使用sha256、sha512等编码格式转码,均无法得到jsrsasign库输出的结果。

但在尝试以上编解码方式时,注意到了前文提供编码的长度关系:通过jsrsasign库加密后的数据长度均为1024,而计算python中cipher.encrypt(password.encode())加密后数据长度为512,显然两者存在明显关联,而观察jsrsasign加密后数据可知,jsrsasign加密后数据是仅由小写字母和数字组成的字符串,不包含符号,不符合base64编码格式,与16进制数据格式很相似。

因此这里尝试将RSA加密后数据直接转换为16进制数据,代码如下:

import base64
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pksc1_v1_5
from Crypto.PublicKey import RSA

def encrpt(password, public_key):
    rsakey = RSA.importKey(public_key)
    cipher = Cipher_pksc1_v1_5.new(rsakey)
    cipher_text = cipher.encrypt(password.encode()).hex()
    return cipher_text

# 加载服务器公钥文件
public_server_key = b"""-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyMGvoJM6NvtbnKNB0zBh
***************************...
g/NXXD/LZaWsLTNy51DCWGxBvszYJ7CcW2pkX/BasMez0GRQeiC/OHmfueO+3Fit
iOuXXY9JzgdOFxgXGRGfJwECAwEAAQ==
-----END PUBLIC KEY-----
"""
print(encrpt("Test",public_server_key))

打印结果如下:

可见数据格式和长度均与jsrsasign库加密后数据一致,将该加密后数据通过postman发送给登录接口,可以成功获取到Token,验证通过,由此证明,以上代码可以复现前端jsrsasign库加密方式。

更新

由于生产环境Python3.9.9不再支持Crypto库,这里提供基于cryptography库的加密代码:

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes

def encrypt(password, public_key):
    rsakey = serialization.load_pem_public_key(public_key)
    cipher_text = rsakey.encrypt(
        password.encode(),
        padding.PKCS1v15()
    )
    return cipher_text.hex()

# 加载服务器公钥文件
public_server_key = b"""-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyMGvoJM6NvtbnKNB0zBh
***************************...
g/NXXD/LZaWsLTNy51DCWGxBvszYJ7CcW2pkX/BasMez0GRQeiC/OHmfueO+3Fit
iOuXXY9JzgdOFxgXGRGfJwECAwEAAQ==
-----END PUBLIC KEY-----
"""
print(encrpt("Test",public_server_key))
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值