aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cryptography/hazmat/backends/commoncrypto/ciphers.py14
-rw-r--r--src/cryptography/hazmat/backends/openssl/ciphers.py22
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/base.py26
-rw-r--r--src/cryptography/hazmat/primitives/ciphers/modes.py25
4 files changed, 64 insertions, 23 deletions
diff --git a/src/cryptography/hazmat/backends/commoncrypto/ciphers.py b/src/cryptography/hazmat/backends/commoncrypto/ciphers.py
index b59381cb..85ec9e76 100644
--- a/src/cryptography/hazmat/backends/commoncrypto/ciphers.py
+++ b/src/cryptography/hazmat/backends/commoncrypto/ciphers.py
@@ -213,11 +213,15 @@ class _GCMCipherContext(object):
self._backend._check_cipher_response(res)
self._backend._release_cipher_ctx(self._ctx)
self._tag = self._backend._ffi.buffer(tag_buf)[:]
- if (self._operation == self._backend._lib.kCCDecrypt and
- not constant_time.bytes_eq(
- self._tag[:len(self._mode.tag)], self._mode.tag
- )):
- raise InvalidTag
+ if self._operation == self._backend._lib.kCCDecrypt:
+ if self._mode.tag is None:
+ raise ValueError(
+ "Authentication tag must be provided when decrypting."
+ )
+ if not constant_time.bytes_eq(
+ self._tag[:len(self._mode.tag)], self._mode.tag
+ ):
+ raise InvalidTag
return b""
def authenticate_additional_data(self, data):
diff --git a/src/cryptography/hazmat/backends/openssl/ciphers.py b/src/cryptography/hazmat/backends/openssl/ciphers.py
index 0e0918af..b6058150 100644
--- a/src/cryptography/hazmat/backends/openssl/ciphers.py
+++ b/src/cryptography/hazmat/backends/openssl/ciphers.py
@@ -78,7 +78,13 @@ class _CipherContext(object):
len(iv_nonce), self._backend._ffi.NULL
)
self._backend.openssl_assert(res != 0)
- if operation == self._DECRYPT:
+ if operation == self._DECRYPT and \
+ self._backend.openssl_version_number() < 0x10002000:
+ if mode.tag is None:
+ raise NotImplementedError(
+ "delayed passing of GCM tag requires OpenSSL >= 1.0.2."
+ " To use this feature please update OpenSSL"
+ )
res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
ctx, self._backend._lib.EVP_CTRL_GCM_SET_TAG,
len(mode.tag), mode.tag
@@ -134,6 +140,20 @@ class _CipherContext(object):
if isinstance(self._mode, modes.GCM):
self.update(b"")
+ if self._operation == self._DECRYPT and \
+ isinstance(self._mode, modes.ModeWithAuthenticationTag) and \
+ self._backend.openssl_version_number() >= 0x10002000:
+ tag = self._mode.tag
+ if tag is None:
+ raise ValueError(
+ "Authentication tag must be provided when decrypting."
+ )
+ res = self._backend._lib.EVP_CIPHER_CTX_ctrl(
+ self._ctx, self._backend._lib.EVP_CTRL_GCM_SET_TAG,
+ len(tag), tag
+ )
+ self._backend.openssl_assert(res != 0)
+
buf = self._backend._ffi.new("unsigned char[]", self._block_size_bytes)
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
diff --git a/src/cryptography/hazmat/primitives/ciphers/base.py b/src/cryptography/hazmat/primitives/ciphers/base.py
index e9d55a10..9e0d0051 100644
--- a/src/cryptography/hazmat/primitives/ciphers/base.py
+++ b/src/cryptography/hazmat/primitives/ciphers/base.py
@@ -76,6 +76,16 @@ class AEADCipherContext(object):
@six.add_metaclass(abc.ABCMeta)
+class AEADDecryptionContext(object):
+ @abc.abstractmethod
+ def finalize_with_tag(self, tag):
+ """
+ Returns the results of processing the final block as bytes and allows
+ delayed passing of the authentication tag.
+ """
+
+
+@six.add_metaclass(abc.ABCMeta)
class AEADEncryptionContext(object):
@abc.abstractproperty
def tag(self):
@@ -115,11 +125,6 @@ class Cipher(object):
return self._wrap_ctx(ctx, encrypt=True)
def decryptor(self):
- if isinstance(self.mode, modes.ModeWithAuthenticationTag):
- if self.mode.tag is None:
- raise ValueError(
- "Authentication tag must be provided when decrypting."
- )
ctx = self._backend.create_symmetric_decryption_ctx(
self.algorithm, self.mode
)
@@ -169,6 +174,7 @@ class _CipherContext(object):
@utils.register_interface(AEADCipherContext)
@utils.register_interface(CipherContext)
+@utils.register_interface(AEADDecryptionContext)
class _AEADCipherContext(object):
def __init__(self, ctx):
self._ctx = ctx
@@ -214,6 +220,16 @@ class _AEADCipherContext(object):
self._ctx = None
return data
+ def finalize_with_tag(self, tag):
+ if self._ctx._backend.name == "openssl" and \
+ self._ctx._backend.openssl_version_number() < 0x10002000:
+ raise NotImplementedError(
+ "finalize_with_tag requires OpenSSL >= 1.0.2. To use this "
+ "method please update OpenSSL"
+ )
+ self._ctx._mode._set_tag(tag)
+ return self.finalize()
+
def authenticate_additional_data(self, data):
if self._ctx is None:
raise AlreadyFinalized("Context was already finalized.")
diff --git a/src/cryptography/hazmat/primitives/ciphers/modes.py b/src/cryptography/hazmat/primitives/ciphers/modes.py
index 802e544a..5b28157a 100644
--- a/src/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/src/cryptography/hazmat/primitives/ciphers/modes.py
@@ -161,21 +161,22 @@ class GCM(object):
# len(initialization_vector) must in [1, 2 ** 64), but it's impossible
# to actually construct a bytes object that large, so we don't check
# for it
- if min_tag_length < 4:
- raise ValueError("min_tag_length must be >= 4")
- if tag is not None and len(tag) < min_tag_length:
- raise ValueError(
- "Authentication tag must be {0} bytes or longer.".format(
- min_tag_length)
- )
-
if not isinstance(initialization_vector, bytes):
raise TypeError("initialization_vector must be bytes")
-
- if tag is not None and not isinstance(tag, bytes):
- raise TypeError("tag must be bytes or None")
-
self._initialization_vector = initialization_vector
+ self._set_tag(tag, min_tag_length)
+
+ def _set_tag(self, tag, min_tag_length=16):
+ if tag is not None:
+ if not isinstance(tag, bytes):
+ raise TypeError("tag must be bytes or None")
+ if min_tag_length < 4:
+ raise ValueError("min_tag_length must be >= 4")
+ if len(tag) < min_tag_length:
+ raise ValueError(
+ "Authentication tag must be {0} bytes or longer.".format(
+ min_tag_length)
+ )
self._tag = tag
tag = utils.read_only_property("_tag")