diff options
author | Ivan Kanakarakis <ivan.kanak@gmail.com> | 2018-07-17 01:20:36 +0300 |
---|---|---|
committer | Ivan Kanakarakis <ivan.kanak@gmail.com> | 2018-08-02 15:06:10 +0300 |
commit | a7763cdee88b39fb812df66e63c16063c468f006 (patch) | |
tree | ca39e58ebf15a8e86dc13c2e6f6274d3e45b3a5b | |
parent | 912a1b34402ca26c2fb86b57aeebbdc7685efa2d (diff) | |
download | pysaml2-a7763cdee88b39fb812df66e63c16063c468f006.tar.gz |
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>
-rw-r--r-- | src/saml2/aes.py | 111 | ||||
-rw-r--r-- | src/saml2/cryptography/symmetric.py | 124 |
2 files changed, 136 insertions, 99 deletions
diff --git a/src/saml2/aes.py b/src/saml2/aes.py index 54808e67..d58e34e5 100644 --- a/src/saml2/aes.py +++ b/src/saml2/aes.py @@ -1,105 +1,18 @@ -import os -from base64 import b64decode -from base64 import b64encode +import warnings as _warnings -from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.ciphers import Cipher -from cryptography.hazmat.primitives.ciphers import algorithms -from cryptography.hazmat.primitives.ciphers import modes +from saml2.cryptography.symmetric import AESCipher as _AESCipher -POSTFIX_MODE = { - 'cbc': modes.CBC, - 'cfb': modes.CFB, -} +_deprecation_msg = ( + '{name} {type} is deprecated. ' + 'It will be removed in the next version. ' + 'Use saml2.cryptography.symmetric instead.' +).format(name=__name__, type='module') -AES_BLOCK_SIZE = int(algorithms.AES.block_size / 8) +_warnings.simplefilter('default') +_warnings.warn(_deprecation_msg, DeprecationWarning) -class AESCipher(object): - def __init__(self, key): - """ - :param key: The encryption key - :return: AESCipher instance - """ - self.key = key - - def build_cipher(self, alg='aes_128_cbc'): - """ - :param alg: cipher algorithm - :return: A Cipher instance - """ - typ, bits, cmode = alg.lower().split('_') - bits = int(bits) - iv = os.urandom(AES_BLOCK_SIZE) - - if len(iv) != AES_BLOCK_SIZE: - raise Exception('Wrong iv size: {}'.format(len(iv))) - - if bits not in algorithms.AES.key_sizes: - raise Exception('Unsupported key length: {}'.format(bits)) - - if len(self.key) != bits / 8: - raise Exception('Wrong Key length: {}'.format(len(self.key))) - - try: - mode = POSTFIX_MODE[cmode] - except KeyError: - raise Exception('Unsupported chaining mode: {}'.format(cmode)) - - cipher = Cipher( - algorithms.AES(self.key), - mode(iv), - backend=default_backend()) - - return cipher, iv - - def encrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64enc=True, - block_size=AES_BLOCK_SIZE): - """ - :param key: The encryption key - :param msg: Message to be encrypted - :param padding: Which padding that should be used - :param b64enc: Whether the result should be base64encoded - :param block_size: If PKCS#7 padding which block size to use - :return: The encrypted message - """ - - if padding == 'PKCS#7': - _block_size = block_size - elif padding == 'PKCS#5': - _block_size = 8 - else: - _block_size = 0 - - if _block_size: - plen = _block_size - (len(msg) % _block_size) - c = chr(plen).encode() - msg += c * plen - - cipher, iv = self.build_cipher(alg) - encryptor = cipher.encryptor() - cmsg = iv + encryptor.update(msg) + encryptor.finalize() - - if b64enc: - enc_msg = b64encode(cmsg) - else: - enc_msg = cmsg - - return enc_msg - - def decrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64dec=True): - """ - :param key: The encryption key - :param msg: Base64 encoded message to be decrypted - :return: The decrypted message - """ - data = b64decode(msg) if b64dec else msg - - cipher, iv = self.build_cipher(alg=alg) - decryptor = cipher.decryptor() - res = decryptor.update(data)[AES_BLOCK_SIZE:] + decryptor.finalize() - if padding in ['PKCS#5', 'PKCS#7']: - idx = bytearray(res)[-1] - res = res[:-idx] - return res +AESCipher = _AESCipher +POSTFIX_MODE = _AESCipher.POSTFIX_MODE +AES_BLOCK_SIZE = _AESCipher.AES_BLOCK_SIZE diff --git a/src/saml2/cryptography/symmetric.py b/src/saml2/cryptography/symmetric.py index 93d9cdf8..16df21f3 100644 --- a/src/saml2/cryptography/symmetric.py +++ b/src/saml2/cryptography/symmetric.py @@ -4,7 +4,16 @@ The default symmetric cryptography method used is Fernet by the cryptography library. Reference: https://cryptography.io/en/latest/fernet/ """ +import base64 as _base64 +import os as _os +import warnings as _warnings + import cryptography.fernet as _fernet +import cryptography.hazmat.backends as _backends +import cryptography.hazmat.primitives.ciphers as _ciphers + + +_warnings.simplefilter('default') class Default(object): @@ -43,3 +52,118 @@ class Default(object): """ plaintext = self._symmetric.decrypt(ciphertext) return plaintext + + +class AESCipher(object): + """[deprecated] Symmetric cryptography method using AES. + + The default parameter set is AES 128bit in CBC mode. + """ + + POSTFIX_MODE = { + 'cbc': _ciphers.modes.CBC, + 'cfb': _ciphers.modes.CFB, + } + + AES_BLOCK_SIZE = int(_ciphers.algorithms.AES.block_size / 8) + + @classmethod + def _deprecation_notice(cls): + """Warn about deprecation of this class.""" + _deprecation_msg = ( + '{name} {type} is deprecated. ' + 'It will be removed in the next version. ' + 'Use saml2.cryptography.symmetric instead.' + ).format(name=cls.__name__, type=type(cls).__name__) + _warnings.warn(_deprecation_msg, DeprecationWarning) + + def __init__(self, key): + """ + :param key: The encryption key + :return: AESCipher instance + """ + self.__class__._deprecation_notice() + self.key = key + + def build_cipher(self, alg='aes_128_cbc'): + """ + :param alg: cipher algorithm + :return: A Cipher instance + """ + self.__class__._deprecation_notice() + typ, bits, cmode = alg.lower().split('_') + bits = int(bits) + iv = _os.urandom(self.AES_BLOCK_SIZE) + + if len(iv) != self.AES_BLOCK_SIZE: + raise Exception('Wrong iv size: {}'.format(len(iv))) + + if bits not in _ciphers.algorithms.AES.key_sizes: + raise Exception('Unsupported key length: {}'.format(bits)) + + if len(self.key) != bits / 8: + raise Exception('Wrong Key length: {}'.format(len(self.key))) + + try: + mode = self.POSTFIX_MODE[cmode] + except KeyError: + raise Exception('Unsupported chaining mode: {}'.format(cmode)) + + cipher = _ciphers.Cipher( + _ciphers.algorithms.AES(self.key), + mode(iv), + backend=_backends.default_backend()) + + return cipher, iv + + def encrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64enc=True, + block_size=AES_BLOCK_SIZE): + """ + :param key: The encryption key + :param msg: Message to be encrypted + :param padding: Which padding that should be used + :param b64enc: Whether the result should be base64encoded + :param block_size: If PKCS#7 padding which block size to use + :return: The encrypted message + """ + self.__class__._deprecation_notice() + if padding == 'PKCS#7': + _block_size = block_size + elif padding == 'PKCS#5': + _block_size = 8 + else: + _block_size = 0 + + if _block_size: + plen = _block_size - (len(msg) % _block_size) + c = chr(plen).encode() + msg += c * plen + + cipher, iv = self.build_cipher(alg) + encryptor = cipher.encryptor() + cmsg = iv + encryptor.update(msg) + encryptor.finalize() + + if b64enc: + enc_msg = _base64.b64encode(cmsg) + else: + enc_msg = cmsg + + return enc_msg + + def decrypt(self, msg, alg='aes_128_cbc', padding='PKCS#7', b64dec=True): + """ + :param key: The encryption key + :param msg: Base64 encoded message to be decrypted + :return: The decrypted message + """ + self.__class__._deprecation_notice() + data = _base64.b64decode(msg) if b64dec else msg + + cipher, iv = self.build_cipher(alg=alg) + decryptor = cipher.decryptor() + res = decryptor.update(data)[self.AES_BLOCK_SIZE:] + res += decryptor.finalize() + if padding in ['PKCS#5', 'PKCS#7']: + idx = bytearray(res)[-1] + res = res[:-idx] + return res |