aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cryptography/hazmat/backends/commoncrypto/ciphers.py12
-rw-r--r--cryptography/hazmat/backends/openssl/ciphers.py8
-rw-r--r--tests/hazmat/primitives/test_aes.py35
3 files changed, 54 insertions, 1 deletions
diff --git a/cryptography/hazmat/backends/commoncrypto/ciphers.py b/cryptography/hazmat/backends/commoncrypto/ciphers.py
index 525500c8..6d3ba863 100644
--- a/cryptography/hazmat/backends/commoncrypto/ciphers.py
+++ b/cryptography/hazmat/backends/commoncrypto/ciphers.py
@@ -151,6 +151,12 @@ class _GCMCipherContext(object):
len(mode.initialization_vector)
)
self._backend._check_cipher_response(res)
+ # CommonCrypto has a bug where calling update without at least one
+ # call to authenticate_additional_data will result in null byte output
+ # for ciphertext. The following empty byte string call prevents the
+ # issue, which is present in at least 10.8 and 10.9.
+ # Filed as rdar://18314544
+ self.authenticate_additional_data(b"")
def update(self, data):
buf = self._backend._ffi.new("unsigned char[]", len(data))
@@ -164,6 +170,12 @@ class _GCMCipherContext(object):
return self._backend._ffi.buffer(buf)[:]
def finalize(self):
+ # CommonCrypto has a yet another bug where you must make at least one
+ # call to update. If you pass just AAD and call finalize without a call
+ # to update you'll get null bytes for tag. The following update call
+ # prevents this issue, which is present in at least 10.8 and 10.9.
+ # Filed as rdar://18314580
+ self.update(b"")
tag_size = self._cipher.block_size // 8
tag_buf = self._backend._ffi.new("unsigned char[]", tag_size)
tag_len = self._backend._ffi.new("size_t *", tag_size)
diff --git a/cryptography/hazmat/backends/openssl/ciphers.py b/cryptography/hazmat/backends/openssl/ciphers.py
index c3a5499a..d37bb014 100644
--- a/cryptography/hazmat/backends/openssl/ciphers.py
+++ b/cryptography/hazmat/backends/openssl/ciphers.py
@@ -128,6 +128,14 @@ class _CipherContext(object):
return self._backend._ffi.buffer(buf)[:outlen[0]]
def finalize(self):
+ # OpenSSL 1.0.1 on Ubuntu 12.04 (and possibly other distributions)
+ # appears to have a bug where you must make at least one call to update
+ # even if you are only using authenticate_additional_data or the
+ # GCM tag will be wrong. An (empty) call to update resolves this
+ # and is harmless for all other versions of OpenSSL.
+ if isinstance(self._mode, GCM):
+ self.update(b"")
+
buf = self._backend._ffi.new("unsigned char[]", self._block_size)
outlen = self._backend._ffi.new("int *")
res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py
index 5bde7d3c..e8e0eee4 100644
--- a/tests/hazmat/primitives/test_aes.py
+++ b/tests/hazmat/primitives/test_aes.py
@@ -18,7 +18,7 @@ import os
import pytest
-from cryptography.hazmat.primitives.ciphers import algorithms, modes
+from cryptography.hazmat.primitives.ciphers import algorithms, base, modes
from .utils import generate_aead_test, generate_encrypt_test
from ...utils import load_nist_vectors
@@ -228,3 +228,36 @@ class TestAESModeGCM(object):
algorithms.AES,
modes.GCM,
)
+
+ def test_gcm_tag_with_only_aad(self, backend):
+ key = binascii.unhexlify(b"5211242698bed4774a090620a6ca56f3")
+ iv = binascii.unhexlify(b"b1e1349120b6e832ef976f5d")
+ aad = binascii.unhexlify(b"b6d729aab8e6416d7002b9faa794c410d8d2f193")
+ tag = binascii.unhexlify(b"0f247e7f9c2505de374006738018493b")
+
+ cipher = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv),
+ backend=backend
+ )
+ encryptor = cipher.encryptor()
+ encryptor.authenticate_additional_data(aad)
+ encryptor.finalize()
+ assert encryptor.tag == tag
+
+ def test_gcm_ciphertext_with_no_aad(self, backend):
+ key = binascii.unhexlify(b"e98b72a9881a84ca6b76e0f43e68647a")
+ iv = binascii.unhexlify(b"8b23299fde174053f3d652ba")
+ ct = binascii.unhexlify(b"5a3c1cf1985dbb8bed818036fdd5ab42")
+ tag = binascii.unhexlify(b"23c7ab0f952b7091cd324835043b5eb5")
+ pt = binascii.unhexlify(b"28286a321293253c3e0aa2704a278032")
+
+ cipher = base.Cipher(
+ algorithms.AES(key),
+ modes.GCM(iv),
+ backend=backend
+ )
+ encryptor = cipher.encryptor()
+ computed_ct = encryptor.update(pt) + encryptor.finalize()
+ assert computed_ct == ct
+ assert encryptor.tag == tag