aboutsummaryrefslogtreecommitdiffstats
path: root/cryptography/hazmat
diff options
context:
space:
mode:
Diffstat (limited to 'cryptography/hazmat')
-rw-r--r--cryptography/hazmat/bindings/openssl/backend.py13
-rw-r--r--cryptography/hazmat/primitives/block/ciphers.py40
-rw-r--r--cryptography/hazmat/primitives/hashes.py59
-rw-r--r--cryptography/hazmat/primitives/hmac.py38
-rw-r--r--cryptography/hazmat/primitives/interfaces.py46
5 files changed, 145 insertions, 51 deletions
diff --git a/cryptography/hazmat/bindings/openssl/backend.py b/cryptography/hazmat/bindings/openssl/backend.py
index 8de37d5b..fc73dd39 100644
--- a/cryptography/hazmat/bindings/openssl/backend.py
+++ b/cryptography/hazmat/bindings/openssl/backend.py
@@ -20,7 +20,7 @@ import cffi
from cryptography.hazmat.primitives import interfaces
from cryptography.hazmat.primitives.block.ciphers import (
- AES, Camellia, TripleDES,
+ AES, Blowfish, Camellia, CAST5, TripleDES,
)
from cryptography.hazmat.primitives.block.modes import CBC, CTR, ECB, OFB, CFB
@@ -221,6 +221,17 @@ class Ciphers(object):
mode_cls,
GetCipherByName("des-ede3-{mode.name}")
)
+ for mode_cls in [CBC, CFB, OFB, ECB]:
+ self.register_cipher_adapter(
+ Blowfish,
+ mode_cls,
+ GetCipherByName("bf-{mode.name}")
+ )
+ self.register_cipher_adapter(
+ CAST5,
+ ECB,
+ GetCipherByName("cast5-ecb")
+ )
def create_encrypt_ctx(self, cipher, mode):
return _CipherContext(self._backend, cipher, mode,
diff --git a/cryptography/hazmat/primitives/block/ciphers.py b/cryptography/hazmat/primitives/block/ciphers.py
index 4143b89d..8046bd26 100644
--- a/cryptography/hazmat/primitives/block/ciphers.py
+++ b/cryptography/hazmat/primitives/block/ciphers.py
@@ -76,3 +76,43 @@ class TripleDES(object):
@property
def key_size(self):
return len(self.key) * 8
+
+
+class Blowfish(object):
+ name = "Blowfish"
+ block_size = 64
+ key_sizes = frozenset(range(32, 449, 8))
+
+ def __init__(self, key):
+ super(Blowfish, self).__init__()
+ self.key = key
+
+ # Verify that the key size matches the expected key size
+ if self.key_size not in self.key_sizes:
+ raise ValueError("Invalid key size ({0}) for {1}".format(
+ self.key_size, self.name
+ ))
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
+
+
+class CAST5(object):
+ name = "CAST5"
+ block_size = 64
+ key_sizes = frozenset([40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128])
+
+ def __init__(self, key):
+ super(CAST5, self).__init__()
+ self.key = key
+
+ # Verify that the key size matches the expected key size
+ if self.key_size not in self.key_sizes:
+ raise ValueError("Invalid key size ({0}) for {1}".format(
+ self.key_size, self.name
+ ))
+
+ @property
+ def key_size(self):
+ return len(self.key) * 8
diff --git a/cryptography/hazmat/primitives/hashes.py b/cryptography/hazmat/primitives/hashes.py
index 3ccb59d1..bdad5e16 100644
--- a/cryptography/hazmat/primitives/hashes.py
+++ b/cryptography/hazmat/primitives/hashes.py
@@ -13,89 +13,94 @@
from __future__ import absolute_import, division, print_function
-import abc
+import six
-import binascii
+from cryptography.hazmat.primitives import interfaces
-import six
+@interfaces.register(interfaces.HashContext)
+class Hash(object):
+ def __init__(self, algorithm, backend=None, ctx=None):
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+ self.algorithm = algorithm
-class BaseHash(six.with_metaclass(abc.ABCMeta)):
- def __init__(self, data=None, backend=None, ctx=None):
if backend is None:
from cryptography.hazmat.bindings import _default_backend
backend = _default_backend
+
self._backend = backend
+
if ctx is None:
- self._ctx = self._backend.hashes.create_ctx(self)
+ self._ctx = self._backend.hashes.create_ctx(self.algorithm)
else:
self._ctx = None
- if data is not None:
- self.update(data)
-
def update(self, data):
if isinstance(data, six.text_type):
raise TypeError("Unicode-objects must be encoded before hashing")
self._backend.hashes.update_ctx(self._ctx, data)
def copy(self):
- return self.__class__(backend=self._backend, ctx=self._copy_ctx())
-
- def digest(self):
- return self._backend.hashes.finalize_ctx(self._copy_ctx(),
- self.digest_size)
-
- def hexdigest(self):
- return str(binascii.hexlify(self.digest()).decode("ascii"))
+ return self.__class__(self.algorithm, backend=self._backend,
+ ctx=self._backend.hashes.copy_ctx(self._ctx))
- def _copy_ctx(self):
- return self._backend.hashes.copy_ctx(self._ctx)
+ def finalize(self):
+ return self._backend.hashes.finalize_ctx(self._ctx,
+ self.algorithm.digest_size)
-class SHA1(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class SHA1(object):
name = "sha1"
digest_size = 20
block_size = 64
-class SHA224(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class SHA224(object):
name = "sha224"
digest_size = 28
block_size = 64
-class SHA256(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class SHA256(object):
name = "sha256"
digest_size = 32
block_size = 64
-class SHA384(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class SHA384(object):
name = "sha384"
digest_size = 48
block_size = 128
-class SHA512(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class SHA512(object):
name = "sha512"
digest_size = 64
block_size = 128
-class RIPEMD160(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class RIPEMD160(object):
name = "ripemd160"
digest_size = 20
block_size = 64
-class Whirlpool(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class Whirlpool(object):
name = "whirlpool"
digest_size = 64
block_size = 64
-class MD5(BaseHash):
+@interfaces.register(interfaces.HashAlgorithm)
+class MD5(object):
name = "md5"
digest_size = 16
block_size = 64
diff --git a/cryptography/hazmat/primitives/hmac.py b/cryptography/hazmat/primitives/hmac.py
index 4da0cc3f..1457ed78 100644
--- a/cryptography/hazmat/primitives/hmac.py
+++ b/cryptography/hazmat/primitives/hmac.py
@@ -13,47 +13,39 @@
from __future__ import absolute_import, division, print_function
-import binascii
-
import six
+from cryptography.hazmat.primitives import interfaces
+
+@interfaces.register(interfaces.HashContext)
class HMAC(object):
- def __init__(self, key, msg=None, digestmod=None, ctx=None, backend=None):
+ def __init__(self, key, algorithm, ctx=None, backend=None):
super(HMAC, self).__init__()
+ if not isinstance(algorithm, interfaces.HashAlgorithm):
+ raise TypeError("Expected instance of interfaces.HashAlgorithm.")
+ self.algorithm = algorithm
+
if backend is None:
from cryptography.hazmat.bindings import _default_backend
backend = _default_backend
- if digestmod is None:
- raise TypeError("digestmod is a required argument")
-
self._backend = backend
- self.digestmod = digestmod
- self.key = key
+ self._key = key
if ctx is None:
- self._ctx = self._backend.hmacs.create_ctx(key, self.digestmod)
+ self._ctx = self._backend.hmacs.create_ctx(key, self.algorithm)
else:
self._ctx = ctx
- if msg is not None:
- self.update(msg)
-
def update(self, msg):
if isinstance(msg, six.text_type):
raise TypeError("Unicode-objects must be encoded before hashing")
self._backend.hmacs.update_ctx(self._ctx, msg)
def copy(self):
- return self.__class__(self.key, digestmod=self.digestmod,
- backend=self._backend, ctx=self._copy_ctx())
-
- def digest(self):
- return self._backend.hmacs.finalize_ctx(self._copy_ctx(),
- self.digestmod.digest_size)
-
- def hexdigest(self):
- return str(binascii.hexlify(self.digest()).decode("ascii"))
+ return self.__class__(self._key, self.algorithm, backend=self._backend,
+ ctx=self._backend.hmacs.copy_ctx(self._ctx))
- def _copy_ctx(self):
- return self._backend.hmacs.copy_ctx(self._ctx)
+ def finalize(self):
+ return self._backend.hmacs.finalize_ctx(self._ctx,
+ self.algorithm.digest_size)
diff --git a/cryptography/hazmat/primitives/interfaces.py b/cryptography/hazmat/primitives/interfaces.py
index 217490fd..ebf5e31e 100644
--- a/cryptography/hazmat/primitives/interfaces.py
+++ b/cryptography/hazmat/primitives/interfaces.py
@@ -59,3 +59,49 @@ class PaddingContext(six.with_metaclass(abc.ABCMeta)):
"""
finalize return bytes
"""
+
+
+class HashAlgorithm(six.with_metaclass(abc.ABCMeta)):
+ @abc.abstractproperty
+ def name(self):
+ """
+ A string naming this algorithm. (ex. sha256, md5)
+ """
+
+ @abc.abstractproperty
+ def digest_size(self):
+ """
+ The size of the resulting digest in bytes.
+ """
+
+ @abc.abstractproperty
+ def block_size(self):
+ """
+ The internal block size of the hash algorithm in bytes.
+ """
+
+
+class HashContext(six.with_metaclass(abc.ABCMeta)):
+ @abc.abstractproperty
+ def algorithm(self):
+ """
+ A HashAlgorithm that will be used by this context.
+ """
+
+ @abc.abstractmethod
+ def update(self, data):
+ """
+ hash data as bytes
+ """
+
+ @abc.abstractmethod
+ def finalize(self):
+ """
+ finalize this copy of the hash and return the digest as bytes.
+ """
+
+ @abc.abstractmethod
+ def copy(self):
+ """
+ return a HashContext that is a copy of the current context.
+ """