杂项之python利用pycrypto实现RSA
本节内容
- pycrypto模块简介
- RSA的公私钥生成
- RSA使用公钥加密数据
- RSA使用私钥解密密文
- 破解博客园登陆
pycrypto模块简介
pycrypto模块是python中用来处理加密解密等信息安全相关的一个很重要模块。
该模块支持的加密方式:
-
对称加密方式:
- AES
- DES
- ARC4
-
散列值计算:
- MD5
- SHA
- HMAC
-
公钥加密和签名:
- RSA
- DSA
基本上常见的关于信息安全类的算法都可以支持,所以,这是一个很强大的模块。
安装方式:pip install pycrypto
如果在windows上的python3.5中安装完成之后导入from Crypto import Random模块失败,需要找到python35安装目录下的Lib\site-packages\Crypto\Random\OSRNG\nt.py文件,将import winrandom修改成from . import winrandom
关于加密方式的了解可以看我这边博客:加密方式介绍
关于非对称加密算法(RSA)的使用可以看我这篇博客:数字签名和数字证书
RSA的公私钥生成
from Crypto import Random from Crypto.PublicKey import RSA # 伪随机数生成器 random_generator = Random.new().read # rsa算法生成实例 rsa = RSA.generate(1024, random_generator) # master的秘钥对的生成 private_pem = rsa.exportKey() #--------------------------------------------生成公私钥对文件----------------------------------------------------------- with open('master-private.pem', 'wb') as f: f.write(private_pem) public_pem = rsa.publickey().exportKey() with open('master-public.pem', 'wb') as f: f.write(public_pem) #--------------------------------------------------- # ghost的秘钥对的生成 private_pem = rsa.exportKey() with open('ghost-private.pem', 'wb') as f: f.write(private_pem) public_pem = rsa.publickey().exportKey() with open('ghost-public.pem', 'wb') as f: f.write(public_pem) #-----------------------------------生成的公私钥文件类似于如下形式------------------------------------------------------- # 私钥 -----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQC6mwuOxuqYi6mugLGr3OuiHwm/hF4kQX1zd5VhGwxYf4H5+pkO CES2UjOyLP9Xh6w+DJtRwTGE2xwDd3wMfW2wkHijM/uHkM9Jt+oRGIjy4IiXo+7t ue/NWBkDiQm1qte0YDKlmkFREwvZ5X2KaCsSx+dyKH4QsovxQ3/RxftdmQIDAQAB AoGAPA5SNe1G6zlnrsW0aL99Bnw+wuhy8/Av082Uwd/WpVTEHBPO1nlKw/LIuHtK 4nzDrmSYSEOJEF0EMwltXwevGSm1wq2FBhX4T+kz3XUpWfv9O0dlHeNtgxeD1QXL kOxqU4F2WpdALgvi/rlPDd0aIagoXLi8MXkUH7hQlrJpQUECQQC6rygx3jDQA9Iw kPUXlokEuLod+Kgoa700S5qpJi7vft675+tMG5SZtr+HQeqGHty0fqc8MIcy1fJm ZYUrogN9AkEA/+RrrOoTYQbR3ENslTsNsiqQa2aZW5XAv9pEyGJBWu/4HUEEa6G3 FY0Y3ACZR0Xaraya8XAgOo61pWm83GBlTQJBAKH2812Ikzr2BbdDHJExdoEVL8xu /p3LE6U6bt2QFiqNHPtT9C3cw+k0xyi3RJzGS9+A/uDWjYXKXvr92zMG5hUCQFXR alccTZF9swX2ysSlgGtfIP4T85ymdXUiI208noR79C8DbhMWsgsVPeASh1VC1Rrn xzLvkq9wyvSFqKQT5AUCQAxMO7KI1rwIm+ISuDEcwxRJXkdFypD74kOSYRxTqMun Zdu4ku4t6mVeq5kBv1/S2dtF3TiqMRlxmLmV/fx7KHM= -----END RSA PRIVATE KEY----- #公钥 -----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6mwuOxuqYi6mugLGr3OuiHwm/ hF4kQX1zd5VhGwxYf4H5+pkOCES2UjOyLP9Xh6w+DJtRwTGE2xwDd3wMfW2wkHij M/uHkM9Jt+oRGIjy4IiXo+7tue/NWBkDiQm1qte0YDKlmkFREwvZ5X2KaCsSx+dy KH4QsovxQ3/RxftdmQIDAQAB -----END PUBLIC KEY-----
RSA使用公私钥加解密数据
from Crypto.PublicKey import RSA from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 import base64 message = 'hello ghost, this is a plian text' with open('ghost-public.pem',"r") as f: key = f.read() rsakey = RSA.importKey(key) # 导入读取到的公钥 cipher = Cipher_pkcs1_v1_5.new(rsakey) # 生成对象 cipher_text = base64.b64encode(cipher.encrypt(message.encode(encoding="utf-8"))) # 通过生成的对象加密message明文,注意,在python3中加密的数据必须是bytes类型的数据,不能是str类型的数据 print(cipher_text) with open('ghost-private.pem') as f: key = f.read() rsakey = RSA.importKey(key) # 导入读取到的私钥 cipher = Cipher_pkcs1_v1_5.new(rsakey) # 生成对象 text = cipher.decrypt(base64.b64decode(cipher_text), "ERROR") # 将密文解密成明文,返回的是一个bytes类型数据,需要自己转换成str print(text) # 结果: b'meBtYXP35VNjtWXsONDluweXdG98tMHjb5GxBLFJ0GJzo+96wSrHe8SDhNJweDJP6/OdeIQ8jP1HKCK+aC9HA12YMSUUqcixsY5s8QUyTs+fkMjGrlC6I7hPLO4DGQbFXEY0jiqP9ycgmAi5FCsDMcm0oEm8/fVzv7vl9QarSN4=' # 加密后的密文 b'hello ghost, this is a plian text' # 解密后的明文
破解博客园登陆
经过分析博客园登陆方式为在用户填入用户名和密码之后,点击登录时js将会使用JSEncrypt这个开源组件对用户输入的用户名和密码进行加密,加密的公钥在js源码中查找到了,为”MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0MccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdgOQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknrScAKC0XhadTHT3Al0QIDAQAB”
后经查询资料得知该js组件使用的加密方式为RSA加密,又获取到了加密的公钥,所以,我们可以自己模拟JS加密方式将我们自己的用户名密码使用RSA加密之后提交到博客园服务器来实现登录。
import re import json from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5 from Crypto.PublicKey import RSA import base64 import requests def js_encrypt(text): # 通过拿到js中的RSA公钥,构造完整的公钥部分 key = """-----BEGIN PUBLIC KEY----- MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCp0wHYbg/NOPO3nzMD3dndwS0MccuMeXCHgVlGOoYyFwLdS24Im2e7YyhB0wrUsyYf0/nhzCzBK8ZC9eCWqd0aHbdgOQT6CuFQBMjbyGYvlVYU2ZP7kG9Ft6YV6oc9ambuO7nPZh+bvXH0zDKfi02prknrScAKC0XhadTHT3Al0QIDAQAB -----END PUBLIC KEY-----""" rsakey = RSA.importKey(key) cipher = Cipher_pkcs1_v1_5.new(rsakey) # 生成对象 cipher_text = base64.b64encode(cipher.encrypt(text.encode(encoding="utf-8"))) # 对传递进来的用户名或密码字符串加密 print(cipher_text) value = cipher_text.decode('utf8') # 将加密获取到的bytes类型密文解码成str类型 return value session = requests.Session() i1 = session.get('https://passport.cnblogs.com/user/signin') # 访问博客园登陆页面 rep = re.compile("'VerificationToken': '(.*)'") # 构造正则获取博客园的CSRF键值对 v = re.search(rep, i1.text) verification_token = v.group(1) # 拿到CSRF值 form_data = { # 构造post的请求体 'input1': js_encrypt('你博客园账号'), # 将用户名填在提示位置,将返回加密后的用户名 'input2': js_encrypt('你博客园密码'), # 将密码填在提示位置,将返回加密后的密码 'remember': False } i2 = session.post(url='https://passport.cnblogs.com/user/signin', # post访问登陆页面,发送登陆请求 data=json.dumps(form_data), headers={ 'Content-Type': 'application/json; charset=UTF-8', # 设置Content-Type类型为JSON类型 'X-Requested-With': 'XMLHttpRequest', # 设置头部的X-Requested-With字段,标示该请求为AJAX请求 'VerificationToken': verification_token} # 将之前获取到的CSRF键值对设置在头部信息中 ) i3 = session.get(url='https://i.cnblogs.com') # 访问登陆后的页面 print(i3.text) # 如果打印出登陆后的页面,说明登陆操作成功
来源:https://www.cnblogs.com/huxianglin/p/6387045.html