用Python写DES加解密的常用函数
渗透测试借助burpy插件写Python加解密脚本,des加解密函数示例
生成pkcs(填充明文)
输入str类型的data,返回byte型data
padding(data,key_len)
def padding(data,key_len): #传参是str类型的data和密钥长度key_len
data=data.encode() #先把它这个str转成byte~
missing_padding=key_len-len(data)%key_len #计算需要填充几个字符 假设data长33,密钥长16,那么取模得1,要填充15位保证data填充后长度是密钥长度的整数倍 但是……要是刚好整除,取模为0,那不就是要填充一个密钥长度了……好像不太合理
if missing_padding:
data+=(chr(missing_padding)*missing_padding).encode() #如果需要填充,那么就填充上missing_padding这么多位数的missing_padding,这种设计主要是为了之后去掉填充会很巧妙,注意不要漏掉encode(),因为data已经是byte类型了
return data #返回byte形式的、已经填充的data
去掉填充
输入是上面的那个byte形式的、已经填充的data,返回的是去掉填充的str形式的data
unpadding(data_e)
def unpadding(data_e): #参数data_e是byte形式的、已经填充的data
data_e=data_e[:-data_e[-1]] #去掉填充,这里直接去掉data_e的最后一位的值对应的长度,因为之前填充的填充位就是填充长度的数字(读起来太绕的话建议直接执行一下试试看效果,但要注意这里是【byte类型】才可以实现这种操作!)
return data_e.decode() #byte转str
DES加密(ECB模式)
需要自己写一部分,然后调用两个模块,DES和base64:
记得要先在代码开头写上
from Crypto.Cipher import DES
和
import base64
传参是str,在函数内部先转换密钥key为byte,对明文data填充并转byte,之后再调用DES模块,new一个des对象,des对象调用encrypt加密函数,加密完再base64编码一下,最后转str类型返回
des_encrypt(data,key)
def des_encrypt(data,key): #明文data和密钥key均为str类型
key_len=len(key) #拿到密钥长度,后续作为padding函数的传参
key=key.encode() #密钥需要转成byte
data=padding(data,key_len) #调用上面的padding函数得到byte形式的、已经填充的data
'''------↓下面重点来了↓------'''
des=DES.new(key,DES.MODE_ECB) #调用DES.new创建了一个des对象!指定了密钥和模式为ECB
result=des.encrypt(data) #由des对象调用DES模块的encrypt函数进行des加密
'''注意上面这两个DES模块的函数,参数都需要是byte类型,返回的result也是byte,然后下一步直接传给base64编码函数'''
result=base64.b64encode(result) #加密结果做base64编码
return result.decode() #返回str类型的base64编码结果
DES解密(ECB模式)
类比加密,传参data是上面des_encrypt函数返回的那种str类型的密文,key也是str类型,进入函数先转key为byte,并将data做base64解码(b64decode函数的参数可以是str,解码后返回的结果是byte,但b64encode函数的参数只能是byte,编码后返回的也是byte)。调用DES.new创建des对象,des对象调用解密函数decrypt对密文data解密,解密结果去掉填充,得到str类型的明文。
des_decrypt(data,key)
def des_decrypt(data,key):
key=key.encode()
data=base64.b64decode(data) #b64decode传入参数可以是str,返回的是byte,所以这里执行后,data也是byte了
des=DES.new(key,DES.MODE_ECB)
data=des.decrypt(data) #解密得到的是明文经填充了的结果,byte类型
result=unpadding(data) #去掉填充,str类型
return result
总结上面的函数,在加解密方面,我们自定义的函数传参都是str,返回也是str;但Python的DES模块提供的函数,传入参数和返回参数都是byte。对于填充函数padding,传入str,返回byte;对于去填充函数unpadding,传入byte,返回str。
请求包加密
对HTTPS请求包的内容进行加密。body就是请求包中body的内容,是str类型,进入函数首先要调用json.loads(body)将str转成dict。
调用json模块的函数要先
import json
加密后要对body做url编码,调用parse.quote(body)也要先
from urllib import parse
req_encrypt(body)
def req_encrypt(body):
body_dict=json.loads(body) #body传入时是str,这里先转str为dict
data=body_dict['data'] #取字典中的data【键】对应的【值】,ps:因为这里是要加密明文,而明文中的data值又是字典类型,所以下面要将dict转str
data=json.dumps(data,ensure_ascii=False) #dict转str
data=des_encrypt(data,key) #调用上面的des_encrypt加密函数,输入参数为str,返回值也为str,所以这里得到的密文data是str
body_dict['data']=data #加密结果赋值给data键对应的值
body=json.dumps(body_dict) #将dict转回str得到已经加密的body
body='CONTENT_DATA='+parse.quote(body) #连接字符串,quote是用url编码body
return body
请求包解密
req_decrypt(body)
def req_decrypt(body):
body=parse.unquote(body)[13:] #从body的'CONTENT_DATA='后面开始取,调用parse.unquote()将url编码做解码,即%xx替换成单个字符,这里body是str类型
body_dict=json.loads(body) #str转dict
data=body_dict['data'] #取dict中的'data'【键】对应的【值】,这里data是密文是str
data=des_decrypt(data,key) #调用上面自定义的des_decrypt函数做DES解密,解密后得到str类型的data明文
data=json.loads(data) #str转dict
body_dict['data']=data #解密后的data赋给body中的'data'键,作为值
body=json.dumps(body_dict) #dict转回str
return body
总结以上函数,https的请求包中的body是str,且body在加密前、加密后都是str,在加密和解密时,因为要取出’data’键对应的值,所以都是先将body做str到dict的转换。
在加密时,data的明文是dict,加密处理前还要转一次str,加密后将密文重新赋给data,再把body转回str。
在解密时,data的密文是str,可以直接去调解密函数,解密后要先将明文data转成dict类型再重新赋给data,最后再把body转回str。
响应包解密
和请求包解密一个道理,就是body先转dict,取出data密文,解密得到data明文先转dict再重新赋给data,最后将body转回str。
def rsp_decrypt(body):
body_dict=json.loads(body)
data=body_dict['data'] #body_dict是dict,但'data'【键】的值是密文、是str
data=des_decrypt(data,key)
body_dict['data']=json.loads(data) #解密结果先转dict再赋回data
body=json.dumps(body_dict,ensure_ascii=False) #body_dict整体转str
return body
响应包加密
之前觉得响应包加密是服务端干的事儿,不用关心,但是后来意识到,我忽略了拦截响应包再修改响应包后放包的渗透测试常用操作……
响应包加密函数里执行的步骤几乎完全可以参考请求包加密。
def rsp_encrypt(body):
body_dict=json.loads(body)
data=body_dict['data'] #data是dict类型
data=json.dumps(data,ensure_ascii=False) #加密前先转str
data=des_encrypt(data,key)
body_dict['data']=data #加密后的data赋给'data'
body=json.dumps(body_dict,ensure_ascii=False) #body_dict整体转str
return body
class Burpy
最后顺便贴上想要调用burpy插件中Python加解密脚本的固定代码
记得要先在代码开头写上import traceback
class Burpy:
def __init__(self):
print('-----------')
pass
def _getmethod(self, header):
if "POST" in header['first_line']:
return 0
else:
return 1
def decrypt(self,header,body):
try:
meth = self._getmethod(header)
if meth==0:
body=req_decrypt(body)
if meth==1:
body=rsp_decrypt(body)
except Exception as err:
print(err)
traceback.print_exc() #import traceback
pass
return header,body
def encrypt(self,header,body):
try:
meth = self._getmethod(header)
if meth==0:
body=req_encrypt(body)
if meth==1:
body=rsp_encrypt(body)
except Exception as err:
print(err)
traceback.print_exc()
pass
return header,body
备注
对密文解密后得到的明文再加密,得到的密文和原始密文不同,这是因为原始密文解密后得到的明文会多些空格啥的,导致再次加密后得到的密文和原始密文不一致了,但不用担心这个事情,因为经试验发现,再对该密文(原始密文解密再加密得到的那个密文)解密,还是可以得到关键内容一致的明文,只是空格的区别(我知道我在说废话哈哈哈
具体如下:
原始密文解密:
解密后的明文再加密后,再解密:
可见密文不同但得到的明文只是在换行或者空格的位置上有点区别,所展现的关键内容是一致的。
更多推荐
所有评论(0)