aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml1
-rwxr-xr-x.travis/install.sh10
-rw-r--r--CHANGELOG.rst8
-rw-r--r--README.rst4
-rw-r--r--cryptography/fernet.py14
-rw-r--r--cryptography/hazmat/backends/commoncrypto/backend.py20
-rw-r--r--cryptography/hazmat/backends/multibackend.py48
-rw-r--r--cryptography/hazmat/backends/openssl/backend.py153
-rw-r--r--cryptography/hazmat/bindings/openssl/aes.py6
-rw-r--r--cryptography/hazmat/bindings/openssl/binding.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/ec.py11
-rw-r--r--cryptography/hazmat/bindings/openssl/opensslv.py2
-rw-r--r--cryptography/hazmat/bindings/openssl/ssl.py35
-rw-r--r--cryptography/hazmat/primitives/asymmetric/dsa.py22
-rw-r--r--cryptography/hazmat/primitives/asymmetric/padding.py10
-rw-r--r--cryptography/hazmat/primitives/asymmetric/rsa.py44
-rw-r--r--cryptography/hazmat/primitives/ciphers/algorithms.py2
-rw-r--r--cryptography/hazmat/primitives/ciphers/base.py24
-rw-r--r--cryptography/hazmat/primitives/ciphers/modes.py40
-rw-r--r--cryptography/hazmat/primitives/cmac.py20
-rw-r--r--cryptography/hazmat/primitives/constant_time.py6
-rw-r--r--cryptography/hazmat/primitives/hashes.py14
-rw-r--r--cryptography/hazmat/primitives/hmac.py18
-rw-r--r--cryptography/hazmat/primitives/kdf/hkdf.py72
-rw-r--r--cryptography/hazmat/primitives/kdf/pbkdf2.py22
-rw-r--r--cryptography/hazmat/primitives/padding.py24
-rw-r--r--cryptography/hazmat/primitives/twofactor/hotp.py12
-rw-r--r--cryptography/hazmat/primitives/twofactor/totp.py4
-rw-r--r--docs/development/custom-vectors/cast5.rst6
-rw-r--r--docs/development/custom-vectors/idea.rst6
-rw-r--r--docs/development/custom-vectors/seed.rst6
-rw-r--r--docs/doing-a-release.rst3
-rw-r--r--docs/faq.rst29
-rw-r--r--docs/fernet.rst6
-rw-r--r--docs/hazmat/backends/commoncrypto.rst4
-rw-r--r--docs/hazmat/backends/interfaces.rst18
-rw-r--r--docs/hazmat/backends/openssl.rst10
-rw-r--r--docs/hazmat/primitives/asymmetric/dsa.rst2
-rw-r--r--docs/hazmat/primitives/asymmetric/rsa.rst100
-rw-r--r--docs/hazmat/primitives/constant-time.rst2
-rw-r--r--docs/hazmat/primitives/cryptographic-hashes.rst1
-rw-r--r--docs/hazmat/primitives/key-derivation-functions.rst107
-rw-r--r--docs/hazmat/primitives/mac/cmac.rst7
-rw-r--r--docs/hazmat/primitives/mac/hmac.rst3
-rw-r--r--docs/hazmat/primitives/mac/index.rst3
-rw-r--r--docs/hazmat/primitives/padding.rst1
-rw-r--r--docs/hazmat/primitives/symmetric-encryption.rst19
-rw-r--r--docs/installation.rst16
-rw-r--r--tasks.py2
-rw-r--r--tests/hazmat/backends/test_multibackend.py30
-rw-r--r--tests/hazmat/backends/test_openssl.py15
-rw-r--r--tests/hazmat/primitives/test_3des.py37
-rw-r--r--tests/hazmat/primitives/test_aes.py33
-rw-r--r--tests/hazmat/primitives/test_block.py8
-rw-r--r--tests/hazmat/primitives/test_hkdf.py63
-rw-r--r--tests/hazmat/primitives/test_rsa.py36
-rw-r--r--tests/hazmat/primitives/utils.py7
-rw-r--r--tox.ini8
58 files changed, 896 insertions, 340 deletions
diff --git a/.travis.yml b/.travis.yml
index f4c40470..cacd1e27 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -49,6 +49,7 @@ matrix:
- os: osx
env: TOX_ENV=py3pep8
compiler: clang
+
- os: linux
env: TOX_ENV=docs
compiler: clang
diff --git a/.travis/install.sh b/.travis/install.sh
index 79790050..e028033e 100755
--- a/.travis/install.sh
+++ b/.travis/install.sh
@@ -32,18 +32,18 @@ if [[ "$(uname -s)" == "Darwin" ]]; then
if which pyenv > /dev/null; then eval "$(pyenv init -)"; fi
case "${TOX_ENV}" in
py26)
- curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
+ curl -O https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
sudo pip install virtualenv
;;
py27)
- curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
+ curl -O https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
sudo pip install virtualenv
;;
pypy)
- pyenv install pypy-2.2.1
- pyenv global pypy-2.2.1
+ pyenv install pypy-2.3
+ pyenv global pypy-2.3
pip install virtualenv
;;
py32)
@@ -62,7 +62,7 @@ if [[ "$(uname -s)" == "Darwin" ]]; then
pip install virtualenv
;;
docs)
- curl -O https://raw.githubusercontent.com/pypa/pip/master/contrib/get-pip.py
+ curl -O https://bootstrap.pypa.io/get-pip.py
sudo python get-pip.py
sudo pip install virtualenv
;;
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 54d6229f..93423988 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,14 @@ Changelog
.. note:: This version is not yet released and is under active development.
+* Added :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDFExpand`.
+* Added :class:`~cryptography.hazmat.primitives.ciphers.modes.CFB8` support
+ for :class:`~cryptography.hazmat.primitives.ciphers.algorithms.AES` and
+ :class:`~cryptography.hazmat.primitives.ciphers.algorithms.TripleDES` on
+ :doc:`/hazmat/backends/commoncrypto` and :doc:`/hazmat/backends/openssl`.
+* Added ``AES`` :class:`~cryptography.hazmat.primitives.ciphers.modes.CTR`
+ support to the OpenSSL backend when linked against 0.9.8.
+
0.4 - 2014-05-03
~~~~~~~~~~~~~~~~
diff --git a/README.rst b/README.rst
index ac7ec61a..5e1a82a8 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,10 @@
Cryptography
============
+.. image:: https://pypip.in/version/cryptography/badge.svg
+ :target: https://pypi.python.org/pypi/cryptography/
+ :alt: Latest Version
+
.. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master
:target: https://travis-ci.org/pyca/cryptography
diff --git a/cryptography/fernet.py b/cryptography/fernet.py
index 674ce8ae..cdb9bdca 100644
--- a/cryptography/fernet.py
+++ b/cryptography/fernet.py
@@ -43,7 +43,7 @@ class Fernet(object):
key = base64.urlsafe_b64decode(key)
if len(key) != 32:
raise ValueError(
- "Fernet key must be 32 url-safe base64-encoded bytes"
+ "Fernet key must be 32 url-safe base64-encoded bytes."
)
self._signing_key = key[:16]
@@ -60,10 +60,8 @@ class Fernet(object):
return self._encrypt_from_parts(data, current_time, iv)
def _encrypt_from_parts(self, data, current_time, iv):
- if isinstance(data, six.text_type):
- raise TypeError(
- "Unicode-objects must be encoded before encryption"
- )
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
padder = padding.PKCS7(algorithms.AES.block_size).padder()
padded_data = padder.update(data) + padder.finalize()
@@ -82,10 +80,8 @@ class Fernet(object):
return base64.urlsafe_b64encode(basic_parts + hmac)
def decrypt(self, token, ttl=None):
- if isinstance(token, six.text_type):
- raise TypeError(
- "Unicode-objects must be encoded before decryption"
- )
+ if not isinstance(token, bytes):
+ raise TypeError("token must be bytes.")
current_time = int(time.time())
diff --git a/cryptography/hazmat/backends/commoncrypto/backend.py b/cryptography/hazmat/backends/commoncrypto/backend.py
index 4faca73e..213cbd8c 100644
--- a/cryptography/hazmat/backends/commoncrypto/backend.py
+++ b/cryptography/hazmat/backends/commoncrypto/backend.py
@@ -28,7 +28,7 @@ from cryptography.hazmat.primitives.ciphers.algorithms import (
AES, ARC4, Blowfish, CAST5, TripleDES
)
from cryptography.hazmat.primitives.ciphers.modes import (
- CBC, CFB, CTR, ECB, GCM, OFB
+ CBC, CFB, CFB8, CTR, ECB, GCM, OFB
)
@@ -154,7 +154,7 @@ class Backend(object):
def _register_cipher_adapter(self, cipher_cls, cipher_const, mode_cls,
mode_const):
if (cipher_cls, mode_cls) in self._cipher_registry:
- raise ValueError("Duplicate registration for: {0} {1}".format(
+ raise ValueError("Duplicate registration for: {0} {1}.".format(
cipher_cls, mode_cls)
)
self._cipher_registry[cipher_cls, mode_cls] = (cipher_const,
@@ -165,6 +165,7 @@ class Backend(object):
(CBC, self._lib.kCCModeCBC),
(ECB, self._lib.kCCModeECB),
(CFB, self._lib.kCCModeCFB),
+ (CFB8, self._lib.kCCModeCFB8),
(OFB, self._lib.kCCModeOFB),
(CTR, self._lib.kCCModeCTR),
(GCM, self._lib.kCCModeGCM),
@@ -178,6 +179,7 @@ class Backend(object):
for mode_cls, mode_const in [
(CBC, self._lib.kCCModeCBC),
(CFB, self._lib.kCCModeCFB),
+ (CFB8, self._lib.kCCModeCFB8),
(OFB, self._lib.kCCModeOFB),
]:
self._register_cipher_adapter(
@@ -226,7 +228,7 @@ class Backend(object):
# rdar://15589470
raise ValueError(
"The length of the provided data is not a multiple of "
- "the block length"
+ "the block length."
)
else:
raise InternalError(
@@ -264,7 +266,7 @@ class _CipherContext(object):
# This bug has been filed as rdar://15589470
self._bytes_processed = 0
if (isinstance(cipher, interfaces.BlockCipherAlgorithm) and not
- isinstance(mode, (OFB, CFB, CTR))):
+ isinstance(mode, (OFB, CFB, CFB8, CTR))):
self._byte_block_size = cipher.block_size // 8
else:
self._byte_block_size = 1
@@ -275,7 +277,7 @@ class _CipherContext(object):
except KeyError:
raise UnsupportedAlgorithm(
"cipher {0} in {1} mode is not supported "
- "by this backend".format(
+ "by this backend.".format(
cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
)
@@ -322,7 +324,7 @@ class _CipherContext(object):
if self._bytes_processed % self._byte_block_size:
raise ValueError(
"The length of the provided data is not a multiple of "
- "the block length"
+ "the block length."
)
buf = self._backend._ffi.new("unsigned char[]", self._byte_block_size)
outlen = self._backend._ffi.new("size_t *")
@@ -349,7 +351,7 @@ class _GCMCipherContext(object):
except KeyError:
raise UnsupportedAlgorithm(
"cipher {0} in {1} mode is not supported "
- "by this backend".format(
+ "by this backend.".format(
cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
)
@@ -423,7 +425,7 @@ class _HashContext(object):
methods = self._backend._hash_mapping[self.algorithm.name]
except KeyError:
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend".format(
+ "{0} is not a supported hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
@@ -467,7 +469,7 @@ class _HMACContext(object):
alg = self._backend._supported_hmac_algorithms[algorithm.name]
except KeyError:
raise UnsupportedAlgorithm(
- "{0} is not a supported HMAC hash on this backend".format(
+ "{0} is not a supported HMAC hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
diff --git a/cryptography/hazmat/backends/multibackend.py b/cryptography/hazmat/backends/multibackend.py
index 753f4fc6..21d307cf 100644
--- a/cryptography/hazmat/backends/multibackend.py
+++ b/cryptography/hazmat/backends/multibackend.py
@@ -52,7 +52,7 @@ class MultiBackend(object):
except UnsupportedAlgorithm:
pass
raise UnsupportedAlgorithm(
- "cipher {0} in {1} mode is not supported by this backend".format(
+ "cipher {0} in {1} mode is not supported by this backend.".format(
algorithm.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
)
@@ -64,7 +64,7 @@ class MultiBackend(object):
except UnsupportedAlgorithm:
pass
raise UnsupportedAlgorithm(
- "cipher {0} in {1} mode is not supported by this backend".format(
+ "cipher {0} in {1} mode is not supported by this backend.".format(
algorithm.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
)
@@ -82,7 +82,7 @@ class MultiBackend(object):
except UnsupportedAlgorithm:
pass
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend".format(
+ "{0} is not a supported hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
@@ -100,7 +100,7 @@ class MultiBackend(object):
except UnsupportedAlgorithm:
pass
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend".format(
+ "{0} is not a supported hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
@@ -121,7 +121,7 @@ class MultiBackend(object):
except UnsupportedAlgorithm:
pass
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend".format(
+ "{0} is not a supported hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
@@ -129,13 +129,13 @@ class MultiBackend(object):
def generate_rsa_private_key(self, public_exponent, key_size):
for b in self._filtered_backends(RSABackend):
return b.generate_rsa_private_key(public_exponent, key_size)
- raise UnsupportedAlgorithm("RSA is not supported by the backend",
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_rsa_signature_ctx(self, private_key, padding, algorithm):
for b in self._filtered_backends(RSABackend):
return b.create_rsa_signature_ctx(private_key, padding, algorithm)
- raise UnsupportedAlgorithm("RSA is not supported by the backend",
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_rsa_verification_ctx(self, public_key, signature, padding,
@@ -143,44 +143,62 @@ class MultiBackend(object):
for b in self._filtered_backends(RSABackend):
return b.create_rsa_verification_ctx(public_key, signature,
padding, algorithm)
- raise UnsupportedAlgorithm("RSA is not supported by the backend",
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def mgf1_hash_supported(self, algorithm):
+ for b in self._filtered_backends(RSABackend):
+ return b.mgf1_hash_supported(algorithm)
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def decrypt_rsa(self, private_key, ciphertext, padding):
+ for b in self._filtered_backends(RSABackend):
+ return b.decrypt_rsa(private_key, ciphertext, padding)
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
+
+ def encrypt_rsa(self, public_key, plaintext, padding):
+ for b in self._filtered_backends(RSABackend):
+ return b.encrypt_rsa(public_key, plaintext, padding)
+ raise UnsupportedAlgorithm("RSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def generate_dsa_parameters(self, key_size):
for b in self._filtered_backends(DSABackend):
return b.generate_dsa_parameters(key_size)
- raise UnsupportedAlgorithm("DSA is not supported by the backend",
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def generate_dsa_private_key(self, parameters):
for b in self._filtered_backends(DSABackend):
return b.generate_dsa_private_key(parameters)
- raise UnsupportedAlgorithm("DSA is not supported by the backend",
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_dsa_verification_ctx(self, public_key, signature, algorithm):
for b in self._filtered_backends(DSABackend):
return b.create_dsa_verification_ctx(public_key, signature,
algorithm)
- raise UnsupportedAlgorithm("DSA is not supported by the backend",
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def create_dsa_signature_ctx(self, private_key, algorithm):
for b in self._filtered_backends(DSABackend):
return b.create_dsa_signature_ctx(private_key, algorithm)
- raise UnsupportedAlgorithm("DSA is not supported by the backend",
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def dsa_hash_supported(self, algorithm):
for b in self._filtered_backends(DSABackend):
return b.dsa_hash_supported(algorithm)
- raise UnsupportedAlgorithm("DSA is not supported by the backend",
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def dsa_parameters_supported(self, p, q, g):
for b in self._filtered_backends(DSABackend):
return b.dsa_parameters_supported(p, q, g)
- raise UnsupportedAlgorithm("DSA is not supported by the backend",
+ raise UnsupportedAlgorithm("DSA is not supported by the backend.",
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM)
def cmac_algorithm_supported(self, algorithm):
@@ -195,5 +213,5 @@ class MultiBackend(object):
return b.create_cmac_ctx(algorithm)
except UnsupportedAlgorithm:
pass
- raise UnsupportedAlgorithm("This backend does not support CMAC",
+ raise UnsupportedAlgorithm("This backend does not support CMAC.",
_Reasons.UNSUPPORTED_CIPHER)
diff --git a/cryptography/hazmat/backends/openssl/backend.py b/cryptography/hazmat/backends/openssl/backend.py
index c8a93ef6..5d9626d0 100644
--- a/cryptography/hazmat/backends/openssl/backend.py
+++ b/cryptography/hazmat/backends/openssl/backend.py
@@ -38,7 +38,7 @@ from cryptography.hazmat.primitives.ciphers.algorithms import (
AES, ARC4, Blowfish, CAST5, Camellia, IDEA, SEED, TripleDES
)
from cryptography.hazmat.primitives.ciphers.modes import (
- CBC, CFB, CTR, ECB, GCM, OFB
+ CBC, CFB, CFB8, CTR, ECB, GCM, OFB
)
@@ -114,11 +114,14 @@ class Backend(object):
def openssl_version_text(self):
"""
- Friendly string name of linked OpenSSL.
+ Friendly string name of the loaded OpenSSL library. This is not
+ necessarily the same version as it was compiled against.
Example: OpenSSL 1.0.1e 11 Feb 2013
"""
- return self._ffi.string(self._lib.OPENSSL_VERSION_TEXT).decode("ascii")
+ return self._ffi.string(
+ self._lib.SSLeay_version(self._lib.SSLEAY_VERSION)
+ ).decode("ascii")
def create_hmac_ctx(self, key, algorithm):
return _HMACContext(self, key, algorithm)
@@ -134,6 +137,14 @@ class Backend(object):
return _HashContext(self, algorithm)
def cipher_supported(self, cipher, mode):
+ if self._evp_cipher_supported(cipher, mode):
+ return True
+ elif isinstance(mode, CTR) and isinstance(cipher, AES):
+ return True
+ else:
+ return False
+
+ def _evp_cipher_supported(self, cipher, mode):
try:
adapter = self._cipher_registry[type(cipher), type(mode)]
except KeyError:
@@ -143,22 +154,25 @@ class Backend(object):
def register_cipher_adapter(self, cipher_cls, mode_cls, adapter):
if (cipher_cls, mode_cls) in self._cipher_registry:
- raise ValueError("Duplicate registration for: {0} {1}".format(
+ raise ValueError("Duplicate registration for: {0} {1}.".format(
cipher_cls, mode_cls)
)
self._cipher_registry[cipher_cls, mode_cls] = adapter
def _register_default_ciphers(self):
- for cipher_cls, mode_cls in itertools.product(
- [AES, Camellia],
- [CBC, CTR, ECB, OFB, CFB],
- ):
+ for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8]:
self.register_cipher_adapter(
- cipher_cls,
+ AES,
mode_cls,
GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
)
- for mode_cls in [CBC, CFB, OFB]:
+ for mode_cls in [CBC, CTR, ECB, OFB, CFB]:
+ self.register_cipher_adapter(
+ Camellia,
+ mode_cls,
+ GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}")
+ )
+ for mode_cls in [CBC, CFB, CFB8, OFB]:
self.register_cipher_adapter(
TripleDES,
mode_cls,
@@ -197,10 +211,24 @@ class Backend(object):
)
def create_symmetric_encryption_ctx(self, cipher, mode):
- return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT)
+ if (isinstance(mode, CTR) and isinstance(cipher, AES)
+ and not self._evp_cipher_supported(cipher, mode)):
+ # This is needed to provide support for AES CTR mode in OpenSSL
+ # 0.9.8. It can be removed when we drop 0.9.8 support (RHEL 5
+ # extended life ends 2020).
+ return _AESCTRCipherContext(self, cipher, mode)
+ else:
+ return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT)
def create_symmetric_decryption_ctx(self, cipher, mode):
- return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
+ if (isinstance(mode, CTR) and isinstance(cipher, AES)
+ and not self._evp_cipher_supported(cipher, mode)):
+ # This is needed to provide support for AES CTR mode in OpenSSL
+ # 0.9.8. It can be removed when we drop 0.9.8 support (RHEL 5
+ # extended life ends 2020).
+ return _AESCTRCipherContext(self, cipher, mode)
+ else:
+ return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT)
def pbkdf2_hmac_supported(self, algorithm):
if self._lib.Cryptography_HAS_PBKDF2_HMAC:
@@ -233,7 +261,7 @@ class Backend(object):
if not isinstance(algorithm, hashes.SHA1):
raise UnsupportedAlgorithm(
"This version of OpenSSL only supports PBKDF2HMAC with "
- "SHA1",
+ "SHA1.",
_Reasons.UNSUPPORTED_HASH
)
res = self._lib.PKCS5_PBKDF2_HMAC_SHA1(
@@ -271,7 +299,7 @@ class Backend(object):
def _unknown_error(self, error):
return InternalError(
"Unknown error code {0} from OpenSSL, "
- "you should probably file a bug. {1}".format(
+ "you should probably file a bug. {1}.".format(
error.code, self._err_string(error.code)
)
)
@@ -328,13 +356,13 @@ class Backend(object):
def generate_rsa_private_key(self, public_exponent, key_size):
if public_exponent < 3:
- raise ValueError("public_exponent must be >= 3")
+ raise ValueError("public_exponent must be >= 3.")
if public_exponent & 1 == 0:
- raise ValueError("public_exponent must be odd")
+ raise ValueError("public_exponent must be odd.")
if key_size < 512:
- raise ValueError("key_size must be at least 512-bits")
+ raise ValueError("key_size must be at least 512-bits.")
ctx = self._lib.RSA_new()
assert ctx != self._ffi.NULL
@@ -509,13 +537,13 @@ class Backend(object):
def generate_dsa_parameters(self, key_size):
if key_size not in (1024, 2048, 3072):
raise ValueError(
- "Key size must be 1024 or 2048 or 3072 bits")
+ "Key size must be 1024 or 2048 or 3072 bits.")
if (self._lib.OPENSSL_VERSION_NUMBER < 0x1000000f and
key_size > 1024):
raise ValueError(
"Key size must be 1024 because OpenSSL < 1.0.0 doesn't "
- "support larger key sizes")
+ "support larger key sizes.")
ctx = self._lib.DSA_new()
assert ctx != self._ffi.NULL
@@ -614,28 +642,28 @@ class Backend(object):
padding_enum = self._lib.RSA_PKCS1_OAEP_PADDING
if not isinstance(padding._mgf, MGF1):
raise UnsupportedAlgorithm(
- "Only MGF1 is supported by this backend",
+ "Only MGF1 is supported by this backend.",
_Reasons.UNSUPPORTED_MGF
)
if not isinstance(padding._mgf._algorithm, hashes.SHA1):
raise UnsupportedAlgorithm(
"This backend supports only SHA1 inside MGF1 when "
- "using OAEP",
+ "using OAEP.",
_Reasons.UNSUPPORTED_HASH
)
if padding._label is not None and padding._label != b"":
- raise ValueError("This backend does not support OAEP labels")
+ raise ValueError("This backend does not support OAEP labels.")
if not isinstance(padding._algorithm, hashes.SHA1):
raise UnsupportedAlgorithm(
- "This backend only supports SHA1 when using OAEP",
+ "This backend only supports SHA1 when using OAEP.",
_Reasons.UNSUPPORTED_HASH
)
else:
raise UnsupportedAlgorithm(
- "{0} is not supported by this backend".format(
+ "{0} is not supported by this backend.".format(
padding.name
),
_Reasons.UNSUPPORTED_PADDING
@@ -715,14 +743,14 @@ class Backend(object):
self._lib.RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE)
raise ValueError(
"Data too long for key size. Encrypt less data or use a "
- "larger key size"
+ "larger key size."
)
else:
assert (
errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_01 or
errors[0].reason == self._lib.RSA_R_BLOCK_TYPE_IS_NOT_02
)
- raise ValueError("Decryption failed")
+ raise ValueError("Decryption failed.")
def cmac_algorithm_supported(self, algorithm):
return (
@@ -838,7 +866,7 @@ class _CipherContext(object):
except KeyError:
raise UnsupportedAlgorithm(
"cipher {0} in {1} mode is not supported "
- "by this backend".format(
+ "by this backend.".format(
cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
)
@@ -847,7 +875,7 @@ class _CipherContext(object):
if evp_cipher == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"cipher {0} in {1} mode is not supported "
- "by this backend".format(
+ "by this backend.".format(
cipher.name, mode.name if mode else mode),
_Reasons.UNSUPPORTED_CIPHER
)
@@ -973,6 +1001,41 @@ class _CipherContext(object):
return self._tag
+@utils.register_interface(interfaces.CipherContext)
+class _AESCTRCipherContext(object):
+ """
+ This is needed to provide support for AES CTR mode in OpenSSL 0.9.8. It can
+ be removed when we drop 0.9.8 support (RHEL5 extended life ends 2020).
+ """
+ def __init__(self, backend, cipher, mode):
+ self._backend = backend
+
+ self._key = self._backend._ffi.new("AES_KEY *")
+ assert self._key != self._backend._ffi.NULL
+ res = self._backend._lib.AES_set_encrypt_key(
+ cipher.key, len(cipher.key) * 8, self._key
+ )
+ assert res == 0
+ self._ecount = self._backend._ffi.new("char[]", 16)
+ self._nonce = self._backend._ffi.new("char[16]", mode.nonce)
+ self._num = self._backend._ffi.new("unsigned int *", 0)
+
+ def update(self, data):
+ buf = self._backend._ffi.new("unsigned char[]", len(data))
+ self._backend._lib.AES_ctr128_encrypt(
+ data, buf, len(data), self._key, self._nonce,
+ self._ecount, self._num
+ )
+ return self._backend._ffi.buffer(buf)[:]
+
+ def finalize(self):
+ self._key = None
+ self._ecount = None
+ self._nonce = None
+ self._num = None
+ return b""
+
+
@utils.register_interface(interfaces.HashContext)
class _HashContext(object):
def __init__(self, backend, algorithm, ctx=None):
@@ -988,7 +1051,7 @@ class _HashContext(object):
algorithm.name.encode("ascii"))
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend".format(
+ "{0} is not a supported hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
@@ -1039,7 +1102,7 @@ class _HMACContext(object):
algorithm.name.encode('ascii'))
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
- "{0} is not a supported hash on this backend".format(
+ "{0} is not a supported hash on this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
@@ -1108,7 +1171,7 @@ class _RSASignatureContext(object):
if not isinstance(padding, interfaces.AsymmetricPadding):
raise TypeError(
- "Expected provider of interfaces.AsymmetricPadding")
+ "Expected provider of interfaces.AsymmetricPadding.")
if isinstance(padding, PKCS1v15):
if self._backend._lib.Cryptography_HAS_PKEY_CTX:
@@ -1119,7 +1182,7 @@ class _RSASignatureContext(object):
elif isinstance(padding, PSS):
if not isinstance(padding._mgf, MGF1):
raise UnsupportedAlgorithm(
- "Only MGF1 is supported by this backend",
+ "Only MGF1 is supported by this backend.",
_Reasons.UNSUPPORTED_MGF
)
@@ -1144,7 +1207,7 @@ class _RSASignatureContext(object):
self._finalize_method = self._finalize_pss
else:
raise UnsupportedAlgorithm(
- "{0} is not supported by this backend".format(padding.name),
+ "{0} is not supported by this backend.".format(padding.name),
_Reasons.UNSUPPORTED_PADDING
)
@@ -1154,13 +1217,13 @@ class _RSASignatureContext(object):
def update(self, data):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
self._hash_ctx.update(data)
def finalize(self):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
evp_pkey = self._backend._rsa_private_key_to_evp_pkey(
self._private_key)
@@ -1308,7 +1371,7 @@ class _RSAVerificationContext(object):
if not isinstance(padding, interfaces.AsymmetricPadding):
raise TypeError(
- "Expected provider of interfaces.AsymmetricPadding")
+ "Expected provider of interfaces.AsymmetricPadding.")
if isinstance(padding, PKCS1v15):
if self._backend._lib.Cryptography_HAS_PKEY_CTX:
@@ -1319,7 +1382,7 @@ class _RSAVerificationContext(object):
elif isinstance(padding, PSS):
if not isinstance(padding._mgf, MGF1):
raise UnsupportedAlgorithm(
- "Only MGF1 is supported by this backend",
+ "Only MGF1 is supported by this backend.",
_Reasons.UNSUPPORTED_MGF
)
@@ -1346,7 +1409,7 @@ class _RSAVerificationContext(object):
self._verify_method = self._verify_pss
else:
raise UnsupportedAlgorithm(
- "{0} is not supported by this backend".format(padding.name),
+ "{0} is not supported by this backend.".format(padding.name),
_Reasons.UNSUPPORTED_PADDING
)
@@ -1356,13 +1419,13 @@ class _RSAVerificationContext(object):
def update(self, data):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
self._hash_ctx.update(data)
def verify(self):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
evp_pkey = self._backend._rsa_public_key_to_evp_pkey(
self._public_key)
@@ -1496,13 +1559,13 @@ class _DSAVerificationContext(object):
def update(self, data):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
self._hash_ctx.update(data)
def verify(self):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
self._dsa_cdata = self._backend._dsa_cdata_from_public_key(
self._public_key)
@@ -1541,13 +1604,13 @@ class _DSASignatureContext(object):
def update(self, data):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
self._hash_ctx.update(data)
def finalize(self):
if self._hash_ctx is None:
- raise AlreadyFinalized("Context has already been finalized")
+ raise AlreadyFinalized("Context has already been finalized.")
data_to_sign = self._hash_ctx.finalize()
self._hash_ctx = None
@@ -1570,7 +1633,7 @@ class _DSASignatureContext(object):
class _CMACContext(object):
def __init__(self, backend, algorithm, ctx=None):
if not backend.cmac_algorithm_supported(algorithm):
- raise UnsupportedAlgorithm("This backend does not support CMAC",
+ raise UnsupportedAlgorithm("This backend does not support CMAC.",
_Reasons.UNSUPPORTED_CIPHER)
self._backend = backend
diff --git a/cryptography/hazmat/bindings/openssl/aes.py b/cryptography/hazmat/bindings/openssl/aes.py
index 17c154cf..b0e00721 100644
--- a/cryptography/hazmat/bindings/openssl/aes.py
+++ b/cryptography/hazmat/bindings/openssl/aes.py
@@ -29,6 +29,12 @@ typedef struct aes_key_st AES_KEY;
FUNCTIONS = """
int AES_set_encrypt_key(const unsigned char *, const int, AES_KEY *);
int AES_set_decrypt_key(const unsigned char *, const int, AES_KEY *);
+/* The ctr128_encrypt function is only useful in 0.9.8. You should use EVP for
+ this in 1.0.0+. */
+void AES_ctr128_encrypt(const unsigned char *, unsigned char *,
+ const unsigned long, const AES_KEY *,
+ unsigned char[], unsigned char[], unsigned int *);
+
"""
MACROS = """
diff --git a/cryptography/hazmat/bindings/openssl/binding.py b/cryptography/hazmat/bindings/openssl/binding.py
index aa0525ff..464081b0 100644
--- a/cryptography/hazmat/bindings/openssl/binding.py
+++ b/cryptography/hazmat/bindings/openssl/binding.py
@@ -149,7 +149,7 @@ class Binding(object):
lock.release()
else:
raise RuntimeError(
- "Unknown lock mode {0}: lock={1}, file={2}, line={3}".format(
+ "Unknown lock mode {0}: lock={1}, file={2}, line={3}.".format(
mode, n, file, line
)
)
diff --git a/cryptography/hazmat/bindings/openssl/ec.py b/cryptography/hazmat/bindings/openssl/ec.py
index 45c17c2e..26fc8ff0 100644
--- a/cryptography/hazmat/bindings/openssl/ec.py
+++ b/cryptography/hazmat/bindings/openssl/ec.py
@@ -27,6 +27,8 @@ static const int Cryptography_HAS_EC_1_0_1;
static const int Cryptography_HAS_EC_NISTP_64_GCC_128;
static const int Cryptography_HAS_EC2M;
+static const int OPENSSL_EC_NAMED_CURVE;
+
typedef ... EC_KEY;
typedef ... EC_GROUP;
typedef ... EC_POINT;
@@ -61,6 +63,8 @@ int EC_GROUP_set_curve_GF2m(
int EC_GROUP_get_curve_GF2m(
const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
+int EC_GROUP_get_degree(const EC_GROUP *);
+
const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *);
const EC_POINT *EC_GROUP_get0_generator(const EC_GROUP *);
int EC_GROUP_get_curve_name(const EC_GROUP *);
@@ -198,6 +202,7 @@ int EC_METHOD_get_field_type(const EC_METHOD *);
CUSTOMIZATIONS = """
#ifdef OPENSSL_NO_EC
static const long Cryptography_HAS_EC = 0;
+
typedef void EC_KEY;
typedef void EC_GROUP;
typedef void EC_POINT;
@@ -208,6 +213,8 @@ typedef struct {
} EC_builtin_curve;
typedef long point_conversion_form_t;
+static const int OPENSSL_EC_NAMED_CURVE = 0;
+
void (*EC_KEY_free)(EC_KEY *) = NULL;
size_t (*EC_get_builtin_curves)(EC_builtin_curve *, size_t) = NULL;
EC_KEY *(*EC_KEY_new_by_curve_name)(int) = NULL;
@@ -250,6 +257,8 @@ int (*EC_GROUP_set_curve_GFp)(
int (*EC_GROUP_get_curve_GFp)(
const EC_GROUP *, BIGNUM *, BIGNUM *, BIGNUM *, BN_CTX *);
+int (*EC_GROUP_get_degree)(const EC_GROUP *) = NULL;
+
const EC_METHOD *(*EC_GROUP_method_of)(const EC_GROUP *) = NULL;
const EC_POINT *(*EC_GROUP_get0_generator)(const EC_GROUP *) = NULL;
int (*EC_GROUP_get_curve_name)(const EC_GROUP *) = NULL;
@@ -389,6 +398,7 @@ static const long Cryptography_HAS_EC2M = 1;
CONDITIONAL_NAMES = {
"Cryptography_HAS_EC": [
+ "OPENSSL_EC_NAMED_CURVE",
"EC_GROUP_new",
"EC_GROUP_free",
"EC_GROUP_clear_free",
@@ -399,6 +409,7 @@ CONDITIONAL_NAMES = {
"EC_GROUP_method_of",
"EC_GROUP_get0_generator",
"EC_GROUP_get_curve_name",
+ "EC_GROUP_get_degree",
"EC_KEY_free",
"EC_get_builtin_curves",
"EC_KEY_new_by_curve_name",
diff --git a/cryptography/hazmat/bindings/openssl/opensslv.py b/cryptography/hazmat/bindings/openssl/opensslv.py
index e4aa6212..ef6e057b 100644
--- a/cryptography/hazmat/bindings/openssl/opensslv.py
+++ b/cryptography/hazmat/bindings/openssl/opensslv.py
@@ -18,6 +18,8 @@ INCLUDES = """
"""
TYPES = """
+/* Note that these will be resolved when cryptography is compiled and are NOT
+ guaranteed to be the version that it actually loads. */
static const int OPENSSL_VERSION_NUMBER;
static const char *const OPENSSL_VERSION_TEXT;
"""
diff --git a/cryptography/hazmat/bindings/openssl/ssl.py b/cryptography/hazmat/bindings/openssl/ssl.py
index 0b15411c..94b96d98 100644
--- a/cryptography/hazmat/bindings/openssl/ssl.py
+++ b/cryptography/hazmat/bindings/openssl/ssl.py
@@ -15,6 +15,8 @@ from __future__ import absolute_import, division, print_function
INCLUDES = """
#include <openssl/ssl.h>
+
+typedef STACK_OF(SSL_CIPHER) Cryptography_STACK_OF_SSL_CIPHER;
"""
TYPES = """
@@ -24,6 +26,7 @@ TYPES = """
static const long Cryptography_HAS_SSL2;
static const long Cryptography_HAS_TLSv1_1;
static const long Cryptography_HAS_TLSv1_2;
+static const long Cryptography_HAS_SECURE_RENEGOTIATION;
/* Internally invented symbol to tell us if SNI is supported */
static const long Cryptography_HAS_TLSEXT_HOSTNAME;
@@ -84,6 +87,8 @@ static const long SSL_OP_COOKIE_EXCHANGE;
static const long SSL_OP_NO_TICKET;
static const long SSL_OP_ALL;
static const long SSL_OP_SINGLE_ECDH_USE;
+static const long SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+static const long SSL_OP_LEGACY_SERVER_CONNECT;
static const long SSL_VERIFY_PEER;
static const long SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
static const long SSL_VERIFY_CLIENT_ONCE;
@@ -153,6 +158,8 @@ typedef struct {
static const long TLSEXT_NAMETYPE_host_name;
typedef ... SSL_CIPHER;
+typedef ... Cryptography_STACK_OF_SSL_CIPHER;
+typedef ... COMP_METHOD;
"""
FUNCTIONS = """
@@ -190,6 +197,11 @@ int SSL_get_error(const SSL *, int);
int SSL_do_handshake(SSL *);
int SSL_shutdown(SSL *);
const char *SSL_get_cipher_list(const SSL *, int);
+Cryptography_STACK_OF_SSL_CIPHER *SSL_get_ciphers(const SSL *);
+
+const COMP_METHOD *SSL_get_current_compression(SSL *);
+const COMP_METHOD *SSL_get_current_expansion(SSL *);
+const char *SSL_COMP_get_name(const COMP_METHOD *);
/* context */
void SSL_CTX_free(SSL_CTX *);
@@ -248,6 +260,7 @@ int SSL_want_read(const SSL *);
int SSL_want_write(const SSL *);
long SSL_total_renegotiations(SSL *);
+long SSL_get_secure_renegotiation_support(SSL *);
/* Defined as unsigned long because SSL_OP_ALL is greater than signed 32-bit
and Windows defines long as 32-bit. */
@@ -351,9 +364,23 @@ int SSL_select_next_proto(unsigned char **, unsigned char *,
const unsigned char *, unsigned int);
void SSL_get0_next_proto_negotiated(const SSL *,
const unsigned char **, unsigned *);
+
+int sk_SSL_CIPHER_num(Cryptography_STACK_OF_SSL_CIPHER *);
+SSL_CIPHER *sk_SSL_CIPHER_value(Cryptography_STACK_OF_SSL_CIPHER *, int);
"""
CUSTOMIZATIONS = """
+/** Secure renegotiation is supported in OpenSSL >= 0.9.8m
+ * But some Linux distributions have back ported some features.
+ */
+#ifndef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
+static const long Cryptography_HAS_SECURE_RENEGOTIATION = 0;
+long (*SSL_get_secure_renegotiation_support)(SSL *) = NULL;
+const long SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION = 0;
+const long SSL_OP_LEGACY_SERVER_CONNECT = 0;
+#else
+static const long Cryptography_HAS_SECURE_RENEGOTIATION = 1;
+#endif
#ifdef OPENSSL_NO_SSL2
static const long Cryptography_HAS_SSL2 = 0;
SSL_METHOD* (*SSLv2_method)(void) = NULL;
@@ -551,5 +578,11 @@ CONDITIONAL_NAMES = {
"SSL_CTX_set_next_proto_select_cb",
"SSL_select_next_proto",
"SSL_get0_next_proto_negotiated",
- ]
+ ],
+
+ "Cryptography_HAS_SECURE_RENEGOTIATION": [
+ "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION",
+ "SSL_OP_LEGACY_SERVER_CONNECT",
+ "SSL_get_secure_renegotiation_support",
+ ],
}
diff --git a/cryptography/hazmat/primitives/asymmetric/dsa.py b/cryptography/hazmat/primitives/asymmetric/dsa.py
index aa3cdc90..a9ae9ecb 100644
--- a/cryptography/hazmat/primitives/asymmetric/dsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/dsa.py
@@ -27,7 +27,7 @@ def _check_dsa_parameters(modulus, subgroup_order, generator):
not isinstance(subgroup_order, six.integer_types) or
not isinstance(generator, six.integer_types)
):
- raise TypeError("DSA parameters must be integers")
+ raise TypeError("DSA parameters must be integers.")
if (utils.bit_length(modulus),
utils.bit_length(subgroup_order)) not in (
@@ -36,10 +36,10 @@ def _check_dsa_parameters(modulus, subgroup_order, generator):
(3072, 256)):
raise ValueError("modulus and subgroup_order lengths must be "
"one of these pairs (1024, 160) or (2048, 256) "
- "or (3072, 256)")
+ "or (3072, 256).")
if generator <= 1 or generator >= modulus:
- raise ValueError("generator must be > 1 and < modulus")
+ raise ValueError("generator must be > 1 and < modulus.")
@utils.register_interface(interfaces.DSAParameters)
@@ -55,7 +55,7 @@ class DSAParameters(object):
def generate(cls, key_size, backend):
if not isinstance(backend, DSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement DSABackend",
+ "Backend object does not implement DSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -94,13 +94,13 @@ class DSAPrivateKey(object):
not isinstance(x, six.integer_types) or
not isinstance(y, six.integer_types)
):
- raise TypeError("DSAPrivateKey arguments must be integers")
+ raise TypeError("DSAPrivateKey arguments must be integers.")
if x <= 0 or x >= subgroup_order:
- raise ValueError("x must be > 0 and < subgroup_order")
+ raise ValueError("x must be > 0 and < subgroup_order.")
if y != pow(generator, x, modulus):
- raise ValueError("y must be equal to (generator ** x % modulus)")
+ raise ValueError("y must be equal to (generator ** x % modulus).")
self._modulus = modulus
self._subgroup_order = subgroup_order
@@ -112,7 +112,7 @@ class DSAPrivateKey(object):
def generate(cls, parameters, backend):
if not isinstance(backend, DSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement DSABackend",
+ "Backend object does not implement DSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -121,7 +121,7 @@ class DSAPrivateKey(object):
def signer(self, algorithm, backend):
if not isinstance(backend, DSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement DSABackend",
+ "Backend object does not implement DSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -153,7 +153,7 @@ class DSAPublicKey(object):
def __init__(self, modulus, subgroup_order, generator, y):
_check_dsa_parameters(modulus, subgroup_order, generator)
if not isinstance(y, six.integer_types):
- raise TypeError("y must be an integer")
+ raise TypeError("y must be an integer.")
self._modulus = modulus
self._subgroup_order = subgroup_order
@@ -163,7 +163,7 @@ class DSAPublicKey(object):
def verifier(self, signature, algorithm, backend):
if not isinstance(backend, DSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement DSABackend",
+ "Backend object does not implement DSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
diff --git a/cryptography/hazmat/primitives/asymmetric/padding.py b/cryptography/hazmat/primitives/asymmetric/padding.py
index f7710c49..d44bbda5 100644
--- a/cryptography/hazmat/primitives/asymmetric/padding.py
+++ b/cryptography/hazmat/primitives/asymmetric/padding.py
@@ -44,13 +44,13 @@ class PSS(object):
else:
if (not isinstance(salt_length, six.integer_types) and
salt_length is not self.MAX_LENGTH):
- raise TypeError("salt_length must be an integer")
+ raise TypeError("salt_length must be an integer.")
if salt_length is not self.MAX_LENGTH and salt_length < 0:
- raise ValueError("salt_length must be zero or greater")
+ raise ValueError("salt_length must be zero or greater.")
if salt_length is None and self._mgf._salt_length is None:
- raise ValueError("You must supply salt_length")
+ raise ValueError("You must supply salt_length.")
self._salt_length = salt_length
@@ -86,9 +86,9 @@ class MGF1(object):
)
if (not isinstance(salt_length, six.integer_types) and
salt_length is not self.MAX_LENGTH):
- raise TypeError("salt_length must be an integer")
+ raise TypeError("salt_length must be an integer.")
if salt_length is not self.MAX_LENGTH and salt_length < 0:
- raise ValueError("salt_length must be zero or greater")
+ raise ValueError("salt_length must be zero or greater.")
self._salt_length = salt_length
diff --git a/cryptography/hazmat/primitives/asymmetric/rsa.py b/cryptography/hazmat/primitives/asymmetric/rsa.py
index 5d3bb36c..a9f57838 100644
--- a/cryptography/hazmat/primitives/asymmetric/rsa.py
+++ b/cryptography/hazmat/primitives/asymmetric/rsa.py
@@ -28,16 +28,16 @@ class RSAPublicKey(object):
not isinstance(public_exponent, six.integer_types) or
not isinstance(modulus, six.integer_types)
):
- raise TypeError("RSAPublicKey arguments must be integers")
+ raise TypeError("RSAPublicKey arguments must be integers.")
if modulus < 3:
- raise ValueError("modulus must be >= 3")
+ raise ValueError("modulus must be >= 3.")
if public_exponent < 3 or public_exponent >= modulus:
- raise ValueError("public_exponent must be >= 3 and < modulus")
+ raise ValueError("public_exponent must be >= 3 and < modulus.")
if public_exponent & 1 == 0:
- raise ValueError("public_exponent must be odd")
+ raise ValueError("public_exponent must be odd.")
self._public_exponent = public_exponent
self._modulus = modulus
@@ -45,7 +45,7 @@ class RSAPublicKey(object):
def verifier(self, signature, padding, algorithm, backend):
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement RSABackend",
+ "Backend object does not implement RSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -55,7 +55,7 @@ class RSAPublicKey(object):
def encrypt(self, plaintext, padding, backend):
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement RSABackend",
+ "Backend object does not implement RSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -132,43 +132,43 @@ class RSAPrivateKey(object):
not isinstance(public_exponent, six.integer_types) or
not isinstance(modulus, six.integer_types)
):
- raise TypeError("RSAPrivateKey arguments must be integers")
+ raise TypeError("RSAPrivateKey arguments must be integers.")
if modulus < 3:
- raise ValueError("modulus must be >= 3")
+ raise ValueError("modulus must be >= 3.")
if p >= modulus:
- raise ValueError("p must be < modulus")
+ raise ValueError("p must be < modulus.")
if q >= modulus:
- raise ValueError("q must be < modulus")
+ raise ValueError("q must be < modulus.")
if dmp1 >= modulus:
- raise ValueError("dmp1 must be < modulus")
+ raise ValueError("dmp1 must be < modulus.")
if dmq1 >= modulus:
- raise ValueError("dmq1 must be < modulus")
+ raise ValueError("dmq1 must be < modulus.")
if iqmp >= modulus:
- raise ValueError("iqmp must be < modulus")
+ raise ValueError("iqmp must be < modulus.")
if private_exponent >= modulus:
- raise ValueError("private_exponent must be < modulus")
+ raise ValueError("private_exponent must be < modulus.")
if public_exponent < 3 or public_exponent >= modulus:
- raise ValueError("public_exponent must be >= 3 and < modulus")
+ raise ValueError("public_exponent must be >= 3 and < modulus.")
if public_exponent & 1 == 0:
- raise ValueError("public_exponent must be odd")
+ raise ValueError("public_exponent must be odd.")
if dmp1 & 1 == 0:
- raise ValueError("dmp1 must be odd")
+ raise ValueError("dmp1 must be odd.")
if dmq1 & 1 == 0:
- raise ValueError("dmq1 must be odd")
+ raise ValueError("dmq1 must be odd.")
if p * q != modulus:
- raise ValueError("p*q must equal modulus")
+ raise ValueError("p*q must equal modulus.")
self._p = p
self._q = q
@@ -183,7 +183,7 @@ class RSAPrivateKey(object):
def generate(cls, public_exponent, key_size, backend):
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement RSABackend",
+ "Backend object does not implement RSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -192,7 +192,7 @@ class RSAPrivateKey(object):
def signer(self, padding, algorithm, backend):
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement RSABackend",
+ "Backend object does not implement RSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -201,7 +201,7 @@ class RSAPrivateKey(object):
def decrypt(self, ciphertext, padding, backend):
if not isinstance(backend, RSABackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement RSABackend",
+ "Backend object does not implement RSABackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
diff --git a/cryptography/hazmat/primitives/ciphers/algorithms.py b/cryptography/hazmat/primitives/ciphers/algorithms.py
index 52daf178..bd8437c2 100644
--- a/cryptography/hazmat/primitives/ciphers/algorithms.py
+++ b/cryptography/hazmat/primitives/ciphers/algorithms.py
@@ -20,7 +20,7 @@ from cryptography.hazmat.primitives import interfaces
def _verify_key_size(algorithm, key):
# Verify that the key size matches the expected key size
if len(key) * 8 not in algorithm.key_sizes:
- raise ValueError("Invalid key size ({0}) for {1}".format(
+ raise ValueError("Invalid key size ({0}) for {1}.".format(
len(key) * 8, algorithm.name
))
return key
diff --git a/cryptography/hazmat/primitives/ciphers/base.py b/cryptography/hazmat/primitives/ciphers/base.py
index 2274e945..e3fe5adc 100644
--- a/cryptography/hazmat/primitives/ciphers/base.py
+++ b/cryptography/hazmat/primitives/ciphers/base.py
@@ -26,12 +26,14 @@ class Cipher(object):
def __init__(self, algorithm, mode, backend):
if not isinstance(backend, CipherBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement CipherBackend",
+ "Backend object does not implement CipherBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not isinstance(algorithm, interfaces.CipherAlgorithm):
- raise TypeError("Expected interface of interfaces.CipherAlgorithm")
+ raise TypeError(
+ "Expected interface of interfaces.CipherAlgorithm."
+ )
if mode is not None:
mode.validate_for_algorithm(algorithm)
@@ -44,7 +46,7 @@ class Cipher(object):
if isinstance(self.mode, interfaces.ModeWithAuthenticationTag):
if self.mode.tag is not None:
raise ValueError(
- "Authentication tag must be None when encrypting"
+ "Authentication tag must be None when encrypting."
)
ctx = self._backend.create_symmetric_encryption_ctx(
self.algorithm, self.mode
@@ -55,7 +57,7 @@ class Cipher(object):
if isinstance(self.mode, interfaces.ModeWithAuthenticationTag):
if self.mode.tag is None:
raise ValueError(
- "Authentication tag must be provided when decrypting"
+ "Authentication tag must be provided when decrypting."
)
ctx = self._backend.create_symmetric_decryption_ctx(
self.algorithm, self.mode
@@ -79,12 +81,12 @@ class _CipherContext(object):
def update(self, data):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
return self._ctx.update(data)
def finalize(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
data = self._ctx.finalize()
self._ctx = None
return data
@@ -100,13 +102,13 @@ class _AEADCipherContext(object):
def update(self, data):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
self._updated = True
return self._ctx.update(data)
def finalize(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
data = self._ctx.finalize()
self._tag = self._ctx.tag
self._ctx = None
@@ -114,9 +116,9 @@ class _AEADCipherContext(object):
def authenticate_additional_data(self, data):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
if self._updated:
- raise AlreadyUpdated("Update has been called on this context")
+ raise AlreadyUpdated("Update has been called on this context.")
self._ctx.authenticate_additional_data(data)
@@ -126,5 +128,5 @@ class _AEADEncryptionContext(_AEADCipherContext):
def tag(self):
if self._ctx is not None:
raise NotYetFinalized("You must finalize encryption before "
- "getting the tag")
+ "getting the tag.")
return self._tag
diff --git a/cryptography/hazmat/primitives/ciphers/modes.py b/cryptography/hazmat/primitives/ciphers/modes.py
index 739f23dd..e70a9db5 100644
--- a/cryptography/hazmat/primitives/ciphers/modes.py
+++ b/cryptography/hazmat/primitives/ciphers/modes.py
@@ -17,6 +17,13 @@ from cryptography import utils
from cryptography.hazmat.primitives import interfaces
+def _check_iv_length(mode, algorithm):
+ if len(mode.initialization_vector) * 8 != algorithm.block_size:
+ raise ValueError("Invalid IV size ({0}) for {1}.".format(
+ len(mode.initialization_vector), mode.name
+ ))
+
+
@utils.register_interface(interfaces.Mode)
@utils.register_interface(interfaces.ModeWithInitializationVector)
class CBC(object):
@@ -25,11 +32,7 @@ class CBC(object):
def __init__(self, initialization_vector):
self.initialization_vector = initialization_vector
- def validate_for_algorithm(self, algorithm):
- if len(self.initialization_vector) * 8 != algorithm.block_size:
- raise ValueError("Invalid iv size ({0}) for {1}".format(
- len(self.initialization_vector), self.name
- ))
+ validate_for_algorithm = _check_iv_length
@utils.register_interface(interfaces.Mode)
@@ -48,11 +51,7 @@ class OFB(object):
def __init__(self, initialization_vector):
self.initialization_vector = initialization_vector
- def validate_for_algorithm(self, algorithm):
- if len(self.initialization_vector) * 8 != algorithm.block_size:
- raise ValueError("Invalid iv size ({0}) for {1}".format(
- len(self.initialization_vector), self.name
- ))
+ validate_for_algorithm = _check_iv_length
@utils.register_interface(interfaces.Mode)
@@ -63,11 +62,18 @@ class CFB(object):
def __init__(self, initialization_vector):
self.initialization_vector = initialization_vector
- def validate_for_algorithm(self, algorithm):
- if len(self.initialization_vector) * 8 != algorithm.block_size:
- raise ValueError("Invalid iv size ({0}) for {1}".format(
- len(self.initialization_vector), self.name
- ))
+ validate_for_algorithm = _check_iv_length
+
+
+@utils.register_interface(interfaces.Mode)
+@utils.register_interface(interfaces.ModeWithInitializationVector)
+class CFB8(object):
+ name = "CFB8"
+
+ def __init__(self, initialization_vector):
+ self.initialization_vector = initialization_vector
+
+ validate_for_algorithm = _check_iv_length
@utils.register_interface(interfaces.Mode)
@@ -80,7 +86,7 @@ class CTR(object):
def validate_for_algorithm(self, algorithm):
if len(self.nonce) * 8 != algorithm.block_size:
- raise ValueError("Invalid nonce size ({0}) for {1}".format(
+ raise ValueError("Invalid nonce size ({0}) for {1}.".format(
len(self.nonce), self.name
))
@@ -97,7 +103,7 @@ class GCM(object):
# for it
if tag is not None and len(tag) < 4:
raise ValueError(
- "Authentication tag must be 4 bytes or longer"
+ "Authentication tag must be 4 bytes or longer."
)
self.initialization_vector = initialization_vector
diff --git a/cryptography/hazmat/primitives/cmac.py b/cryptography/hazmat/primitives/cmac.py
index 7e7f65ab..fa463ae0 100644
--- a/cryptography/hazmat/primitives/cmac.py
+++ b/cryptography/hazmat/primitives/cmac.py
@@ -13,8 +13,6 @@
from __future__ import absolute_import, division, print_function
-import six
-
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
@@ -28,13 +26,13 @@ class CMAC(object):
def __init__(self, algorithm, backend, ctx=None):
if not isinstance(backend, CMACBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement CMACBackend",
+ "Backend object does not implement CMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not isinstance(algorithm, interfaces.BlockCipherAlgorithm):
raise TypeError(
- "Expected instance of interfaces.BlockCipherAlgorithm"
+ "Expected instance of interfaces.BlockCipherAlgorithm."
)
self._algorithm = algorithm
@@ -46,28 +44,28 @@ class CMAC(object):
def update(self, data):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
- if isinstance(data, six.text_type):
- raise TypeError("Unicode-objects must be encoded before hashing")
+ raise AlreadyFinalized("Context was already finalized.")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
self._ctx.update(data)
def finalize(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
return digest
def verify(self, signature):
- if isinstance(signature, six.text_type):
- raise TypeError("Unicode-objects must be encoded before verifying")
+ if not isinstance(signature, bytes):
+ raise TypeError("signature must be bytes.")
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")
def copy(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
return CMAC(
self._algorithm,
backend=self._backend,
diff --git a/cryptography/hazmat/primitives/constant_time.py b/cryptography/hazmat/primitives/constant_time.py
index e0e9aa37..4547da13 100644
--- a/cryptography/hazmat/primitives/constant_time.py
+++ b/cryptography/hazmat/primitives/constant_time.py
@@ -17,8 +17,6 @@ import sys
import cffi
-import six
-
from cryptography.hazmat.bindings.utils import _create_modulename
TYPES = """
@@ -57,7 +55,7 @@ _lib = _ffi.verify(
def bytes_eq(a, b):
- if isinstance(a, six.text_type) or isinstance(b, six.text_type):
- raise TypeError("Unicode-objects must be encoded before comparing")
+ if not isinstance(a, bytes) or not isinstance(b, bytes):
+ raise TypeError("a and b must be bytes.")
return _lib.Cryptography_constant_time_bytes_eq(a, len(a), b, len(b)) == 1
diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py
index 35b677b0..04f7620a 100644
--- a/cryptography/hazmat/primitives/hashes.py
+++ b/cryptography/hazmat/primitives/hashes.py
@@ -13,8 +13,6 @@
from __future__ import absolute_import, division, print_function
-import six
-
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, UnsupportedAlgorithm, _Reasons
@@ -28,7 +26,7 @@ class Hash(object):
def __init__(self, algorithm, backend, ctx=None):
if not isinstance(backend, HashBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement HashBackend",
+ "Backend object does not implement HashBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -45,21 +43,21 @@ class Hash(object):
def update(self, data):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
- if isinstance(data, six.text_type):
- raise TypeError("Unicode-objects must be encoded before hashing")
+ raise AlreadyFinalized("Context was already finalized.")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
self._ctx.update(data)
def copy(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
return Hash(
self.algorithm, backend=self._backend, ctx=self._ctx.copy()
)
def finalize(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
return digest
diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py
index afbb2f75..026ad3b3 100644
--- a/cryptography/hazmat/primitives/hmac.py
+++ b/cryptography/hazmat/primitives/hmac.py
@@ -13,8 +13,6 @@
from __future__ import absolute_import, division, print_function
-import six
-
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidSignature, UnsupportedAlgorithm, _Reasons
@@ -28,7 +26,7 @@ class HMAC(object):
def __init__(self, key, algorithm, backend, ctx=None):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement HMACBackend",
+ "Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -45,14 +43,14 @@ class HMAC(object):
def update(self, msg):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
- if isinstance(msg, six.text_type):
- raise TypeError("Unicode-objects must be encoded before hashing")
+ raise AlreadyFinalized("Context was already finalized.")
+ if not isinstance(msg, bytes):
+ raise TypeError("msg must be bytes.")
self._ctx.update(msg)
def copy(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
return HMAC(
self._key,
self.algorithm,
@@ -62,14 +60,14 @@ class HMAC(object):
def finalize(self):
if self._ctx is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
digest = self._ctx.finalize()
self._ctx = None
return digest
def verify(self, signature):
- if isinstance(signature, six.text_type):
- raise TypeError("Unicode-objects must be encoded before verifying")
+ if not isinstance(signature, bytes):
+ raise TypeError("signature must be bytes.")
digest = self.finalize()
if not constant_time.bytes_eq(digest, signature):
raise InvalidSignature("Signature did not match digest.")
diff --git a/cryptography/hazmat/primitives/kdf/hkdf.py b/cryptography/hazmat/primitives/kdf/hkdf.py
index 03500aaa..04d02b26 100644
--- a/cryptography/hazmat/primitives/kdf/hkdf.py
+++ b/cryptography/hazmat/primitives/kdf/hkdf.py
@@ -28,12 +28,53 @@ class HKDF(object):
def __init__(self, algorithm, length, salt, info, backend):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement HMACBackend",
+ "Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
self._algorithm = algorithm
+ if not isinstance(salt, bytes) and salt is not None:
+ raise TypeError("salt must be bytes.")
+
+ if salt is None:
+ salt = b"\x00" * (self._algorithm.digest_size // 8)
+
+ self._salt = salt
+
+ self._backend = backend
+
+ self._hkdf_expand = HKDFExpand(self._algorithm, length, info, backend)
+
+ def _extract(self, key_material):
+ h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend)
+ h.update(key_material)
+ return h.finalize()
+
+ def derive(self, key_material):
+ if not isinstance(key_material, bytes):
+ raise TypeError("key_material must be bytes.")
+
+ return self._hkdf_expand.derive(self._extract(key_material))
+
+ def verify(self, key_material, expected_key):
+ if not constant_time.bytes_eq(self.derive(key_material), expected_key):
+ raise InvalidKey
+
+
+@utils.register_interface(interfaces.KeyDerivationFunction)
+class HKDFExpand(object):
+ def __init__(self, algorithm, length, info, backend):
+ if not isinstance(backend, HMACBackend):
+ raise UnsupportedAlgorithm(
+ "Backend object does not implement HMACBackend.",
+ _Reasons.BACKEND_MISSING_INTERFACE
+ )
+
+ self._algorithm = algorithm
+
+ self._backend = backend
+
max_length = 255 * (algorithm.digest_size // 8)
if length > max_length:
@@ -44,32 +85,16 @@ class HKDF(object):
self._length = length
- if isinstance(salt, six.text_type):
- raise TypeError(
- "Unicode-objects must be encoded before using them as a salt.")
-
- if salt is None:
- salt = b"\x00" * (self._algorithm.digest_size // 8)
-
- self._salt = salt
-
- if isinstance(info, six.text_type):
- raise TypeError(
- "Unicode-objects must be encoded before using them as info.")
+ if not isinstance(info, bytes) and info is not None:
+ raise TypeError("info must be bytes.")
if info is None:
info = b""
self._info = info
- self._backend = backend
self._used = False
- def _extract(self, key_material):
- h = hmac.HMAC(self._salt, self._algorithm, backend=self._backend)
- h.update(key_material)
- return h.finalize()
-
def _expand(self, key_material):
output = [b""]
counter = 1
@@ -85,17 +110,14 @@ class HKDF(object):
return b"".join(output)[:self._length]
def derive(self, key_material):
- if isinstance(key_material, six.text_type):
- raise TypeError(
- "Unicode-objects must be encoded before using them as key "
- "material."
- )
+ if not isinstance(key_material, bytes):
+ raise TypeError("key_material must be bytes.")
if self._used:
raise AlreadyFinalized
self._used = True
- return self._expand(self._extract(key_material))
+ return self._expand(key_material)
def verify(self, key_material, expected_key):
if not constant_time.bytes_eq(self.derive(key_material), expected_key):
diff --git a/cryptography/hazmat/primitives/kdf/pbkdf2.py b/cryptography/hazmat/primitives/kdf/pbkdf2.py
index bec35bb2..97b6408c 100644
--- a/cryptography/hazmat/primitives/kdf/pbkdf2.py
+++ b/cryptography/hazmat/primitives/kdf/pbkdf2.py
@@ -13,8 +13,6 @@
from __future__ import absolute_import, division, print_function
-import six
-
from cryptography import utils
from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, UnsupportedAlgorithm, _Reasons
@@ -28,38 +26,32 @@ class PBKDF2HMAC(object):
def __init__(self, algorithm, length, salt, iterations, backend):
if not isinstance(backend, PBKDF2HMACBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement PBKDF2HMACBackend",
+ "Backend object does not implement PBKDF2HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
if not backend.pbkdf2_hmac_supported(algorithm):
raise UnsupportedAlgorithm(
- "{0} is not supported for PBKDF2 by this backend".format(
+ "{0} is not supported for PBKDF2 by this backend.".format(
algorithm.name),
_Reasons.UNSUPPORTED_HASH
)
self._used = False
self._algorithm = algorithm
self._length = length
- if isinstance(salt, six.text_type):
- raise TypeError(
- "Unicode-objects must be encoded before using them as key "
- "material."
- )
+ if not isinstance(salt, bytes):
+ raise TypeError("salt must be bytes.")
self._salt = salt
self._iterations = iterations
self._backend = backend
def derive(self, key_material):
if self._used:
- raise AlreadyFinalized("PBKDF2 instances can only be used once")
+ raise AlreadyFinalized("PBKDF2 instances can only be used once.")
self._used = True
- if isinstance(key_material, six.text_type):
- raise TypeError(
- "Unicode-objects must be encoded before using them as key "
- "material."
- )
+ if not isinstance(key_material, bytes):
+ raise TypeError("key_material must be bytes.")
return self._backend.derive_pbkdf2_hmac(
self._algorithm,
self._length,
diff --git a/cryptography/hazmat/primitives/padding.py b/cryptography/hazmat/primitives/padding.py
index c1a763b5..74f1ef2e 100644
--- a/cryptography/hazmat/primitives/padding.py
+++ b/cryptography/hazmat/primitives/padding.py
@@ -79,10 +79,10 @@ _lib = _ffi.verify(
class PKCS7(object):
def __init__(self, block_size):
if not (0 <= block_size < 256):
- raise ValueError("block_size must be in range(0, 256)")
+ raise ValueError("block_size must be in range(0, 256).")
if block_size % 8 != 0:
- raise ValueError("block_size must be a multiple of 8")
+ raise ValueError("block_size must be a multiple of 8.")
self.block_size = block_size
@@ -102,10 +102,10 @@ class _PKCS7PaddingContext(object):
def update(self, data):
if self._buffer is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
- if isinstance(data, six.text_type):
- raise TypeError("Unicode-objects must be encoded before padding")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
self._buffer += data
@@ -118,7 +118,7 @@ class _PKCS7PaddingContext(object):
def finalize(self):
if self._buffer is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
pad_size = self.block_size // 8 - len(self._buffer)
result = self._buffer + six.int2byte(pad_size) * pad_size
@@ -135,10 +135,10 @@ class _PKCS7UnpaddingContext(object):
def update(self, data):
if self._buffer is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
- if isinstance(data, six.text_type):
- raise TypeError("Unicode-objects must be encoded before unpadding")
+ if not isinstance(data, bytes):
+ raise TypeError("data must be bytes.")
self._buffer += data
@@ -154,17 +154,17 @@ class _PKCS7UnpaddingContext(object):
def finalize(self):
if self._buffer is None:
- raise AlreadyFinalized("Context was already finalized")
+ raise AlreadyFinalized("Context was already finalized.")
if len(self._buffer) != self.block_size // 8:
- raise ValueError("Invalid padding bytes")
+ raise ValueError("Invalid padding bytes.")
valid = _lib.Cryptography_check_pkcs7_padding(
self._buffer, self.block_size // 8
)
if not valid:
- raise ValueError("Invalid padding bytes")
+ raise ValueError("Invalid padding bytes.")
pad_size = six.indexbytes(self._buffer, -1)
res = self._buffer[:-pad_size]
diff --git a/cryptography/hazmat/primitives/twofactor/hotp.py b/cryptography/hazmat/primitives/twofactor/hotp.py
index 41c467c8..d0b476a7 100644
--- a/cryptography/hazmat/primitives/twofactor/hotp.py
+++ b/cryptography/hazmat/primitives/twofactor/hotp.py
@@ -29,7 +29,7 @@ class HOTP(object):
def __init__(self, key, length, algorithm, backend):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement HMACBackend",
+ "Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -37,13 +37,13 @@ class HOTP(object):
raise ValueError("Key length has to be at least 128 bits.")
if not isinstance(length, six.integer_types):
- raise TypeError("Length parameter must be an integer type")
+ raise TypeError("Length parameter must be an integer type.")
if length < 6 or length > 8:
raise ValueError("Length of HOTP has to be between 6 to 8.")
if not isinstance(algorithm, (SHA1, SHA256, SHA512)):
- raise TypeError("Algorithm must be SHA1, SHA256 or SHA512")
+ raise TypeError("Algorithm must be SHA1, SHA256 or SHA512.")
self._key = key
self._length = length
@@ -57,15 +57,13 @@ class HOTP(object):
def verify(self, hotp, counter):
if not constant_time.bytes_eq(self.generate(counter), hotp):
- raise InvalidToken("Supplied HOTP value does not match")
+ raise InvalidToken("Supplied HOTP value does not match.")
def _dynamic_truncate(self, counter):
ctx = hmac.HMAC(self._key, self._algorithm, self._backend)
ctx.update(struct.pack(">Q", counter))
hmac_value = ctx.finalize()
- offset_bits = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111
-
- offset = int(offset_bits)
+ offset = six.indexbytes(hmac_value, len(hmac_value) - 1) & 0b1111
p = hmac_value[offset:offset + 4]
return struct.unpack(">I", p)[0] & 0x7fffffff
diff --git a/cryptography/hazmat/primitives/twofactor/totp.py b/cryptography/hazmat/primitives/twofactor/totp.py
index e55ba00d..854c5163 100644
--- a/cryptography/hazmat/primitives/twofactor/totp.py
+++ b/cryptography/hazmat/primitives/twofactor/totp.py
@@ -25,7 +25,7 @@ class TOTP(object):
def __init__(self, key, length, algorithm, time_step, backend):
if not isinstance(backend, HMACBackend):
raise UnsupportedAlgorithm(
- "Backend object does not implement HMACBackend",
+ "Backend object does not implement HMACBackend.",
_Reasons.BACKEND_MISSING_INTERFACE
)
@@ -38,4 +38,4 @@ class TOTP(object):
def verify(self, totp, time):
if not constant_time.bytes_eq(self.generate(time), totp):
- raise InvalidToken("Supplied TOTP value does not match")
+ raise InvalidToken("Supplied TOTP value does not match.")
diff --git a/docs/development/custom-vectors/cast5.rst b/docs/development/custom-vectors/cast5.rst
index f045ec1b..97de9016 100644
--- a/docs/development/custom-vectors/cast5.rst
+++ b/docs/development/custom-vectors/cast5.rst
@@ -15,7 +15,8 @@ the following Python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/cast5/generate_cast5.py
-Download link: :download:`generate_cast5.py </development/custom-vectors/cast5/generate_cast5.py>`
+Download link: :download:`generate_cast5.py
+</development/custom-vectors/cast5/generate_cast5.py>`
Verification
@@ -26,4 +27,5 @@ The following Go code was used to verify the vectors.
.. literalinclude:: /development/custom-vectors/cast5/verify_cast5.go
:language: go
-Download link: :download:`verify_cast5.go </development/custom-vectors/cast5/verify_cast5.go>`
+Download link: :download:`verify_cast5.go
+</development/custom-vectors/cast5/verify_cast5.go>`
diff --git a/docs/development/custom-vectors/idea.rst b/docs/development/custom-vectors/idea.rst
index c2268634..336cdf01 100644
--- a/docs/development/custom-vectors/idea.rst
+++ b/docs/development/custom-vectors/idea.rst
@@ -14,7 +14,8 @@ the following python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/idea/generate_idea.py
-Download link: :download:`generate_idea.py </development/custom-vectors/idea/generate_idea.py>`
+Download link: :download:`generate_idea.py
+</development/custom-vectors/idea/generate_idea.py>`
Verification
@@ -25,6 +26,7 @@ project's Python bindings.
.. literalinclude:: /development/custom-vectors/idea/verify_idea.py
-Download link: :download:`verify_idea.py </development/custom-vectors/idea/verify_idea.py>`
+Download link: :download:`verify_idea.py
+</development/custom-vectors/idea/verify_idea.py>`
.. _`Botan`: http://botan.randombit.net
diff --git a/docs/development/custom-vectors/seed.rst b/docs/development/custom-vectors/seed.rst
index 5ea4295b..290fb77a 100644
--- a/docs/development/custom-vectors/seed.rst
+++ b/docs/development/custom-vectors/seed.rst
@@ -14,7 +14,8 @@ the following python script was run to generate the vector files.
.. literalinclude:: /development/custom-vectors/seed/generate_seed.py
-Download link: :download:`generate_seed.py </development/custom-vectors/seed/generate_seed.py>`
+Download link: :download:`generate_seed.py
+</development/custom-vectors/seed/generate_seed.py>`
Verification
@@ -25,6 +26,7 @@ project's Python bindings.
.. literalinclude:: /development/custom-vectors/seed/verify_seed.py
-Download link: :download:`verify_seed.py </development/custom-vectors/seed/verify_seed.py>`
+Download link: :download:`verify_seed.py
+</development/custom-vectors/seed/verify_seed.py>`
.. _`Botan`: http://botan.randombit.net
diff --git a/docs/doing-a-release.rst b/docs/doing-a-release.rst
index ad3b4791..dd62c794 100644
--- a/docs/doing-a-release.rst
+++ b/docs/doing-a-release.rst
@@ -52,3 +52,6 @@ Post-release tasks
* Check for any outstanding code undergoing a deprecation cycle by looking in
``cryptography.utils`` for ``DeprecatedIn**`` definitions. If any exist open
a ticket to increment them for the next release.
+* Send an email to the `mailing list`_ announcing the release.
+
+.. _`mailing list`: https://mail.python.org/mailman/listinfo/cryptography-dev
diff --git a/docs/faq.rst b/docs/faq.rst
index 0b7bdce4..4e8efc1d 100644
--- a/docs/faq.rst
+++ b/docs/faq.rst
@@ -14,5 +14,34 @@ to NaCl.
If you prefer NaCl's design, we highly recommend `PyNaCl`_.
+When I try to use ``cryptography`` on Windows I get a ``cffi.ffiplatform.VerificationError``
+--------------------------------------------------------------------------------------------
+
+This error looks something like:
+
+.. code-block:: console
+
+ cffi.ffiplatform.VerificationError: importing '<some_path>.pyd': DLL load failed:
+
+It typically occurs on Windows when you have not installed OpenSSL. Download
+a `pre-compiled binary`_ to resolve the issue. To select the right architecture
+(32-bit or 64-bit) open a command prompt and start your Python interpreter.
+
+If it is 32-bit it will say ``32 bit`` as well as ``Intel`` in the output:
+
+.. code-block:: console
+
+ Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC v.1500 32 bit (Intel)] on win32
+
+If it is 64-bit you will see ``64 bit`` as well as ``AMD64``:
+
+.. code-block:: console
+
+ Python 2.7.6 (default, Nov 10 2013, 19:24:24) [MSC v.1500 64 bit (AMD64)] on win32
+
+Note that for both 32-bit and 64-bit it will say ``win32``, but other data
+in the string may vary based on your version of Python.
+
.. _`NaCl`: http://nacl.cr.yp.to/
.. _`PyNaCl`: https://pynacl.readthedocs.org
+.. _`pre-compiled binary`: https://www.openssl.org/related/binaries.html
diff --git a/docs/fernet.rst b/docs/fernet.rst
index f55a2d60..1c4918ad 100644
--- a/docs/fernet.rst
+++ b/docs/fernet.rst
@@ -34,12 +34,13 @@ symmetric (also known as "secret key") authenticated cryptography.
they'll also be able forge arbitrary messages that will be
authenticated and decrypted.
- .. method:: encrypt(plaintext)
+ .. method:: encrypt(data)
- :param bytes plaintext: The message you would like to encrypt.
+ :param bytes data: The message you would like to encrypt.
:returns bytes: A secure message that cannot be read or altered
without the key. It is URL-safe base64-encoded. This is
referred to as a "Fernet token".
+ :raises TypeError: This exception is raised if ``data`` is not ``bytes``.
.. note::
@@ -66,6 +67,7 @@ symmetric (also known as "secret key") authenticated cryptography.
``ttl``, it is malformed, or
it does not have a valid
signature.
+ :raises TypeError: This exception is raised if ``token`` is not ``bytes``.
.. class:: InvalidToken
diff --git a/docs/hazmat/backends/commoncrypto.rst b/docs/hazmat/backends/commoncrypto.rst
index 77d6612c..ddaf97e5 100644
--- a/docs/hazmat/backends/commoncrypto.rst
+++ b/docs/hazmat/backends/commoncrypto.rst
@@ -3,8 +3,8 @@
CommonCrypto backend
====================
-The `CommonCrypto`_ C library provided by Apple on OS X and iOS. The CommonCrypto
-backend is only supported on OS X versions 10.8 and above.
+The `CommonCrypto`_ C library provided by Apple on OS X and iOS. The
+CommonCrypto backend is only supported on OS X versions 10.8 and above.
.. currentmodule:: cryptography.hazmat.backends.commoncrypto.backend
diff --git a/docs/hazmat/backends/interfaces.rst b/docs/hazmat/backends/interfaces.rst
index f363b541..ff389cb5 100644
--- a/docs/hazmat/backends/interfaces.rst
+++ b/docs/hazmat/backends/interfaces.rst
@@ -6,8 +6,8 @@ Backend interfaces
.. currentmodule:: cryptography.hazmat.backends.interfaces
-Backend implementations may provide a number of interfaces to support operations
-such as :doc:`/hazmat/primitives/symmetric-encryption`,
+Backend implementations may provide a number of interfaces to support
+operations such as :doc:`/hazmat/primitives/symmetric-encryption`,
:doc:`/hazmat/primitives/cryptographic-hashes`, and
:doc:`/hazmat/primitives/mac/hmac`.
@@ -275,6 +275,14 @@ A specific ``backend`` may provide one or more of these interfaces.
:class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
provider.
+ :return bytes: The decrypted data.
+
+ :raises cryptography.exceptions.UnsupportedAlgorithm: If an unsupported
+ MGF, hash function, or padding is chosen.
+
+ :raises ValueError: When decryption fails or key size does not match
+ ciphertext length.
+
.. method:: encrypt_rsa(public_key, plaintext, padding)
:param public_key: An instance of an
@@ -287,6 +295,12 @@ A specific ``backend`` may provide one or more of these interfaces.
:class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
provider.
+ :return bytes: The encrypted data.
+
+ :raises cryptography.exceptions.UnsupportedAlgorithm: If an unsupported
+ MGF, hash function, or padding is chosen.
+
+ :raises ValueError: When plaintext is too long for the key size.
.. class:: TraditionalOpenSSLSerializationBackend
diff --git a/docs/hazmat/backends/openssl.rst b/docs/hazmat/backends/openssl.rst
index f21116b8..6ad0d045 100644
--- a/docs/hazmat/backends/openssl.rst
+++ b/docs/hazmat/backends/openssl.rst
@@ -46,9 +46,9 @@ where two different processes can return similar or identical keys and
compromise the security of the system.
The approach this project has chosen to mitigate this vulnerability is to
-include an engine that replaces the OpenSSL default CSPRNG with one that sources
-its entropy from ``/dev/urandom`` on UNIX-like operating systems and uses
-``CryptGenRandom`` on Windows. This method of pulling from the system pool
+include an engine that replaces the OpenSSL default CSPRNG with one that
+sources its entropy from ``/dev/urandom`` on UNIX-like operating systems and
+uses ``CryptGenRandom`` on Windows. This method of pulling from the system pool
allows us to avoid potential issues with `initializing the RNG`_ as well as
protecting us from the ``fork()`` weakness.
@@ -70,8 +70,8 @@ On Windows the implementation of ``CryptGenRandom`` depends on which version of
the operation system you are using. See the `Microsoft documentation`_ for more
details.
-Linux uses its own PRNG design. ``/dev/urandom`` is a non-blocking source seeded
-from the same pool as ``/dev/random``.
+Linux uses its own PRNG design. ``/dev/urandom`` is a non-blocking source
+seeded from the same pool as ``/dev/random``.
.. _`OpenSSL`: https://www.openssl.org/
diff --git a/docs/hazmat/primitives/asymmetric/dsa.rst b/docs/hazmat/primitives/asymmetric/dsa.rst
index cc46029c..6848d84c 100644
--- a/docs/hazmat/primitives/asymmetric/dsa.rst
+++ b/docs/hazmat/primitives/asymmetric/dsa.rst
@@ -120,7 +120,7 @@ DSA
... hashes.SHA256(),
... default_backend()
... )
- >>> data= b"this is some data I'd like to sign"
+ >>> data = b"this is some data I'd like to sign"
>>> signer.update(data)
>>> signature = signer.finalize()
diff --git a/docs/hazmat/primitives/asymmetric/rsa.rst b/docs/hazmat/primitives/asymmetric/rsa.rst
index 68ad089d..234a5c66 100644
--- a/docs/hazmat/primitives/asymmetric/rsa.rst
+++ b/docs/hazmat/primitives/asymmetric/rsa.rst
@@ -85,7 +85,10 @@ RSA
:param padding: An instance of a
:class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
- provider.
+ provider. Valid values are
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` and
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`
+ (``PSS`` is recommended for all new applications).
:param algorithm: An instance of a
:class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
@@ -154,21 +157,39 @@ RSA
:class:`~cryptography.hazmat.primitives.asymmetric.padding.OAEP`
it may also be raised for invalid label values.
- .. code-block:: python
+ .. doctest::
- from cryptography.hazmat.backends import default_backend
- from cryptography.hazmat.primitives import hashes
- from cryptography.hazmat.primitives.asymmetric import padding
+ >>> from cryptography.hazmat.backends import default_backend
+ >>> from cryptography.hazmat.primitives import hashes
+ >>> from cryptography.hazmat.primitives.asymmetric import padding
- plaintext = private_key.decrypt(
- ciphertext,
- padding.OAEP(
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
- algorithm=hashes.SHA1(),
- label=None
- ),
- default_backend()
- )
+ >>> # Generate a key
+ >>> private_key = rsa.RSAPrivateKey.generate(
+ ... public_exponent=65537,
+ ... key_size=2048,
+ ... backend=default_backend()
+ ... )
+ >>> public_key = private_key.public_key()
+ >>> # encrypt some data
+ >>> ciphertext = public_key.encrypt(
+ ... b"encrypted data",
+ ... padding.OAEP(
+ ... mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ ... algorithm=hashes.SHA1(),
+ ... label=None
+ ... ),
+ ... default_backend()
+ ... )
+ >>> # Now do the actual decryption
+ >>> plaintext = private_key.decrypt(
+ ... ciphertext,
+ ... padding.OAEP(
+ ... mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ ... algorithm=hashes.SHA1(),
+ ... label=None
+ ... ),
+ ... default_backend()
+ ... )
.. class:: RSAPublicKey(public_exponent, modulus)
@@ -216,7 +237,7 @@ RSA
... hashes.SHA256(),
... default_backend()
... )
- >>> data= b"this is some data I'd like to sign"
+ >>> data = b"this is some data I'd like to sign"
>>> signer.update(data)
>>> signature = signer.finalize()
>>> public_key = private_key.public_key()
@@ -236,7 +257,10 @@ RSA
:param padding: An instance of a
:class:`~cryptography.hazmat.primitives.interfaces.AsymmetricPadding`
- provider.
+ provider. Valid values are
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PSS` and
+ :class:`~cryptography.hazmat.primitives.asymmetric.padding.PKCS1v15`
+ (``PSS`` is recommended for all new applications).
:param algorithm: An instance of a
:class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
@@ -306,27 +330,29 @@ RSA
:class:`~cryptography.hazmat.primitives.asymmetric.padding.OAEP`
it may also be raised for invalid label values.
- .. code-block:: python
-
- from cryptography.hazmat.backends import default_backend
- from cryptography.hazmat.primitives import hashes
- from cryptography.hazmat.primitives.asymmetric import padding, rsa
-
- private_key = rsa.RSAPrivateKey.generate(
- public_exponent=65537,
- key_size=2048,
- backend=default_backend()
- )
- public_key = private_key.public_key()
- ciphertext = public_key.encrypt(
- plaintext,
- padding.OAEP(
- mgf=padding.MGF1(algorithm=hashes.SHA1()),
- algorithm=hashes.SHA1(),
- label=None
- ),
- default_backend()
- )
+ .. doctest::
+
+ >>> from cryptography.hazmat.backends import default_backend
+ >>> from cryptography.hazmat.primitives import hashes
+ >>> from cryptography.hazmat.primitives.asymmetric import padding
+
+ >>> # Generate a key
+ >>> private_key = rsa.RSAPrivateKey.generate(
+ ... public_exponent=65537,
+ ... key_size=2048,
+ ... backend=default_backend()
+ ... )
+ >>> public_key = private_key.public_key()
+ >>> # encrypt some data
+ >>> ciphertext = public_key.encrypt(
+ ... b"encrypted data",
+ ... padding.OAEP(
+ ... mgf=padding.MGF1(algorithm=hashes.SHA1()),
+ ... algorithm=hashes.SHA1(),
+ ... label=None
+ ... ),
+ ... default_backend()
+ ... )
Handling partial RSA private keys
diff --git a/docs/hazmat/primitives/constant-time.rst b/docs/hazmat/primitives/constant-time.rst
index c6fcb3a3..1394b6b3 100644
--- a/docs/hazmat/primitives/constant-time.rst
+++ b/docs/hazmat/primitives/constant-time.rst
@@ -36,6 +36,8 @@ about the timing attacks on KeyCzar and Java's ``MessageDigest.isEqual()``.
:param bytes b: The right-hand side.
:returns bool: ``True`` if ``a`` has the same bytes as ``b``, otherwise
``False``.
+ :raises TypeError: This exception is raised if ``a`` or ``b`` is not
+ ``bytes``.
.. _`Coda Hale's blog post`: http://codahale.com/a-lesson-in-timing-attacks/
diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst
index 773d97f6..7e5295c4 100644
--- a/docs/hazmat/primitives/cryptographic-hashes.rst
+++ b/docs/hazmat/primitives/cryptographic-hashes.rst
@@ -54,6 +54,7 @@ Message digests
:param bytes data: The bytes to be hashed.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`.
+ :raises TypeError: This exception is raised if ``data`` is not ``bytes``.
.. method:: copy()
diff --git a/docs/hazmat/primitives/key-derivation-functions.rst b/docs/hazmat/primitives/key-derivation-functions.rst
index 269f949d..f68b12c1 100644
--- a/docs/hazmat/primitives/key-derivation-functions.rst
+++ b/docs/hazmat/primitives/key-derivation-functions.rst
@@ -88,6 +88,8 @@ Different KDFs are suitable for different tasks such as:
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.PBKDF2HMACBackend`
+ :raises TypeError: This exception is raised if ``salt`` is not ``bytes``.
+
.. method:: derive(key_material)
:param bytes key_material: The input key material. For PBKDF2 this
@@ -99,6 +101,9 @@ Different KDFs are suitable for different tasks such as:
called more than
once.
+ :raises TypeError: This exception is raised if ``key_material`` is not
+ ``bytes``.
+
This generates and returns a new key from the supplied password.
.. method:: verify(key_material, expected_key)
@@ -191,10 +196,108 @@ Different KDFs are suitable for different tasks such as:
provided ``backend`` does not implement
:class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
+ :raises TypeError: This exception is raised if ``salt`` or ``info`` is not
+ ``bytes``.
+
+ .. method:: derive(key_material)
+
+ :param bytes key_material: The input key material.
+ :return bytes: The derived key.
+ :raises TypeError: This exception is raised if ``key_material`` is not
+ ``bytes``.
+
+ Derives a new key from the input key material by performing both the
+ extract and expand operations.
+
+ .. method:: verify(key_material, expected_key)
+
+ :param key_material bytes: The input key material. This is the same as
+ ``key_material`` in :meth:`derive`.
+ :param expected_key bytes: The expected result of deriving a new key,
+ this is the same as the return value of
+ :meth:`derive`.
+ :raises cryptography.exceptions.InvalidKey: This is raised when the
+ derived key does not match
+ the expected key.
+ :raises cryptography.exceptions.AlreadyFinalized: This is raised when
+ :meth:`derive` or
+ :meth:`verify` is
+ called more than
+ once.
+
+ This checks whether deriving a new key from the supplied
+ ``key_material`` generates the same key as the ``expected_key``, and
+ raises an exception if they do not match.
+
+
+.. class:: HKDFExpand(algorithm, length, info, backend)
+
+ .. versionadded:: 0.5
+
+ HKDF consists of two stages, extract and expand. This class exposes an
+ expand only version of HKDF that is suitable when the key material is
+ already cryptographically strong.
+
+ .. warning::
+
+ HKDFExpand should only be used if the key material is
+ cryptographically strong. You should use
+ :class:`~cryptography.hazmat.primitives.kdf.hkdf.HKDF` if
+ you are unsure.
+
+ .. doctest::
+
+ >>> import os
+ >>> from cryptography.hazmat.primitives import hashes
+ >>> from cryptography.hazmat.primitives.kdf.hkdf import HKDFExpand
+ >>> from cryptography.hazmat.backends import default_backend
+ >>> backend = default_backend()
+ >>> info = b"hkdf-example"
+ >>> key_material = os.urandom(16)
+ >>> hkdf = HKDFExpand(
+ ... algorithm=hashes.SHA256(),
+ ... length=32,
+ ... info=info,
+ ... backend=backend
+ ... )
+ >>> key = hkdf.derive(key_material)
+ >>> hkdf = HKDFExpand(
+ ... algorithm=hashes.SHA256(),
+ ... length=32,
+ ... info=info,
+ ... backend=backend
+ ... )
+ >>> hkdf.verify(key_material, key)
+
+ :param algorithm: An instance of a
+ :class:`~cryptography.hazmat.primitives.interfaces.HashAlgorithm`
+ provider.
+
+ :param int length: The desired length of the derived key. Maximum is
+ ``255 * (algorithm.digest_size // 8)``.
+
+ :param bytes info: Application specific context information. If ``None``
+ is explicitly passed an empty byte string will be used.
+
+ :param backend: A
+ :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
+ provider.
+
+ :raises cryptography.exceptions.UnsupportedAlgorithm: This is raised if the
+ provided ``backend`` does not implement
+ :class:`~cryptography.hazmat.backends.interfaces.HMACBackend`
+ :raises TypeError: This is raised if the provided ``info`` is a unicode object
+ :raises TypeError: This exception is raised if ``info`` is not ``bytes``.
+
.. method:: derive(key_material)
:param bytes key_material: The input key material.
- :retunr bytes: The derived key.
+ :return bytes: The derived key.
+
+ :raises TypeError: This is raised if the provided ``key_material`` is
+ a unicode object
+ :raises TypeError: This exception is raised if ``key_material`` is not
+ ``bytes``.
Derives a new key from the input key material by performing both the
extract and expand operations.
@@ -214,6 +317,8 @@ Different KDFs are suitable for different tasks such as:
:meth:`verify` is
called more than
once.
+ :raises TypeError: This is raised if the provided ``key_material`` is
+ a unicode object
This checks whether deriving a new key from the supplied
``key_material`` generates the same key as the ``expected_key``, and
diff --git a/docs/hazmat/primitives/mac/cmac.rst b/docs/hazmat/primitives/mac/cmac.rst
index 1fde1398..498b8b1e 100644
--- a/docs/hazmat/primitives/mac/cmac.rst
+++ b/docs/hazmat/primitives/mac/cmac.rst
@@ -10,8 +10,8 @@ Cipher-based message authentication code
import binascii
key = binascii.unhexlify(b"0" * 32)
-`Cipher-based message authentication codes`_ (or CMACs) are a tool for calculating
-message authentication codes using a block cipher coupled with a
+`Cipher-based message authentication codes`_ (or CMACs) are a tool for
+calculating message authentication codes using a block cipher coupled with a
secret key. You can use an CMAC to verify both the integrity and authenticity
of a message.
@@ -68,6 +68,7 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`.
:param bytes data: The bytes to hash and authenticate.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
+ :raises TypeError: This exception is raised if ``data`` is not ``bytes``.
.. method:: copy()
@@ -89,6 +90,8 @@ A subset of CMAC with the AES-128 algorithm is described in :rfc:`4493`.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
:raises cryptography.exceptions.InvalidSignature: If signature does not
match digest
+ :raises TypeError: This exception is raised if ``signature`` is not
+ ``bytes``.
.. method:: finalize()
diff --git a/docs/hazmat/primitives/mac/hmac.rst b/docs/hazmat/primitives/mac/hmac.rst
index e20a4034..d56927b9 100644
--- a/docs/hazmat/primitives/mac/hmac.rst
+++ b/docs/hazmat/primitives/mac/hmac.rst
@@ -69,6 +69,7 @@ of a message.
:param bytes msg: The bytes to hash and authenticate.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
+ :raises TypeError: This exception is raised if ``msg`` is not ``bytes``.
.. method:: copy()
@@ -90,6 +91,8 @@ of a message.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`
:raises cryptography.exceptions.InvalidSignature: If signature does not
match digest
+ :raises TypeError: This exception is raised if ``signature`` is not
+ ``bytes``.
.. method:: finalize()
diff --git a/docs/hazmat/primitives/mac/index.rst b/docs/hazmat/primitives/mac/index.rst
index 4f075417..acfe9bed 100644
--- a/docs/hazmat/primitives/mac/index.rst
+++ b/docs/hazmat/primitives/mac/index.rst
@@ -6,7 +6,8 @@ Message Authentication Codes
While cryptography supports both the CMAC and HMAC algorithms, we strongly
recommend that HMAC should be used unless you have a good reason otherwise.
-For more information on why HMAC is preferred, see `Use cases for CMAC vs. HMAC?`_
+For more information on why HMAC is preferred, see `Use cases for CMAC vs.
+HMAC?`_
.. _`Use cases for CMAC vs. HMAC?`: http://crypto.stackexchange.com/questions/15721/use-cases-for-cmac-vs-hmac
diff --git a/docs/hazmat/primitives/padding.rst b/docs/hazmat/primitives/padding.rst
index 4092ac00..0322f9d2 100644
--- a/docs/hazmat/primitives/padding.rst
+++ b/docs/hazmat/primitives/padding.rst
@@ -70,6 +70,7 @@ multiple of the block size.
:return bytes: Returns the data that was padded or unpadded.
:raises TypeError: Raised if data is not bytes.
:raises cryptography.exceptions.AlreadyFinalized: See :meth:`finalize`.
+ :raises TypeError: This exception is raised if ``data`` is not ``bytes``.
.. method:: finalize()
diff --git a/docs/hazmat/primitives/symmetric-encryption.rst b/docs/hazmat/primitives/symmetric-encryption.rst
index 78bf6637..bca78354 100644
--- a/docs/hazmat/primitives/symmetric-encryption.rst
+++ b/docs/hazmat/primitives/symmetric-encryption.rst
@@ -20,9 +20,9 @@ provides secrecy but not authenticity. That means an attacker can't see the
message but an attacker can create bogus messages and force the application to
decrypt them.
-For this reason it is *strongly* recommended to combine encryption with a
-message authentication code, such as :doc:`HMAC </hazmat/primitives/mac/hmac>`, in
-an "encrypt-then-MAC" formulation as `described by Colin Percival`_.
+For this reason it is **strongly** recommended to combine encryption with a
+message authentication code, such as :doc:`HMAC </hazmat/primitives/mac/hmac>`,
+in an "encrypt-then-MAC" formulation as `described by Colin Percival`_.
.. class:: Cipher(algorithm, mode, backend)
@@ -275,6 +275,19 @@ Modes
Must be the same number of bytes as the ``block_size`` of the cipher.
Do not reuse an ``initialization_vector`` with a given ``key``.
+.. class:: CFB8(initialization_vector)
+
+ CFB (Cipher Feedback) is a mode of operation for block ciphers. It
+ transforms a block cipher into a stream cipher. The CFB8 variant uses an
+ 8-bit shift register.
+
+ **This mode does not require padding.**
+
+ :param bytes initialization_vector: Must be random bytes. They do not need
+ to be kept secret and they can be included in a transmitted message.
+ Must be the same number of bytes as the ``block_size`` of the cipher.
+ Do not reuse an ``initialization_vector`` with a given ``key``.
+
.. class:: GCM(initialization_vector, tag=None)
.. danger::
diff --git a/docs/installation.rst b/docs/installation.rst
index 865e4cb6..8fbbcb30 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -24,6 +24,7 @@ We test compiling with ``clang`` as well as ``gcc`` and use the following
OpenSSL releases:
* ``OpenSSL 0.9.8e-fips-rhel5`` (``RHEL/CentOS 5``)
+* ``OpenSSL 0.9.8k``
* ``OpenSSL 0.9.8y``
* ``OpenSSL 1.0.0-fips`` (``RHEL/CentOS 6.4``)
* ``OpenSSL 1.0.1``
@@ -107,7 +108,8 @@ Using your own OpenSSL on OS X
------------------------------
To link cryptography against a custom version of OpenSSL you'll need to set
-``ARCHFLAGS``, ``LDFLAGS``, and ``CFLAGS``. OpenSSL can be installed via `Homebrew`_ or `MacPorts`_:
+``ARCHFLAGS``, ``LDFLAGS``, and ``CFLAGS``. OpenSSL can be installed via
+`Homebrew`_ or `MacPorts`_:
`Homebrew`_
@@ -127,13 +129,21 @@ Building cryptography with conda
--------------------------------
Because of a `bug in conda`_, attempting to install cryptography out of the box
-will result in an error. This can be resolved by setting the
-``DYLD_LIBRARY_PATH`` environment variable:
+will result in an error. This can be resolved by setting the library path
+environment variable for your platform.
+
+On OS X:
.. code-block:: console
$ env DYLD_LIBRARY_PATH="$HOME/anaconda/lib" pip install cryptography
+and on Linux:
+
+.. code-block:: console
+
+ $ env LD_LIBRARY_PATH="$HOME/anaconda/lib" pip install cryptography
+
You will need to set this variable every time you start Python. For more
information, consult `Greg Wilson's blog post`_ on the subject.
diff --git a/tasks.py b/tasks.py
index c205ac88..9ffdc8a7 100644
--- a/tasks.py
+++ b/tasks.py
@@ -62,7 +62,7 @@ def download_artifacts():
response.raise_for_status()
for artifact in response.json()["artifacts"]:
response = requests.get(
- "{0}artifacts/{1}".format(run["url"], artifact["relativePath"])
+ "{0}artifact/{1}".format(run["url"], artifact["relativePath"])
)
out_path = os.path.join(
os.path.dirname(__file__),
diff --git a/tests/hazmat/backends/test_multibackend.py b/tests/hazmat/backends/test_multibackend.py
index fd2a30cd..088465a1 100644
--- a/tests/hazmat/backends/test_multibackend.py
+++ b/tests/hazmat/backends/test_multibackend.py
@@ -98,6 +98,15 @@ class DummyRSABackend(object):
algorithm):
pass
+ def mgf1_hash_supported(self, algorithm):
+ pass
+
+ def decrypt_rsa(self, private_key, ciphertext, padding):
+ pass
+
+ def encrypt_rsa(self, public_key, plaintext, padding):
+ pass
+
@utils.register_interface(DSABackend)
class DummyDSABackend(object):
@@ -211,6 +220,12 @@ class TestMultiBackend(object):
backend.create_rsa_verification_ctx("public_key", "sig",
padding.PKCS1v15(), hashes.MD5())
+ backend.mgf1_hash_supported(hashes.MD5())
+
+ backend.encrypt_rsa("public_key", "encryptme", padding.PKCS1v15())
+
+ backend.decrypt_rsa("private_key", "encrypted", padding.PKCS1v15())
+
backend = MultiBackend([])
with raises_unsupported_algorithm(
_Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
@@ -229,6 +244,21 @@ class TestMultiBackend(object):
backend.create_rsa_verification_ctx(
"public_key", "sig", padding.PKCS1v15(), hashes.MD5())
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ ):
+ backend.mgf1_hash_supported(hashes.MD5())
+
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ ):
+ backend.encrypt_rsa("public_key", "encryptme", padding.PKCS1v15())
+
+ with raises_unsupported_algorithm(
+ _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM
+ ):
+ backend.decrypt_rsa("private_key", "encrypted", padding.PKCS1v15())
+
def test_dsa(self):
backend = MultiBackend([
DummyDSABackend()
diff --git a/tests/hazmat/backends/test_openssl.py b/tests/hazmat/backends/test_openssl.py
index 37347bc8..19274bf8 100644
--- a/tests/hazmat/backends/test_openssl.py
+++ b/tests/hazmat/backends/test_openssl.py
@@ -24,7 +24,7 @@ from cryptography.hazmat.primitives import hashes, interfaces
from cryptography.hazmat.primitives.asymmetric import dsa, padding, rsa
from cryptography.hazmat.primitives.ciphers import Cipher
from cryptography.hazmat.primitives.ciphers.algorithms import AES
-from cryptography.hazmat.primitives.ciphers.modes import CBC
+from cryptography.hazmat.primitives.ciphers.modes import CBC, CTR
from cryptography.hazmat.primitives.interfaces import BlockCipherAlgorithm
from ...utils import raises_unsupported_algorithm
@@ -66,6 +66,11 @@ class TestOpenSSL(object):
def test_supports_cipher(self):
assert backend.cipher_supported(None, None) is False
+ def test_aes_ctr_always_available(self):
+ # AES CTR should always be available in both 0.9.8 and 1.0.0+
+ assert backend.cipher_supported(AES(b"\x00" * 16),
+ CTR(b"\x00" * 16)) is True
+
def test_register_duplicate_cipher_adapter(self):
with pytest.raises(ValueError):
backend.register_cipher_adapter(AES, CBC, None)
@@ -272,8 +277,8 @@ class TestOpenSSLRSA(object):
padding.PSS(
mgf=padding.MGF1(
algorithm=hashes.SHA256(),
- salt_length=padding.MGF1.MAX_LENGTH
- )
+ ),
+ salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA1(),
backend
@@ -285,8 +290,8 @@ class TestOpenSSLRSA(object):
padding.PSS(
mgf=padding.MGF1(
algorithm=hashes.SHA256(),
- salt_length=padding.MGF1.MAX_LENGTH
- )
+ ),
+ salt_length=padding.PSS.MAX_LENGTH
),
hashes.SHA1(),
backend
diff --git a/tests/hazmat/primitives/test_3des.py b/tests/hazmat/primitives/test_3des.py
index a4d696c9..b9354f0e 100644
--- a/tests/hazmat/primitives/test_3des.py
+++ b/tests/hazmat/primitives/test_3des.py
@@ -137,3 +137,40 @@ class TestTripleDESModeCFB(object):
),
lambda iv, **kwargs: modes.CFB(binascii.unhexlify(iv)),
)
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
+ algorithms.TripleDES("\x00" * 8), modes.CFB8("\x00" * 8)
+ ),
+ skip_message="Does not support TripleDES CFB8",
+)
+@pytest.mark.cipher
+class TestTripleDESModeCFB8(object):
+ test_KAT = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "3DES", "CFB"),
+ [
+ "TCFB8invperm.rsp",
+ "TCFB8permop.rsp",
+ "TCFB8subtab.rsp",
+ "TCFB8varkey.rsp",
+ "TCFB8vartext.rsp",
+ ],
+ lambda keys, **kwargs: algorithms.TripleDES(binascii.unhexlify(keys)),
+ lambda iv, **kwargs: modes.CFB8(binascii.unhexlify(iv)),
+ )
+
+ test_MMT = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "3DES", "CFB"),
+ [
+ "TCFB8MMT1.rsp",
+ "TCFB8MMT2.rsp",
+ "TCFB8MMT3.rsp",
+ ],
+ lambda key1, key2, key3, **kwargs: algorithms.TripleDES(
+ binascii.unhexlify(key1 + key2 + key3)
+ ),
+ lambda iv, **kwargs: modes.CFB8(binascii.unhexlify(iv)),
+ )
diff --git a/tests/hazmat/primitives/test_aes.py b/tests/hazmat/primitives/test_aes.py
index 03be268d..173075d6 100644
--- a/tests/hazmat/primitives/test_aes.py
+++ b/tests/hazmat/primitives/test_aes.py
@@ -158,6 +158,39 @@ class TestAESModeCFB(object):
@pytest.mark.supported(
only_if=lambda backend: backend.cipher_supported(
+ algorithms.AES("\x00" * 16), modes.CFB8("\x00" * 16)
+ ),
+ skip_message="Does not support AES CFB8",
+)
+@pytest.mark.cipher
+class TestAESModeCFB8(object):
+ test_CFB8 = generate_encrypt_test(
+ load_nist_vectors,
+ os.path.join("ciphers", "AES", "CFB"),
+ [
+ "CFB8GFSbox128.rsp",
+ "CFB8GFSbox192.rsp",
+ "CFB8GFSbox256.rsp",
+ "CFB8KeySbox128.rsp",
+ "CFB8KeySbox192.rsp",
+ "CFB8KeySbox256.rsp",
+ "CFB8VarKey128.rsp",
+ "CFB8VarKey192.rsp",
+ "CFB8VarKey256.rsp",
+ "CFB8VarTxt128.rsp",
+ "CFB8VarTxt192.rsp",
+ "CFB8VarTxt256.rsp",
+ "CFB8MMT128.rsp",
+ "CFB8MMT192.rsp",
+ "CFB8MMT256.rsp",
+ ],
+ lambda key, **kwargs: algorithms.AES(binascii.unhexlify(key)),
+ lambda iv, **kwargs: modes.CFB8(binascii.unhexlify(iv)),
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.cipher_supported(
algorithms.AES("\x00" * 16), modes.CTR("\x00" * 16)
),
skip_message="Does not support AES CTR",
diff --git a/tests/hazmat/primitives/test_block.py b/tests/hazmat/primitives/test_block.py
index acfd947c..022e3af7 100644
--- a/tests/hazmat/primitives/test_block.py
+++ b/tests/hazmat/primitives/test_block.py
@@ -184,6 +184,14 @@ class TestModeValidation(object):
backend,
)
+ def test_cfb8(self, backend):
+ with pytest.raises(ValueError):
+ Cipher(
+ algorithms.AES(b"\x00" * 16),
+ modes.CFB8(b"abc"),
+ backend,
+ )
+
def test_ctr(self, backend):
with pytest.raises(ValueError):
Cipher(
diff --git a/tests/hazmat/primitives/test_hkdf.py b/tests/hazmat/primitives/test_hkdf.py
index 2e3c0c3d..598f09f0 100644
--- a/tests/hazmat/primitives/test_hkdf.py
+++ b/tests/hazmat/primitives/test_hkdf.py
@@ -13,6 +13,8 @@
from __future__ import absolute_import, division, print_function
+import binascii
+
import pytest
import six
@@ -21,7 +23,7 @@ from cryptography.exceptions import (
AlreadyFinalized, InvalidKey, _Reasons
)
from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.kdf.hkdf import HKDF
+from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand
from ...utils import raises_unsupported_algorithm
@@ -151,8 +153,67 @@ class TestHKDF(object):
hkdf.verify(b"foo", six.u("bar"))
+@pytest.mark.hmac
+class TestHKDFExpand(object):
+ def test_derive(self, backend):
+ prk = binascii.unhexlify(
+ b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
+ )
+
+ okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c"
+ b"5bf34007208d5b887185865")
+
+ info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
+ hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
+
+ assert binascii.hexlify(hkdf.derive(prk)) == okm
+
+ def test_verify(self, backend):
+ prk = binascii.unhexlify(
+ b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
+ )
+
+ okm = (b"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c"
+ b"5bf34007208d5b887185865")
+
+ info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
+ hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
+
+ assert hkdf.verify(prk, binascii.unhexlify(okm)) is None
+
+ def test_invalid_verify(self, backend):
+ prk = binascii.unhexlify(
+ b"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5"
+ )
+
+ info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
+ hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
+
+ with pytest.raises(InvalidKey):
+ hkdf.verify(prk, b"wrong key")
+
+ def test_already_finalized(self, backend):
+ info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
+ hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
+
+ hkdf.derive(b"first")
+
+ with pytest.raises(AlreadyFinalized):
+ hkdf.derive(b"second")
+
+ def test_unicode_error(self, backend):
+ info = binascii.unhexlify(b"f0f1f2f3f4f5f6f7f8f9")
+ hkdf = HKDFExpand(hashes.SHA256(), 42, info, backend)
+
+ with pytest.raises(TypeError):
+ hkdf.derive(six.u("first"))
+
+
def test_invalid_backend():
pretend_backend = object()
with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
HKDF(hashes.SHA256(), 16, None, None, pretend_backend)
+
+ with raises_unsupported_algorithm(_Reasons.BACKEND_MISSING_INTERFACE):
+ HKDFExpand(hashes.SHA256(), 16, None, pretend_backend)
diff --git a/tests/hazmat/primitives/test_rsa.py b/tests/hazmat/primitives/test_rsa.py
index 63d62657..be5e8bfc 100644
--- a/tests/hazmat/primitives/test_rsa.py
+++ b/tests/hazmat/primitives/test_rsa.py
@@ -458,8 +458,10 @@ class TestRSASignature(object):
backend=backend
)
signer = private_key.signer(
- padding.PSS(
- mgf=padding.MGF1(
+ pytest.deprecated_call(
+ padding.PSS,
+ mgf=pytest.deprecated_call(
+ padding.MGF1,
algorithm=hashes.SHA1(),
salt_length=padding.MGF1.MAX_LENGTH
)
@@ -472,8 +474,10 @@ class TestRSASignature(object):
assert len(signature) == math.ceil(private_key.key_size / 8.0)
verifier = private_key.public_key().verifier(
signature,
- padding.PSS(
- mgf=padding.MGF1(
+ pytest.deprecated_call(
+ padding.PSS,
+ mgf=pytest.deprecated_call(
+ padding.MGF1,
algorithm=hashes.SHA1(),
salt_length=padding.MGF1.MAX_LENGTH
)
@@ -944,8 +948,8 @@ class TestRSAVerification(object):
padding.PSS(
mgf=padding.MGF1(
algorithm=hashes.SHA1(),
- salt_length=1000000
- )
+ ),
+ salt_length=1000000
),
hashes.SHA1(),
backend
@@ -972,8 +976,8 @@ class TestRSAPSSMGF1Verification(object):
lambda params, hash_alg: padding.PSS(
mgf=padding.MGF1(
algorithm=hash_alg,
- salt_length=params["salt_length"]
- )
+ ),
+ salt_length=params["salt_length"]
)
))
@@ -992,8 +996,8 @@ class TestRSAPSSMGF1Verification(object):
lambda params, hash_alg: padding.PSS(
mgf=padding.MGF1(
algorithm=hash_alg,
- salt_length=params["salt_length"]
- )
+ ),
+ salt_length=params["salt_length"]
)
))
@@ -1012,8 +1016,8 @@ class TestRSAPSSMGF1Verification(object):
lambda params, hash_alg: padding.PSS(
mgf=padding.MGF1(
algorithm=hash_alg,
- salt_length=params["salt_length"]
- )
+ ),
+ salt_length=params["salt_length"]
)
))
@@ -1032,8 +1036,8 @@ class TestRSAPSSMGF1Verification(object):
lambda params, hash_alg: padding.PSS(
mgf=padding.MGF1(
algorithm=hash_alg,
- salt_length=params["salt_length"]
- )
+ ),
+ salt_length=params["salt_length"]
)
))
@@ -1052,8 +1056,8 @@ class TestRSAPSSMGF1Verification(object):
lambda params, hash_alg: padding.PSS(
mgf=padding.MGF1(
algorithm=hash_alg,
- salt_length=params["salt_length"]
- )
+ ),
+ salt_length=params["salt_length"]
)
))
diff --git a/tests/hazmat/primitives/utils.py b/tests/hazmat/primitives/utils.py
index 6c3f4c95..a496459b 100644
--- a/tests/hazmat/primitives/utils.py
+++ b/tests/hazmat/primitives/utils.py
@@ -26,7 +26,7 @@ from cryptography.exceptions import (
from cryptography.hazmat.primitives import hashes, hmac
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives.ciphers import Cipher
-from cryptography.hazmat.primitives.kdf.hkdf import HKDF
+from cryptography.hazmat.primitives.kdf.hkdf import HKDF, HKDFExpand
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from ...utils import load_vectors_from_file
@@ -347,15 +347,14 @@ def hkdf_extract_test(backend, algorithm, params):
def hkdf_expand_test(backend, algorithm, params):
- hkdf = HKDF(
+ hkdf = HKDFExpand(
algorithm,
int(params["l"]),
- salt=binascii.unhexlify(params["salt"]) or None,
info=binascii.unhexlify(params["info"]) or None,
backend=backend
)
- okm = hkdf._expand(binascii.unhexlify(params["prk"]))
+ okm = hkdf.derive(binascii.unhexlify(params["prk"]))
assert okm == binascii.unhexlify(params["okm"])
diff --git a/tox.ini b/tox.ini
index e7d168d6..745fb37a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -16,6 +16,7 @@ commands =
[testenv:docs]
deps =
+ doc8
pyenchant
sphinx
sphinx_rtd_theme
@@ -26,6 +27,7 @@ commands =
sphinx-build -W -b latex -d {envtmpdir}/doctrees docs docs/_build/latex
sphinx-build -W -b doctest -d {envtmpdir}/doctrees docs docs/_build/html
sphinx-build -W -b spelling docs docs/_build/html
+ doc8 --allow-long-titles README.rst docs/
[testenv:docs-linkcheck]
deps =
@@ -45,7 +47,8 @@ deps =
flake8
flake8-import-order
pep8-naming
-commands = flake8 .
+commands =
+ flake8 .
[testenv:py3pep8]
basepython = python3.3
@@ -53,7 +56,8 @@ deps =
flake8
flake8-import-order
pep8-naming
-commands = flake8 .
+commands =
+ flake8 .
[flake8]
exclude = .tox,*.egg