刚开始pyhton自己脚本加解密,网上很多方法,都能实现
# -*- coding: utf-8 -*-
# @Time : 2019/3/11 11:14
# @Author : guigle
# @File : AES_CBC.py
# @Software: PyCharm
import base64
from Crypto.Cipher import AES
from binascii import b2a_base64, a2b_base64
# from binascii import b2a_hex, a2b_hex
class PrpCrypt(object):
def __init__(self, key, iv):
self.key = key.encode('utf-8')
self.iv = iv
self.mode = AES.MODE_CBC
# 指定填充
self.bs = 16
self.PADDING = lambda s: s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
# self.PADDING = lambda s: s + ((self.bs - len(s) % self.bs)*' ').encode('utf-8')
# 加密函数,如果text不足16位就用空格补足为16位,
# 如果大于16当时不是16的倍数,那就补足为16的倍数。
def encrypt(self, text):
# text = text.encode('utf-8')
# cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn') # 偏移量必须是16位
cryptor = AES.new(self.key, self.mode, self.iv) # 偏移量必须是16位
text = text.encode('utf-8')
tt = self.PADDING(text)
crypt = cryptor.encrypt(tt)
crypted_str = base64.b64encode(crypt)
# crypted_str = b2a_base64(crypt)
result = crypted_str.decode()
# 这里密钥key 长度必须为16(AES-128),
# 24(AES-192),或者32 (AES-256)Bytes 长度
# 目前AES-128 足够目前使用
# length = 16
# count = len(text)
# if count < length:
# add = (length - count)
# # \0 backspace
# # text = text + ('\0' * add)
# text = text + ('\0' * add).encode('utf-8')
# elif count > length:
# add = (length - (count % length))
# # text = text + ('\0' * add)
# text = text + ('\0' * add).encode('utf-8')
# self.ciphertext = cryptor.encrypt(text)
# 因为AES加密时候得到的字符串不一定是ascii字符集的,输出到终端或者保存时候可能存在问题
# 所以这里统一把加密后的字符串转化为16进制字符串b2a_hex(self.ciphertext)
# 当然也可以转换为base64加密的内容,可以使用b2a_base64(self.ciphertext)
# return b2a_base64(self.ciphertext) # b2a_hex
return result # b2a_hex
# 解密后,去掉补足的空格用strip() 去掉
def decrypt(self, text):
# cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn') # 偏移量必须是16位
cryptor = AES.new(self.key, self.mode, self.iv) # 偏移量必须是16位
plain_text = cryptor.decrypt(a2b_base64(text)) # a2b_hex
# return plain_text.rstrip('\0')
return bytes.decode(plain_text).rstrip('\0')
if __name__ == '__main__':
# 初始化密钥 必须是16位 这个key和iv是去申请获取的
# pc = PrpCrypt(key,iv)
pc = PrpCrypt('TdoO7R7353nT2OWs', 'FxuveEaw8VPdg9lJ'.encode('utf-8'))
e = pc.encrypt("颜老狗") # 对某字符串加密
print("加密:", e, type(e))
# e2 = e.decode('utf-8')
# print("加密解码", e2, type(e2))
d = pc.decrypt('RpDvw0Jdh6lzCzhW4giqsg==') # 解密
print("解密:", d, type(d))
# d2 = d.decode("utf-8")
# print("解密:", d2, type(d2))
然后java自己脚本的加解密也没问题;但是出现python加解密自己能实现,也能解密java的加密内容。但是java那边解密不了我这边的,但在在线转换上我的是没有问题的。
后来换了种方法,以为可以了,实际上只是实现了英文的可以,由于一个英文对应1byte,一个中文对应2byte,于是用了如下方法.
由于java的PKCS5填充机制与python不同,所以用如下方式填充
# -*- coding: utf-8 -*-
# @Time : 2019/3/11 11:14
# @Author : guigle
# @File : AES_CBC.py
# @Software: PyCharm
import base64
import re
from Crypto.Cipher import AES
from binascii import b2a_base64, a2b_base64
# from binascii import b2a_hex, a2b_hex
class PrpCrypt(object):
def __init__(self, key, iv):
self.key = key.encode('utf-8')
self.iv = iv
self.mode = AES.MODE_CBC
# 指定填充
self.bs = 16
self.PADDING01 = lambda s: s + (self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs)
self.PADDING02 = lambda s: s + bytes((self.bs - len(s) % self.bs) * chr(self.bs - len(s) % self.bs), encoding='utf8')
# self.PADDING02 = lambda s: s + ((self.bs - len(s) % self.bs)*' ').encode('utf-8')
def encrypt(self, text):
# text = text.encode('utf-8')
# cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn') # 偏移量必须是16位
cryptor = AES.new(self.key, self.mode, self.iv) # 偏移量必须是16位
contents = u'%s' % text
zhmodel = re.compile(u'[\u4e00-\u9fa5]') # 检查中文
# zhmodel = re.compile(u'[^\u4e00-\u9fa5]') #检查非中文
match = zhmodel.search(contents)
if match:
text = text.encode('utf-8')
tt = self.PADDING02(text)
crypt = cryptor.encrypt(tt)
crypted_str = base64.b64encode(crypt)
# crypted_str = b2a_base64(crypt)
result = crypted_str.decode()
return result
else:
tt = self.PADDING01(text)
crypt = cryptor.encrypt(tt.encode("utf-8"))
crypted_str = base64.b64encode(crypt)
# crypted_str = b2a_base64(crypt)
result = crypted_str.decode()
return result # b2a_hex
# 解密后,去掉补足的空格用strip() 去掉
def decrypt(self, text):
# cryptor = AES.new(self.key, self.mode, b'0123qtwhdg1230mn') # 偏移量必须是16位
cryptor = AES.new(self.key, self.mode, self.iv) # 偏移量必须是16位
plain_text = cryptor.decrypt(a2b_base64(text)) # a2b_hex
# return plain_text.rstrip('\0')
return bytes.decode(plain_text).rstrip('\0')
# if __name__ == '__main__':
# # 初始化密钥 必须是16位 这个key和iv是去申请获取的
# # pc = PrpCrypt(key,iv)
# pc = PrpCrypt('TdoO7R7353nT2OWs', 'FxuveEaw8VPdg9lJ'.encode('utf-8'))
# e = pc.encrypt("dsbltb") # 对某字符串加密
# print("加密:", e, type(e))
#
# # e2 = e.decode('utf-8')
# # print("加密解码", e2, type(e2))
#
# d = pc.decrypt('RpDvw0Jdh6lzCzhW4giqsg==') # 解密
# print("解密:", d, type(d))
# d2 = d.decode("utf-8")
# print("解密:", d2, type(d2))
java的PKCS5和PKCS7填充机制
参考链接:https://blog.csdn.net/chary8088/article/details/21185187
拓展:
最近做到了关于加密和解密的部分。
使用算法AES的时候,涉及到数据填充的部分,数据的填充有很多种方案,用的比较多的有pkcs#5,pkcs#7,
下面的都是从网上转来的。结论就是在AES 的使用中,pkcs#5填充和pkcs#7填充没有任何区别。
PKCS #7 填充字符串由一个字节序列组成,每个字节填充该填充字节序列的长度。
假定块长度为 8,数据长度为 9,
数据: FF FF FF FF FF FF FF FF FF
PKCS7 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07简单地说, PKCS5, PKCS7和SSL3, 以及CMS(Cryptographic Message Syntax)
有如下相同的特点:
1)填充的字节都是一个相同的字节
2)该字节的值,就是要填充的字节的个数如果要填充8个字节,那么填充的字节的值就是0×8;
要填充7个字节,那么填入的值就是0×7;…
如果只填充1个字节,那么填入的值就是0×1;
这种填充方法也叫PKCS5, 恰好8个字节时还要补8个字节的0×08
正是这种即使恰好是8个字节也需要再补充字节的规定,可以让解密的数据很确定无误的移除多余的字节。
标准
PKCS #7: Cryptographic Message Syntax
在 10.3节中讲到了上面提到的填充算法, 对Block Size并没有做规定
PKCS #5: Password-Based Cryptography Specification
在6.1.1 中对 填充做了说明
但是因为该标准 只讨论了 8字节(64位) 块的加密, 对其他块大小没有做说明
其 填充算法跟 PKCS7是一样的后来 AES 等算法, 把BlockSize扩充到 16个字节
比如, Java中
Cipher.getInstance(“AES/CBC/PKCS5Padding”)
这个加密模式
跟C#中的
RijndaelManaged cipher = new RijndaelManaged();
cipher.KeySize = 128;
cipher.BlockSize = 128;
cipher.Mode = CipherMode.CBC;
cipher.Padding = PaddingMode.PKCS7;
的加密模式是一样的因为AES并没有64位的块, 如果采用PKCS5, 那么实质上就是采用PKCS7