aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-x.travis/install.sh18
-rw-r--r--cryptography/hazmat/bindings/openssl/backend.py31
-rw-r--r--cryptography/hazmat/bindings/openssl/err.py7
-rw-r--r--docs/exceptions.rst1
-rw-r--r--docs/hazmat/primitives/padding.rst8
-rw-r--r--docs/hazmat/primitives/symmetric-encryption.rst12
-rw-r--r--tests/hazmat/bindings/test_openssl.py21
-rw-r--r--tests/hazmat/primitives/test_block.py16
8 files changed, 94 insertions, 20 deletions
diff --git a/.travis/install.sh b/.travis/install.sh
index fdd71907..4aa39799 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -5,24 +5,8 @@ set -x
if [[ "${OPENSSL}" == "0.9.8" ]]; then
sudo add-apt-repository "deb http://archive.ubuntu.com/ubuntu/ lucid main"
-fi
-
-if [[ "${TOX_ENV}" == "pypy" ]]; then
- sudo add-apt-repository -y ppa:pypy/ppa
-fi
-
-sudo apt-get -y update
-
-if [[ "${OPENSSL}" == "0.9.8" ]]; then
+ sudo apt-get -y update
sudo apt-get install -y --force-yes libssl-dev/lucid
fi
-if [[ "${TOX_ENV}" == "pypy" ]]; then
- sudo apt-get install -y pypy
-
- # This is required because we need to get rid of the Travis installed PyPy
- # or it'll take precedence over the PPA installed one.
- sudo rm -rf /usr/local/pypy/bin
-fi
-
pip install tox coveralls
diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py
index db4d18e7..9f8ea939 100644
--- a/cryptography/hazmat/bindings/openssl/backend.py
+++ b/cryptography/hazmat/bindings/openssl/backend.py
@@ -193,6 +193,33 @@ class Backend(object):
def create_symmetric_decryption_ctx(self, cipher, mode):
return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
+ def _handle_error(self):
+ code = self.lib.ERR_get_error()
+ assert code != 0
+ lib = self.lib.ERR_GET_LIB(code)
+ func = self.lib.ERR_GET_FUNC(code)
+ reason = self.lib.ERR_GET_REASON(code)
+ return self._handle_error_code(lib, func, reason)
+
+ def _handle_error_code(self, lib, func, reason):
+ if lib == self.lib.ERR_LIB_EVP:
+ if func == self.lib.EVP_F_EVP_ENCRYPTFINAL_EX:
+ if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
+ raise ValueError(
+ "The length of the provided data is not a multiple of "
+ "the block length"
+ )
+ elif func == self.lib.EVP_F_EVP_DECRYPTFINAL_EX:
+ if reason == self.lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH:
+ raise ValueError(
+ "The length of the provided data is not a multiple of "
+ "the block length"
+ )
+
+ raise SystemError(
+ "Unknown error code from OpenSSL, you should probably file a bug."
+ )
+
class GetCipherByName(object):
def __init__(self, fmt):
@@ -268,7 +295,9 @@ class _CipherContext(object):
buf = self._backend.ffi.new("unsigned char[]", self._cipher.block_size)
outlen = self._backend.ffi.new("int *")
res = self._backend.lib.EVP_CipherFinal_ex(self._ctx, buf, outlen)
- assert res != 0
+ if res == 0:
+ self._backend._handle_error()
+
res = self._backend.lib.EVP_CIPHER_CTX_cleanup(self._ctx)
assert res == 1
return self._backend.ffi.buffer(buf)[:outlen[0]]
diff --git a/cryptography/hazmat/bindings/openssl/err.py b/cryptography/hazmat/bindings/openssl/err.py
index 6a36dee0..3dac6948 100644
--- a/cryptography/hazmat/bindings/openssl/err.py
+++ b/cryptography/hazmat/bindings/openssl/err.py
@@ -21,6 +21,13 @@ struct ERR_string_data_st {
const char *string;
};
typedef struct ERR_string_data_st ERR_STRING_DATA;
+
+static const int ERR_LIB_EVP;
+
+static const int EVP_F_EVP_ENCRYPTFINAL_EX;
+static const int EVP_F_EVP_DECRYPTFINAL_EX;
+
+static const int EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH;
"""
FUNCTIONS = """
diff --git a/docs/exceptions.rst b/docs/exceptions.rst
index ab1b28fe..c6f5a7cc 100644
--- a/docs/exceptions.rst
+++ b/docs/exceptions.rst
@@ -12,4 +12,3 @@ Exceptions
This is raised when a backend doesn't support the requested algorithm (or
combination of algorithms).
-
diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst
index aebb4d4d..4d79ac8f 100644
--- a/docs/hazmat/primitives/padding.rst
+++ b/docs/hazmat/primitives/padding.rst
@@ -25,8 +25,14 @@ multiple of the block size.
>>> padder = padding.PKCS7(128).padder()
>>> padder.update(b"1111111111")
''
- >>> padder.finalize()
+ >>> padded_data = padder.finalize()
+ >>> padded_data
'1111111111\x06\x06\x06\x06\x06\x06'
+ >>> unpadder = padding.PKCS7(128).unpadder()
+ >>> unpadder.update(padded_data)
+ ''
+ >>> unpadder.finalize()
+ '1111111111'
:param block_size: The size of the block in bits that the data is being
padded to.
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index f63ad90a..4ab91408 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -86,6 +86,15 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_.
everything into the context. Once that is done call ``finalize()`` to
finish the operation and obtain the remainder of the data.
+ Block ciphers require that plaintext or ciphertext always be a multiple of
+ their block size, because of that **padding** is often required to make a
+ message the correct size. ``CipherContext`` will not automatically apply
+ any padding; you'll need to add your own. For block ciphers the reccomended
+ padding is :class:`cryptography.hazmat.primitives.padding.PKCS7`. If you
+ are using a stream cipher mode (such as
+ :class:`cryptography.hazmat.primitives.modes.CTR`) you don't have to worry
+ about this.
+
.. method:: update(data)
:param bytes data: The data you wish to pass into the context.
@@ -101,6 +110,9 @@ an "encrypt-then-MAC" formulation as `described by Colin Percival`_.
.. method:: finalize()
:return bytes: Returns the remainder of the data.
+ :raises ValueError: This is raised when the data provided isn't
+ correctly padded to be a multiple of the
+ algorithm's block size.
Once ``finalize`` is called this object can no longer be used and
:meth:`update` and :meth:`finalize` will raise
diff --git a/tests/hazmat/bindings/test_openssl.py b/tests/hazmat/bindings/test_openssl.py
index e6604e6b..1eb6f200 100644
--- a/tests/hazmat/bindings/test_openssl.py
+++ b/tests/hazmat/bindings/test_openssl.py
@@ -74,3 +74,24 @@ class TestOpenSSL(object):
)
with pytest.raises(UnsupportedAlgorithm):
cipher.encryptor()
+
+ def test_handle_unknown_error(self):
+ with pytest.raises(SystemError):
+ backend._handle_error_code(0, 0, 0)
+
+ with pytest.raises(SystemError):
+ backend._handle_error_code(backend.lib.ERR_LIB_EVP, 0, 0)
+
+ with pytest.raises(SystemError):
+ backend._handle_error_code(
+ backend.lib.ERR_LIB_EVP,
+ backend.lib.EVP_F_EVP_ENCRYPTFINAL_EX,
+ 0
+ )
+
+ with pytest.raises(SystemError):
+ backend._handle_error_code(
+ backend.lib.ERR_LIB_EVP,
+ backend.lib.EVP_F_EVP_DECRYPTFINAL_EX,
+ 0
+ )
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index 70d7098b..4a8e88b4 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -104,3 +104,19 @@ class TestCipherContext(object):
with pytest.raises(UnsupportedAlgorithm):
cipher.decryptor()
+
+ def test_incorrectly_padded(self, backend):
+ cipher = Cipher(
+ algorithms.AES(b"\x00" * 16),
+ modes.CBC(b"\x00" * 16),
+ backend
+ )
+ encryptor = cipher.encryptor()
+ encryptor.update(b"1")
+ with pytest.raises(ValueError):
+ encryptor.finalize()
+
+ decryptor = cipher.decryptor()
+ decryptor.update(b"1")
+ with pytest.raises(ValueError):
+ decryptor.finalize()