在爬虫分析的时候,常常在网页上看到以下格式的rsa公钥:python
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB
对于rsa算法的公钥,咱们了解到,主要有两个信息:模数(modulus)和指数(exponent)算法
只有有这两个信息,咱们即可以用如下代码段生成公钥,而后使用rsa库对数据进行加密编码
import rsa key = rsa.PublicKey(modulus, exponent) print key
如今咱们须要作的就是从这段字符串中提出模数和指数.加密
在研究的过程当中,除了这种字符串的形式,咱们看得最多的应该属于public.pem、private.pem这种文件格式的公钥私钥了.spa
那么PEM这又是个什么格式呢,搜索下来,基本上都说包含什么信息而后是数据什么的,我怎么知道那些是信息,那些是数据呢?code
对比一些资料,以为看下图基本明了(原本是有一篇很好的文章,貌似找不到连接了,只保存了一张图片)blog
咱们打开pem格式的文件看一下,发现图片
-----BEGIN RSA PUBLIC KEY----- MIGJAoGBAPVZR7eov/GFh77lx2sp1FDkP63mygPAUkomwV9fPFUuajviO5038P3k Jhl5o14+LN8NxLuyiTzgYKSunUkvqxwkWSKHOw8EL3m6YKytk5UR+FEg8LBqPNox lcT9a9VH2PngbnR9WWm2ycMQBppQRC3Ci7yLIcjwgDUOrgoz6PmpAgMBAAE= -----END RSA PUBLIC KEY-----
这个BEGIN和这个END中间这一段很像咱们找到的这个字符串,咱们把开头的字符串复制到public.pem文件的中间,而后使用如下代码加密试试:utf-8
import rsa with open('public.pem','r') as f: pubkey = rsa.PublicKey.load_pkcs1(f.read().encode()) message = 'cnblogs' crypto = rsa.encrypt(message.encode(), pubkey) print crypto
这段彷佛根本就会报错,并且,这个复制过去的格式也不对,原先的是有换行的,字符串
查询一下彷佛换行也是一种信息,而咱们的字符串从哪里换行根本无从得知
那么,这个字符串和pem就没有别的联系了吗?答案是有的.
以前就有猜想这个字符串多是base64加密过的,那么我就解密看看:
import base64 pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB" b64_str = base64.b64decode(pubkey) print b64_str print len(b64_str)
获得一串乱码,咱们把这串乱码转换成16进制
发现结尾是"\x01\x00\x01",10001,看多了rsa的公钥,就知道这个数,多半是exponent了.
再看看解码后的长度,162,咱们找到偏移表,发现模数的偏移位置是159,长度是3,加起来正好162
那么说明这段字符串就是指数和模数加密事后的结果,甚至比通常的pem文件中的信息还要简单
按照这个思路,对照偏移表咱们找出指数和模数:
# /usr/bin/python # encoding: utf-8 import base64 def str2key(s): # 对字符串解码 b_str = base64.b64decode(s) if len(b_str) < 162: return False hex_str = '' # 按位转换成16进制 for x in b_str: h = hex(ord(x))[2:] h = h.rjust(2, '0') hex_str += h # 找到模数和指数的开头结束位置 m_start = 29 * 2 e_start = 159 * 2 m_len = 128 * 2 e_len = 3 * 2 modulus = hex_str[m_start:m_start + m_len] exponent = hex_str[e_start:e_start + e_len] return modulus,exponent if __name__ == "__main__": pubkey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDC7kw8r6tq43pwApYvkJ5laljaN9BZb21TAIfT/vexbobzH7Q8SUdP5uDPXEBKzOjx2L28y7Xs1d9v3tdPfKI2LR7PAzWBmDMn8riHrDDNpUpJnlAGUqJG9ooPn8j7YNpcxCa1iybOlc2kEhmJn5uwoanQq+CA6agNkqly2H4j6wIDAQAB" key = str2key(pubkey) print key
获得结果以下:
('c2ee4c3cafab6ae37a7002962f909e656a58da37d0596f6d530087d3fef7b16e86f31fb43c49474fe6e0cf5c404acce8f1d8bdbccbb5ecd5df6fded74f7ca2362d1ecf033581983327f2b887ac30cda54a499e500652a246f68a0f9fc8fb60da5cc426b58b26ce95cda41219899f9bb0a1a9d0abe080e9a80d92a972d87e23eb', '010001')
如今咱们用刚才获得的key来加密字符串:
import rsa message = 'cnblogs' modulus = int(key[0], 16) exponent = int(key[1], 16) rsa_pubkey = rsa.PublicKey(modulus, exponent) crypto = rsa.encrypt(message, rsa_pubkey) b64str = base64.b64encode(crypto) print b64str
就能够获得一个rsa加密,base64编码过的字符串了.
总结一下:主要就是在一串字符串中,对照一个偏移表,提取须要的位置上的数字.