1
- #!/usr/bin/env python
2
1
import os
3
- from base64 import b64encode
4
2
from base64 import b64decode
3
+ from base64 import b64encode
5
4
6
- from Cryptodome import Random
7
- from Cryptodome .Cipher import AES
5
+ from cryptography .hazmat .backends import default_backend
6
+ from cryptography .hazmat .primitives .ciphers import Cipher
7
+ from cryptography .hazmat .primitives .ciphers import algorithms
8
+ from cryptography .hazmat .primitives .ciphers import modes
8
9
9
- __author__ = 'rolandh'
10
10
11
11
POSTFIX_MODE = {
12
- " cbc" : AES . MODE_CBC ,
13
- " cfb" : AES . MODE_CFB ,
14
- " ecb" : AES . MODE_CFB ,
12
+ ' cbc' : modes . CBC ,
13
+ ' cfb' : modes . CFB ,
14
+ ' ecb' : modes . ECB ,
15
15
}
16
16
17
- BLOCK_SIZE = 16
17
+ AES_BLOCK_SIZE = int ( algorithms . AES . block_size / 8 )
18
18
19
19
20
20
class AESCipher (object ):
21
- def __init__ (self , key , iv = "" ):
21
+ def __init__ (self , key , iv = None ):
22
22
"""
23
-
24
23
:param key: The encryption key
25
24
:param iv: Init vector
26
25
:return: AESCipher instance
27
26
"""
28
27
self .key = key
29
28
self .iv = iv
30
29
31
- def build_cipher (self , iv = "" , alg = " aes_128_cbc" ):
30
+ def build_cipher (self , iv = None , alg = ' aes_128_cbc' ):
32
31
"""
33
32
:param iv: init vector
34
33
:param alg: cipher algorithm
35
34
:return: A Cipher instance
36
35
"""
37
- typ , bits , cmode = alg .split ("_" )
36
+ typ , bits , cmode = alg .lower ().split ('_' )
37
+ bits = int (bits )
38
38
39
39
if not iv :
40
40
if self .iv :
41
41
iv = self .iv
42
42
else :
43
- iv = Random .new ().read (AES .block_size )
44
- else :
45
- assert len (iv ) == AES .block_size
43
+ iv = os .urandom (AES_BLOCK_SIZE )
46
44
47
- if bits not in ["128" , "192" , "256" ]:
48
- raise Exception ("Unsupported key length" )
49
- try :
50
- assert len (self .key ) == int (bits ) >> 3
51
- except AssertionError :
52
- raise Exception ("Wrong Key length" )
45
+ if len (iv ) != AES_BLOCK_SIZE :
46
+ raise Exception ('Wrong iv size: {}' .format (len (iv )))
47
+
48
+ if bits not in algorithms .AES .key_sizes :
49
+ raise Exception ('Unsupported key length: {}' .format (bits ))
50
+
51
+ if len (self .key ) != bits / 8 :
52
+ raise Exception ('Wrong Key length: {}' .format (len (self .key )))
53
53
54
54
try :
55
- return AES . new ( self . key , POSTFIX_MODE [cmode ], iv ), iv
55
+ mode = POSTFIX_MODE [cmode ]
56
56
except KeyError :
57
- raise Exception ("Unsupported chaining mode" )
57
+ raise Exception ('Unsupported chaining mode: {}' .format (cmode ))
58
+
59
+ cipher = Cipher (
60
+ algorithms .AES (self .key ),
61
+ mode (iv ),
62
+ backend = default_backend ())
58
63
64
+ return cipher , iv
59
65
60
- def encrypt (self , msg , iv = None , alg = " aes_128_cbc" , padding = " PKCS#7" ,
61
- b64enc = True , block_size = BLOCK_SIZE ):
66
+ def encrypt (self , msg , iv = None , alg = ' aes_128_cbc' , padding = ' PKCS#7' ,
67
+ b64enc = True , block_size = AES_BLOCK_SIZE ):
62
68
"""
63
69
:param key: The encryption key
64
70
:param iv: init vector
@@ -69,57 +75,71 @@ def encrypt(self, msg, iv=None, alg="aes_128_cbc", padding="PKCS#7",
69
75
:return: The encrypted message
70
76
"""
71
77
72
- if padding == " PKCS#7" :
78
+ if padding == ' PKCS#7' :
73
79
_block_size = block_size
74
- elif padding == " PKCS#5" :
80
+ elif padding == ' PKCS#5' :
75
81
_block_size = 8
76
82
else :
77
83
_block_size = 0
78
84
79
85
if _block_size :
80
86
plen = _block_size - (len (msg ) % _block_size )
81
- c = chr (plen )
82
- msg += c * plen
87
+ c = chr (plen ). encode ()
88
+ msg += c * plen
83
89
84
90
cipher , iv = self .build_cipher (iv , alg )
85
- cmsg = iv + cipher .encrypt (msg )
91
+ encryptor = cipher .encryptor ()
92
+ cmsg = iv + encryptor .update (msg ) + encryptor .finalize ()
93
+
86
94
if b64enc :
87
- return b64encode (cmsg )
95
+ enc_msg = b64encode (cmsg )
88
96
else :
89
- return cmsg
97
+ enc_msg = cmsg
90
98
99
+ return enc_msg
91
100
92
- def decrypt (self , msg , iv = None , alg = "aes_128_cbc" , padding = "PKCS#7" , b64dec = True ):
101
+ def decrypt (self , msg , iv = None , alg = 'aes_128_cbc' , padding = 'PKCS#7' ,
102
+ b64dec = True ):
93
103
"""
94
104
:param key: The encryption key
95
105
:param iv: init vector
96
106
:param msg: Base64 encoded message to be decrypted
97
107
:return: The decrypted message
98
108
"""
99
- if b64dec :
100
- data = b64decode (msg )
101
- else :
102
- data = msg
109
+ data = b64decode (msg ) if b64dec else msg
103
110
104
- _iv = data [:AES . block_size ]
111
+ _iv = data [:AES_BLOCK_SIZE ]
105
112
if iv :
106
113
assert iv == _iv
107
114
cipher , iv = self .build_cipher (iv , alg = alg )
108
- res = cipher .decrypt (data )[AES .block_size :]
109
- if padding in ["PKCS#5" , "PKCS#7" ]:
110
- res = res [:- ord (res [- 1 ])]
115
+ decryptor = cipher .decryptor ()
116
+ res = decryptor .update (data )[AES_BLOCK_SIZE :] + decryptor .finalize ()
117
+ if padding in ['PKCS#5' , 'PKCS#7' ]:
118
+ idx = bytearray (res )[- 1 ]
119
+ res = res [:- idx ]
111
120
return res
112
121
113
- if __name__ == "__main__" :
114
- key_ = "1234523451234545" # 16 byte key
122
+
123
+ def run_test ():
124
+ key = b'1234523451234545' # 16 byte key
125
+ iv = os .urandom (AES_BLOCK_SIZE )
115
126
# Iff padded, the message doesn't have to be multiple of 16 in length
116
- msg_ = "ToBeOrNotTobe W.S."
117
- aes = AESCipher (key_ )
118
- iv_ = os .urandom (16 )
119
- encrypted_msg = aes .encrypt (key_ , msg_ , iv_ )
120
- txt = aes .decrypt (key_ , encrypted_msg , iv_ )
121
- assert txt == msg_
122
-
123
- encrypted_msg = aes .encrypt (key_ , msg_ , 0 )
124
- txt = aes .decrypt (key_ , encrypted_msg , 0 )
125
- assert txt == msg_
127
+ original_msg = b'ToBeOrNotTobe W.S.'
128
+ aes = AESCipher (key )
129
+
130
+ encrypted_msg = aes .encrypt (original_msg , iv )
131
+ decrypted_msg = aes .decrypt (encrypted_msg , iv )
132
+ assert decrypted_msg == original_msg
133
+
134
+ encrypted_msg = aes .encrypt (original_msg )
135
+ decrypted_msg = aes .decrypt (encrypted_msg )
136
+ assert decrypted_msg == original_msg
137
+
138
+ aes = AESCipher (key , iv )
139
+ encrypted_msg = aes .encrypt (original_msg )
140
+ decrypted_msg = aes .decrypt (encrypted_msg )
141
+ assert decrypted_msg == original_msg
142
+
143
+
144
+ if __name__ == '__main__' :
145
+ run_test ()
0 commit comments