Skip to content

Commit a7763cd

Browse files
committed
Deprecate AESCipher and aes.py module
aes.py is deprecated and will be completely removed in a following release. Users should switch to saml2.cryptography.symmetric instead. Signed-off-by: Ivan Kanakarakis <ivan.kanak@gmail.com>
1 parent 912a1b3 commit a7763cd

File tree

2 files changed

+136
-99
lines changed

2 files changed

+136
-99
lines changed

src/saml2/aes.py

Lines changed: 12 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,18 @@
1-
import os
2-
from base64 import b64decode
3-
from base64 import b64encode
1+
import warnings as _warnings
42

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
3+
from saml2.cryptography.symmetric import AESCipher as _AESCipher
94

105

11-
POSTFIX_MODE = {
12-
'cbc': modes.CBC,
13-
'cfb': modes.CFB,
14-
}
6+
_deprecation_msg = (
7+
'{name} {type} is deprecated. '
8+
'It will be removed in the next version. '
9+
'Use saml2.cryptography.symmetric instead.'
10+
).format(name=__name__, type='module')
1511

16-
AES_BLOCK_SIZE = int(algorithms.AES.block_size / 8)
12+
_warnings.simplefilter('default')
13+
_warnings.warn(_deprecation_msg, DeprecationWarning)
1714

1815

19-
class AESCipher(object):
20-
def __init__(self, key):
21-
"""
22-
:param key: The encryption key
23-
:return: AESCipher instance
24-
"""
25-
self.key = key
26-
27-
def build_cipher(self, alg='aes_128_cbc'):
28-
"""
29-
:param alg: cipher algorithm
30-
:return: A Cipher instance
31-
"""
32-
typ, bits, cmode = alg.lower().split('_')
33-
bits = int(bits)
34-
iv = os.urandom(AES_BLOCK_SIZE)
35-
36-
if len(iv) != AES_BLOCK_SIZE:
37-
raise Exception('Wrong iv size: {}'.format(len(iv)))
38-
39-
if bits not in algorithms.AES.key_sizes:
40-
raise Exception('Unsupported key length: {}'.format(bits))
41-
42-
if len(self.key) != bits / 8:
43-
raise Exception('Wrong Key length: {}'.format(len(self.key)))
44-
45-
try:
46-
mode = POSTFIX_MODE[cmode]
47-
except KeyError:
48-
raise Exception('Unsupported chaining mode: {}'.format(cmode))
49-
50-
cipher = Cipher(
51-
algorithms.AES(self.key),
52-
mode(iv),
53-
backend=default_backend())
54-
55-
return cipher, iv
56-
57-
def encrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64enc=True,
58-
block_size=AES_BLOCK_SIZE):
59-
"""
60-
:param key: The encryption key
61-
:param msg: Message to be encrypted
62-
:param padding: Which padding that should be used
63-
:param b64enc: Whether the result should be base64encoded
64-
:param block_size: If PKCS#7 padding which block size to use
65-
:return: The encrypted message
66-
"""
67-
68-
if padding == 'PKCS#7':
69-
_block_size = block_size
70-
elif padding == 'PKCS#5':
71-
_block_size = 8
72-
else:
73-
_block_size = 0
74-
75-
if _block_size:
76-
plen = _block_size - (len(msg) % _block_size)
77-
c = chr(plen).encode()
78-
msg += c * plen
79-
80-
cipher, iv = self.build_cipher(alg)
81-
encryptor = cipher.encryptor()
82-
cmsg = iv + encryptor.update(msg) + encryptor.finalize()
83-
84-
if b64enc:
85-
enc_msg = b64encode(cmsg)
86-
else:
87-
enc_msg = cmsg
88-
89-
return enc_msg
90-
91-
def decrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64dec=True):
92-
"""
93-
:param key: The encryption key
94-
:param msg: Base64 encoded message to be decrypted
95-
:return: The decrypted message
96-
"""
97-
data = b64decode(msg) if b64dec else msg
98-
99-
cipher, iv = self.build_cipher(alg=alg)
100-
decryptor = cipher.decryptor()
101-
res = decryptor.update(data)[AES_BLOCK_SIZE:] + decryptor.finalize()
102-
if padding in ['PKCS#5', 'PKCS#7']:
103-
idx = bytearray(res)[-1]
104-
res = res[:-idx]
105-
return res
16+
AESCipher = _AESCipher
17+
POSTFIX_MODE = _AESCipher.POSTFIX_MODE
18+
AES_BLOCK_SIZE = _AESCipher.AES_BLOCK_SIZE

