aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.rst4
-rw-r--r--docs/hazmat/primitives/cryptographic-hashes.rst31
-rw-r--r--src/cryptography/hazmat/backends/openssl/backend.py13
-rw-r--r--src/cryptography/hazmat/backends/openssl/hashes.py6
-rw-r--r--src/cryptography/hazmat/primitives/hashes.py42
-rw-r--r--tests/hazmat/primitives/test_hash_vectors.py34
-rw-r--r--tests/hazmat/primitives/test_hashes.py48
7 files changed, 174 insertions, 4 deletions
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index 667720c2..18542035 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -6,6 +6,10 @@ Changelog
.. note:: This version is not yet released and is under active development.
+* Added support for :class:`~cryptography.hazmat.primitives.hashes.BLAKE2b` and
+ :class:`~cryptography.hazmat.primitives.hashes.BLAKE2s` when using OpenSSL
+ 1.1.0.
+
1.5 - 2016-08-26
~~~~~~~~~~~~~~~~
diff --git a/docs/hazmat/primitives/cryptographic-hashes.rst b/docs/hazmat/primitives/cryptographic-hashes.rst
index d0414efa..b0e9c16a 100644
--- a/docs/hazmat/primitives/cryptographic-hashes.rst
+++ b/docs/hazmat/primitives/cryptographic-hashes.rst
@@ -117,6 +117,36 @@ SHA-2 family
SHA-512 is a cryptographic hash function from the SHA-2 family and is
standardized by NIST. It produces a 512-bit message digest.
+BLAKE2
+~~~~~~
+
+`BLAKE2`_ is a cryptographic hash function specified in :rfc:`7693`.
+
+.. note::
+
+ While the RFC specifies keying, personalization, and salting features,
+ these are not supported at this time due to limitations in OpenSSL 1.1.0.
+
+.. class:: BLAKE2b(digest_size)
+
+ BLAKE2b is optimized for 64-bit platforms and produces an 1 to 64-byte
+ message digest.
+
+ :param int digest_size: The desired size of the hash output in bytes. Only
+ ``64`` is supported at this time.
+
+ :raises ValueError: If the ``digest_size`` is invalid.
+
+.. class:: BLAKE2s(digest_size)
+
+ BLAKE2s is optimized for 8 to 32-bit platforms and produces a
+ 1 to 32-byte message digest.
+
+ :param int digest_size: The desired size of the hash output in bytes. Only
+ ``32`` is supported at this time.
+
+ :raises ValueError: If the ``digest_size`` is invalid.
+
RIPEMD160
~~~~~~~~~
@@ -193,3 +223,4 @@ Interfaces
.. _`Lifetimes of cryptographic hash functions`: http://valerieaurora.org/hash.html
+.. _`BLAKE2`: https://blake2.net
diff --git a/src/cryptography/hazmat/backends/openssl/backend.py b/src/cryptography/hazmat/backends/openssl/backend.py
index a1de1a89..7d16e05e 100644
--- a/src/cryptography/hazmat/backends/openssl/backend.py
+++ b/src/cryptography/hazmat/backends/openssl/backend.py
@@ -185,8 +185,19 @@ class Backend(object):
def create_hmac_ctx(self, key, algorithm):
return _HMACContext(self, key, algorithm)
+ def _build_openssl_digest_name(self, algorithm):
+ if algorithm.name == "blake2b" or algorithm.name == "blake2s":
+ alg = "{0}{1}".format(
+ algorithm.name, algorithm.digest_size * 8
+ ).encode("ascii")
+ else:
+ alg = algorithm.name.encode("ascii")
+
+ return alg
+
def hash_supported(self, algorithm):
- digest = self._lib.EVP_get_digestbyname(algorithm.name.encode("ascii"))
+ name = self._build_openssl_digest_name(algorithm)
+ digest = self._lib.EVP_get_digestbyname(name)
return digest != self._ffi.NULL
def hmac_supported(self, algorithm):
diff --git a/src/cryptography/hazmat/backends/openssl/hashes.py b/src/cryptography/hazmat/backends/openssl/hashes.py
index 2c8fce1a..92ea53bb 100644
--- a/src/cryptography/hazmat/backends/openssl/hashes.py
+++ b/src/cryptography/hazmat/backends/openssl/hashes.py
@@ -22,12 +22,12 @@ class _HashContext(object):
ctx = self._backend._ffi.gc(
ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free
)
- evp_md = self._backend._lib.EVP_get_digestbyname(
- algorithm.name.encode("ascii"))
+ name = self._backend._build_openssl_digest_name(algorithm)
+ evp_md = self._backend._lib.EVP_get_digestbyname(name)
if evp_md == self._backend._ffi.NULL:
raise UnsupportedAlgorithm(
"{0} is not a supported hash on this backend.".format(
- algorithm.name),
+ name),
_Reasons.UNSUPPORTED_HASH
)
res = self._backend._lib.EVP_DigestInit_ex(ctx, evp_md,
diff --git a/src/cryptography/hazmat/primitives/hashes.py b/src/cryptography/hazmat/primitives/hashes.py
index 6bc8500b..0714c118 100644
--- a/src/cryptography/hazmat/primitives/hashes.py
+++ b/src/cryptography/hazmat/primitives/hashes.py
@@ -161,3 +161,45 @@ class MD5(object):
name = "md5"
digest_size = 16
block_size = 64
+
+
+@utils.register_interface(HashAlgorithm)
+class BLAKE2b(object):
+ name = "blake2b"
+ _max_digest_size = 64
+ _min_digest_size = 1
+ block_size = 128
+
+ def __init__(self, digest_size):
+ if (
+ digest_size > self._max_digest_size or
+ digest_size < self._min_digest_size
+ ):
+ raise ValueError("Digest size must be {0}-{1}".format(
+ self._min_digest_size, self._max_digest_size)
+ )
+
+ self._digest_size = digest_size
+
+ digest_size = utils.read_only_property("_digest_size")
+
+
+@utils.register_interface(HashAlgorithm)
+class BLAKE2s(object):
+ name = "blake2s"
+ block_size = 64
+ _max_digest_size = 32
+ _min_digest_size = 1
+
+ def __init__(self, digest_size):
+ if (
+ digest_size > self._max_digest_size or
+ digest_size < self._min_digest_size
+ ):
+ raise ValueError("Digest size must be {0}-{1}".format(
+ self._min_digest_size, self._max_digest_size)
+ )
+
+ self._digest_size = digest_size
+
+ digest_size = utils.read_only_property("_digest_size")
diff --git a/tests/hazmat/primitives/test_hash_vectors.py b/tests/hazmat/primitives/test_hash_vectors.py
index c6e98283..8757df24 100644
--- a/tests/hazmat/primitives/test_hash_vectors.py
+++ b/tests/hazmat/primitives/test_hash_vectors.py
@@ -158,3 +158,37 @@ class TestMD5(object):
],
hashes.MD5(),
)
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.hash_supported(
+ hashes.BLAKE2b(digest_size=64)),
+ skip_message="Does not support BLAKE2b",
+)
+@pytest.mark.requires_backend_interface(interface=HashBackend)
+class TestBLAKE2b(object):
+ test_b2b = generate_hash_test(
+ load_hash_vectors,
+ os.path.join("hashes", "blake2"),
+ [
+ "blake2b.txt",
+ ],
+ hashes.BLAKE2b(digest_size=64),
+ )
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.hash_supported(
+ hashes.BLAKE2s(digest_size=32)),
+ skip_message="Does not support BLAKE2s",
+)
+@pytest.mark.requires_backend_interface(interface=HashBackend)
+class TestBLAKE2s256(object):
+ test_b2s = generate_hash_test(
+ load_hash_vectors,
+ os.path.join("hashes", "blake2"),
+ [
+ "blake2s.txt",
+ ],
+ hashes.BLAKE2s(digest_size=32),
+ )
diff --git a/tests/hazmat/primitives/test_hashes.py b/tests/hazmat/primitives/test_hashes.py
index a109c219..fe96b322 100644
--- a/tests/hazmat/primitives/test_hashes.py
+++ b/tests/hazmat/primitives/test_hashes.py
@@ -159,6 +159,54 @@ class TestMD5(object):
)
+@pytest.mark.supported(
+ only_if=lambda backend: backend.hash_supported(
+ hashes.BLAKE2b(digest_size=64)),
+ skip_message="Does not support BLAKE2b",
+)
+@pytest.mark.requires_backend_interface(interface=HashBackend)
+class TestBLAKE2b(object):
+ test_BLAKE2b = generate_base_hash_test(
+ hashes.BLAKE2b(digest_size=64),
+ digest_size=64,
+ block_size=128,
+ )
+
+ def test_invalid_digest_size(self, backend):
+ with pytest.raises(ValueError):
+ hashes.BLAKE2b(digest_size=65)
+
+ with pytest.raises(ValueError):
+ hashes.BLAKE2b(digest_size=0)
+
+ with pytest.raises(ValueError):
+ hashes.BLAKE2b(digest_size=-1)
+
+
+@pytest.mark.supported(
+ only_if=lambda backend: backend.hash_supported(
+ hashes.BLAKE2s(digest_size=32)),
+ skip_message="Does not support BLAKE2s",
+)
+@pytest.mark.requires_backend_interface(interface=HashBackend)
+class TestBLAKE2s(object):
+ test_BLAKE2s = generate_base_hash_test(
+ hashes.BLAKE2s(digest_size=32),
+ digest_size=32,
+ block_size=64,
+ )
+
+ def test_invalid_digest_size(self, backend):
+ with pytest.raises(ValueError):
+ hashes.BLAKE2s(digest_size=33)
+
+ with pytest.raises(ValueError):
+ hashes.BLAKE2s(digest_size=0)
+
+ with pytest.raises(ValueError):
+ hashes.BLAKE2s(digest_size=-1)
+
+
def test_invalid_backend():
pretend_backend = object()