diff options
Diffstat (limited to 'src')
4 files changed, 63 insertions, 9 deletions
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py index 2cbfca2c..6abf4ecc 100644 --- a/src/cryptography/hazmat/backends/openssl/backend.py +++ b/src/cryptography/hazmat/backends/openssl/backend.py @@ -61,7 +61,7 @@ from cryptography.hazmat.primitives.ciphers.algorithms import ( AES, ARC4, Blowfish, CAST5, Camellia, ChaCha20, IDEA, SEED, TripleDES ) from cryptography.hazmat.primitives.ciphers.modes import ( - CBC, CFB, CFB8, CTR, ECB, GCM, OFB + CBC, CFB, CFB8, CTR, ECB, GCM, OFB, XTS ) from cryptography.hazmat.primitives.kdf import scrypt @@ -263,6 +263,7 @@ class Backend(object): type(None), GetCipherByName("chacha20") ) + self.register_cipher_adapter(AES, XTS, _get_xts_cipher) def create_symmetric_encryption_ctx(self, cipher, mode): return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) @@ -1961,4 +1962,9 @@ class GetCipherByName(object): return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) +def _get_xts_cipher(backend, cipher, mode): + cipher_name = "aes-{0}-xts".format(cipher.key_size // 2) + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + backend = Backend() diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py index dfb33a07..8e55e28b 100644 --- a/src/cryptography/hazmat/backends/openssl/ciphers.py +++ b/src/cryptography/hazmat/backends/openssl/ciphers.py @@ -57,6 +57,8 @@ class _CipherContext(object): if isinstance(mode, modes.ModeWithInitializationVector): iv_nonce = mode.initialization_vector + elif isinstance(mode, modes.ModeWithTweak): + iv_nonce = mode.tweak elif isinstance(mode, modes.ModeWithNonce): iv_nonce = mode.nonce elif isinstance(cipher, modes.ModeWithNonce): diff --git a/src/cryptography/hazmat/primitives/ciphers/algorithms.py b/src/cryptography/hazmat/primitives/ciphers/algorithms.py index 6e5eb313..99a837e4 100644 --- a/src/cryptography/hazmat/primitives/ciphers/algorithms.py +++ b/src/cryptography/hazmat/primitives/ciphers/algorithms.py @@ -25,7 +25,8 @@ def _verify_key_size(algorithm, key): class AES(object): name = "AES" block_size = 128 - key_sizes = frozenset([128, 192, 256]) + # 512 added to support AES-256-XTS, which uses 512-bit keys + key_sizes = frozenset([128, 192, 256, 512]) def __init__(self, key): self.key = _verify_key_size(self, key) diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py index 54670b7f..598dfaa4 100644 --- a/src/cryptography/hazmat/primitives/ciphers/modes.py +++ b/src/cryptography/hazmat/primitives/ciphers/modes.py @@ -37,6 +37,15 @@ class ModeWithInitializationVector(object): @six.add_metaclass(abc.ABCMeta) +class ModeWithTweak(object): + @abc.abstractproperty + def tweak(self): + """ + The value of the tweak for this mode as bytes. + """ + + +@six.add_metaclass(abc.ABCMeta) class ModeWithNonce(object): @abc.abstractproperty def nonce(self): @@ -54,6 +63,13 @@ class ModeWithAuthenticationTag(object): """ +def _check_aes_key_length(self, algorithm): + if algorithm.key_size > 256 and algorithm.name == "AES": + raise ValueError( + "Only 128, 192, and 256 bit keys are allowed for this AES mode" + ) + + def _check_iv_length(self, algorithm): if len(self.initialization_vector) * 8 != algorithm.block_size: raise ValueError("Invalid IV size ({0}) for {1}.".format( @@ -61,6 +77,11 @@ def _check_iv_length(self, algorithm): )) +def _check_iv_and_key_length(self, algorithm): + _check_aes_key_length(self, algorithm) + _check_iv_length(self, algorithm) + + @utils.register_interface(Mode) @utils.register_interface(ModeWithInitializationVector) class CBC(object): @@ -73,15 +94,38 @@ class CBC(object): self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") - validate_for_algorithm = _check_iv_length + validate_for_algorithm = _check_iv_and_key_length + + +@utils.register_interface(Mode) +@utils.register_interface(ModeWithTweak) +class XTS(object): + name = "XTS" + + def __init__(self, tweak): + if not isinstance(tweak, bytes): + raise TypeError("tweak must be bytes") + + if len(tweak) != 16: + raise ValueError("tweak must be 128-bits (16 bytes)") + + self._tweak = tweak + + tweak = utils.read_only_property("_tweak") + + def validate_for_algorithm(self, algorithm): + if algorithm.key_size not in (256, 512): + raise ValueError( + "The XTS specification requires a 256-bit key for AES-128-XTS" + " and 512-bit key for AES-256-XTS" + ) @utils.register_interface(Mode) class ECB(object): name = "ECB" - def validate_for_algorithm(self, algorithm): - pass + validate_for_algorithm = _check_aes_key_length @utils.register_interface(Mode) @@ -96,7 +140,7 @@ class OFB(object): self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") - validate_for_algorithm = _check_iv_length + validate_for_algorithm = _check_iv_and_key_length @utils.register_interface(Mode) @@ -111,7 +155,7 @@ class CFB(object): self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") - validate_for_algorithm = _check_iv_length + validate_for_algorithm = _check_iv_and_key_length @utils.register_interface(Mode) @@ -126,7 +170,7 @@ class CFB8(object): self._initialization_vector = initialization_vector initialization_vector = utils.read_only_property("_initialization_vector") - validate_for_algorithm = _check_iv_length + validate_for_algorithm = _check_iv_and_key_length @utils.register_interface(Mode) @@ -143,6 +187,7 @@ class CTR(object): nonce = utils.read_only_property("_nonce") def validate_for_algorithm(self, algorithm): + _check_aes_key_length(self, algorithm) if len(self.nonce) * 8 != algorithm.block_size: raise ValueError("Invalid nonce size ({0}) for {1}.".format( len(self.nonce), self.name @@ -180,4 +225,4 @@ class GCM(object): initialization_vector = utils.read_only_property("_initialization_vector") def validate_for_algorithm(self, algorithm): - pass + _check_aes_key_length(self, algorithm) |