src/saml2/cryptography/symmetric.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,16 @@
44
library. Reference: https://cryptography.io/en/latest/fernet/
55
"""
66

7+
import base64 as _base64
8+
import os as _os
9+
import warnings as _warnings
10+
711
import cryptography.fernet as _fernet
12+
import cryptography.hazmat.backends as _backends
13+
import cryptography.hazmat.primitives.ciphers as _ciphers
14+
15+
16+
_warnings.simplefilter('default')
817

918

1019
class Default(object):
@@ -43,3 +52,118 @@ def decrypt(self, ciphertext):
4352
"""
4453
plaintext = self._symmetric.decrypt(ciphertext)
4554
return plaintext
55+
56+
57+
class AESCipher(object):
58+
"""[deprecated] Symmetric cryptography method using AES.
59+
60+
The default parameter set is AES 128bit in CBC mode.
61+
"""
62+
63+
POSTFIX_MODE = {
64+
'cbc': _ciphers.modes.CBC,
65+
'cfb': _ciphers.modes.CFB,
66+
}
67+
68+
AES_BLOCK_SIZE = int(_ciphers.algorithms.AES.block_size / 8)
69+
70+
@classmethod
71+
def _deprecation_notice(cls):
72+
"""Warn about deprecation of this class."""
73+
_deprecation_msg = (
74+
'{name} {type} is deprecated. '
75+
'It will be removed in the next version. '
76+
'Use saml2.cryptography.symmetric instead.'
77+
).format(name=cls.__name__, type=type(cls).__name__)
78+
_warnings.warn(_deprecation_msg, DeprecationWarning)
79+
80+
def __init__(self, key):
81+
"""
82+
:param key: The encryption key
83+
:return: AESCipher instance
84+
"""
85+
self.__class__._deprecation_notice()
86+
self.key = key
87+
88+
def build_cipher(self, alg='aes_128_cbc'):
89+
"""
90+
:param alg: cipher algorithm
91+
:return: A Cipher instance
92+
"""
93+
self.__class__._deprecation_notice()
94+
typ, bits, cmode = alg.lower().split('_')
95+
bits = int(bits)
96+
iv = _os.urandom(self.AES_BLOCK_SIZE)
97+
98+
if len(iv) != self.AES_BLOCK_SIZE:
99+
raise Exception('Wrong iv size: {}'.format(len(iv)))
100+
101+
if bits not in _ciphers.algorithms.AES.key_sizes:
102+
raise Exception('Unsupported key length: {}'.format(bits))
103+
104+
if len(self.key) != bits / 8:
105+
raise Exception('Wrong Key length: {}'.format(len(self.key)))
106+
107+
try:
108+
mode = self.POSTFIX_MODE[cmode]
109+
except KeyError:
110+
raise Exception('Unsupported chaining mode: {}'.format(cmode))
111+
112+
cipher = _ciphers.Cipher(
113+
_ciphers.algorithms.AES(self.key),
114+
mode(iv),
115+
backend=_backends.default_backend())
116+
117+
return cipher, iv
118+
119+
def encrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64enc=True,
120+
block_size=AES_BLOCK_SIZE):
121+
"""
122+
:param key: The encryption key
123+
:param msg: Message to be encrypted
124+
:param padding: Which padding that should be used
125+
:param b64enc: Whether the result should be base64encoded
126+
:param block_size: If PKCS#7 padding which block size to use
127+
:return: The encrypted message
128+
"""
129+
self.__class__._deprecation_notice()
130+
if padding == 'PKCS#7':
131+
_block_size = block_size
132+
elif padding == 'PKCS#5':
133+
_block_size = 8
134+
else:
135+
_block_size = 0
136+
137+
if _block_size:
138+
plen = _block_size - (len(msg) % _block_size)
139+
c = chr(plen).encode()
140+
msg += c * plen
141+
142+
cipher, iv = self.build_cipher(alg)
143+
encryptor = cipher.encryptor()
144+
cmsg = iv + encryptor.update(msg) + encryptor.finalize()
145+
146+
if b64enc:
147+
enc_msg = _base64.b64encode(cmsg)
148+
else:
149+
enc_msg = cmsg
150+
151+
return enc_msg
152+
153+
def decrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64dec=True):
154+
"""
155+
:param key: The encryption key
156+
:param msg: Base64 encoded message to be decrypted
157+
:return: The decrypted message
158+
"""
159+
self.__class__._deprecation_notice()
160+
data = _base64.b64decode(msg) if b64dec else msg
161+
162+
cipher, iv = self.build_cipher(alg=alg)
163+
decryptor = cipher.decryptor()
164+
res = decryptor.update(data)[self.AES_BLOCK_SIZE:]
165+
res += decryptor.finalize()
166+
if padding in ['PKCS#5', 'PKCS#7']:
167+
idx = bytearray(res)[-1]
168+
res = res[:-idx]
169+
return res

0 commit comments

Comments
 (0)