Python DES3加解密

python实现DES3加密

des加密,是一种对称加密算法,一种比较传统的加密方式;3DES(又称Triple DES),是进行了三重数据加密,即:每个数据块进行了三次DES加密算法,故比DES加密更为安全,更难破解。

DES加密的密钥长度为8,而DES3的密钥长度为24.

下面的代码实现是DES3,而DES加密只要把相关DES3的部分替换为DES即可,DES包的导入和方法调用与DES是一样,但是需要注意密钥长度

与AES的加密实现方式基本相同,区别点在于:

  1. DES3需要把待加密文本补齐为8的倍数,AES需要把待加密文本补齐为16的倍数;
  2. DES3密钥长度为24,AES的密钥长度为32。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import base64
from Crypto.Cipher import DES3


# DES3加密解密模块
class DES3Util:

# 每块8的bytes长度
__BLOCK_SIZE_8 = DES3.block_size

@staticmethod
def add_to_8(text): # 转bytes 并 补齐为8的倍数
b_text = text.encode("utf-8")
x = DES3Util.__BLOCK_SIZE_8 - (len(b_text) % DES3Util.__BLOCK_SIZE_8)
if x != 0:
text = text + chr(x) * x
return text.encode('utf-8')

@staticmethod
def encrypt(text: str, key: bytes, mode: str="ECB", iv: bytes=None):
"""
DES 加密方法
:param text: 要加密的字符串
:param key: 密钥
:param mode: 模式,CBC or ECB
:param iv: 偏移量(ECB模式没有偏移量), 长度必须为8位
:return: 返回加密的数据
"""
des_mode = DES3.MODE_CBC if mode == "CBC" else DES3.MODE_ECB
key = key[:24] # DES3密钥长度为24
if iv and mode == "CBC":
cipher = DES3.new(key=key, mode=des_mode, iv=iv)
else:
cipher = DES3.new(key, des_mode)
text = DES3Util.add_to_8(text)
msg = cipher.encrypt(text)
msg = base64.b64encode(msg)
return msg

@staticmethod
def decrypt(en_str: str, key: bytes, mode: str="ECB", iv: bytes=None):
"""
DES 解密方法
:param en_str: 要解密的字符串
:param key: 密钥
:param mode: 模式,CBC or ECB
:param iv: 偏移量(ECB模式没有偏移量)
:return:
"""
des_mode = DES3.MODE_CBC if mode == "CBC" else DES3.MODE_ECB
key = key[:24] # DES3密钥长度为24
if iv and mode == "CBC":
cipher = DES3.new(key, des_mode, iv)
else:
cipher = DES3.new(key, des_mode)
decrypt_bytes = base64.b64decode(en_str)
msg = cipher.decrypt(decrypt_bytes)
msg = msg.decode("utf-8")
unpadding = ord(msg[len(msg)-1])
return msg[0:len(msg)-unpadding]


# 测试
if __name__ == "__main__":
key = b"0E6BDB8DDA7363346EE6145566CDF904"
iv = b"12345678"
res = DESUtil.encrypt('{"q":"","xydm":"","time":"","pageStart":1,"pageSize":10,"sign":"c16fd1befc9fb418ce557a879fd7f7e0fadd73058b992febdd178279e3e2334a","salt":"PSNh1FT+nfFOLc8W7Ibkb5tVaHM/p9RA+nxD5cSYkZ4f5LSAxH1vYkUUUoT2RCVA+9YsRU2hn3OBVbdlyqfl9A=="}', key, "CBC", iv)
print(res)

key = b'0E6BDB8DDA7363346EE6145566CDF904'
res = DESUtil.decrypt(res.decode('utf-8'), key, mode='CBC', iv=b'12345678')
print(res)

# 输出
b'6i/xb/cddI2DoJVmGQNp+J14myGaQrcau6Fo264HT6oOta+AJ2Z/+QGZ8PiqyRTkrFK5GiARYXkoI+8ohC7ba4DM+C+doAtF8vJznUjv+j2CLT0kdQeqWvf5HUIEqUmxoEWsSI/I/Giku3XVe5QxN6O9OvfJP831wWfZy0aGI574hEfZhGpgth9aCmKdXji4Nc0S1hHCJDuAtPbmZH7lc2Ph4Bn32BagarBMWWXVxaZPnmEk0MGXQGtd+DdE5Gt4LPVd2VmOsw3LqyPv05FQ9OdOZaVbhdeNkor2rMm5kXve+LO3+3H6iQ=='

{"q":"","xydm":"","time":"","pageStart":1,"pageSize":10,"sign":"c16fd1befc9fb418ce557a879fd7f7e0fadd73058b992febdd178279e3e2334a","salt":"PSNh1FT+nfFOLc8W7Ibkb5tVaHM/p9RA+nxD5cSYkZ4f5LSAxH1vYkUUUoT2RCVA+9YsRU2hn3OBVbdlyqfl9A=="}

注意:这里我在解密的时候,加了两行处理代码

1
2
unpadding = ord(msg[len(msg)-1])
msg[0:len(msg)-unpadding]

上面提到了,在文本加密之前,都需要把文本补成8的倍数,所以如果在加密之前进行过补齐操作,解密之后,末尾会多出我们补进去的字符。所以我们需要去掉补进去的字符。

我们这里补齐的逻辑是,先计算需要补进去的字符长度记为x,然后补进去的字符是x个ASCII值为x的字符。所以解密后,先计算最后一个字符的ASCII值,也就知道补了几个字符,最后截断即可。

那么有个问题,如果原文本正好是8的倍数,不需要补,那这里面的截断操作不就有问题了?实际上,即使原文本长度正好为8的倍数,也是会在最后补的,直接补8个字符。

AES加密也可以利用同样的方式删除加密前补进去的字符。