diff --git a/ChangeLog b/ChangeLog index a06986d7..778133d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,6 @@ [next] -* cipher: Make package pure-Python. +* cipher/hash/hmac: These modules and packages are now pure-Python. * mpi: Add bitwise operations. API Changes diff --git a/src/mbedtls/_md.pxd b/src/mbedtls/_md.pxd index 93e26430..76327405 100644 --- a/src/mbedtls/_md.pxd +++ b/src/mbedtls/_md.pxd @@ -18,8 +18,7 @@ cdef extern from "mbedtls/md.h" nogil: const mbedtls_md_info_t *md_info const int *mbedtls_md_list() - const mbedtls_md_info_t *mbedtls_md_info_from_string( - const char *md_name) + const mbedtls_md_info_t *mbedtls_md_info_from_string(const char *md_name) # mbedtls_md_info_from_type void mbedtls_md_init(mbedtls_md_context_t *ctx) @@ -66,3 +65,11 @@ cdef class MDBase: cdef const mbedtls_md_info_t* _info cdef mbedtls_md_context_t _ctx cdef _finish(self, const unsigned char *output) + + +cdef class Hash(MDBase): + pass + + +cdef class Hmac(MDBase): + pass diff --git a/src/mbedtls/_md.pyx b/src/mbedtls/_md.pyx index 5c4807a0..4bcc90b2 100644 --- a/src/mbedtls/_md.pyx +++ b/src/mbedtls/_md.pyx @@ -66,12 +66,11 @@ cdef class MDBase: name (str): The name of the message digest. """ - def __init__(self, name, buffer, hmac): - if not isinstance(name, str): - raise TypeError("name must be a string: got %r" % name) - self._info = _md.mbedtls_md_info_from_string( - name.upper().encode("ascii")) - check_error(_md.mbedtls_md_setup(&self._ctx, self._info, hmac)) + def __init__(self, name, _hmac): + name_ = name.upper().encode("ascii", "strict") + cdef char *c_name = name_ + self._info = _md.mbedtls_md_info_from_string(c_name) + check_error(_md.mbedtls_md_setup(&self._ctx, self._info, _hmac)) def __cinit__(self): """Initialize an `md_context` (as NONE).""" @@ -134,3 +133,100 @@ cdef class MDBase: def copy(self): """Return a copy ("clone") of the MD object.""" raise NotImplementedError + + +cdef class Hash(_md.MDBase): + + """Wrap and encapsulate hash calculations. + + This class is a wrapper for the hash calculations in the md module + of mbed TLS. The interface follows the recommendation from PEP 452 + for unkeyed hashes. + + Parameters: + name (str): The MD name known to mbed TLS. + + Attributes: + digest_size (int): The size of the message digest, in bytes. + block_size (int): The internal block size of the hash + algorithm in bytes. + name (str): The name of the message digest. + + """ + def __init__(self, name, buffer=None): + super().__init__(name, 0) + check_error(_md.mbedtls_md_starts(&self._ctx)) + self.update(buffer) + + def update(self, const unsigned char[:] buffer): + """Update the hash object with the `buffer`.""" + if buffer is None or buffer.size == 0: + return + check_error( + _md.mbedtls_md_update(&self._ctx, &buffer[0], buffer.size)) + + cdef _finish(self, unsigned char *output): + """Return the digest output of `message`.""" + return _md.mbedtls_md_finish(&self._ctx, output) + + def copy(self): + """Return a copy ("clone") of the hash object.""" + obj = Hash(self.name) + check_error(_md.mbedtls_md_clone(&obj._ctx, &self._ctx)) + return obj + + +cdef class Hmac(_md.MDBase): + + """Wrap and encapsulate HMAC calculations. + + This class is a wrapper for the HMAC calculations in the md module + of mbed TLS. The interface follows the recommendation from PEP 452 + for keyed hashes. + + Parameters: + key (bytes): The key to use. + name (bytes): The MD name known to mbed TLS. + + Warning: + The message is cleared after calculation of the digest. Only + call :meth:`digest` or :meth:`hexdigest` once per message. + + Attributes: + digest_size (int): The size of the message digest, in bytes. + block_size (int): The internal block size of the hash + algorithm in bytes. + name (bytes): The name of the message digest. + + """ + def __init__( + self, const unsigned char[:] key not None, name, buffer=None + ): + super().__init__(name, 1) + if not key.size: + key = b"\0" + check_error(_md.mbedtls_md_hmac_starts(&self._ctx, &key[0], key.size)) + self.update(buffer) + + def update(self, const unsigned char[:] buffer): + """Update the HMAC object with `buffer`.""" + if buffer is None or buffer.size == 0: + return + check_error( + _md.mbedtls_md_hmac_update(&self._ctx, &buffer[0], buffer.size)) + + cdef _finish(self, unsigned char *output): + """Return the HMAC of key and message.""" + ret = _md.mbedtls_md_hmac_finish(&self._ctx, output) + if ret != 0: + return ret + return _md.mbedtls_md_hmac_reset(&self._ctx) + + def copy(self): + """Return a copy ("clone") of the HMAC object. + + Warning: + Not implemented in mbed TLS, raises NotImplementedError. + + """ + raise NotImplementedError diff --git a/src/mbedtls/hash.pxd b/src/mbedtls/hash.pxd deleted file mode 100644 index 4892e1a7..00000000 --- a/src/mbedtls/hash.pxd +++ /dev/null @@ -1,12 +0,0 @@ -"""Generic message digest wrapper (hash algorithm).""" - -__author__ = "Mathias Laurin" -__copyright__ = "Copyright 2019, Mathias Laurin" -__license__ = "MIT License" - - -cimport mbedtls._md as _md - - -cdef class Hash(_md.MDBase): - pass diff --git a/src/mbedtls/hash.pyx b/src/mbedtls/hash.py similarity index 50% rename from src/mbedtls/hash.pyx rename to src/mbedtls/hash.py index 44fcb005..88a6ef41 100644 --- a/src/mbedtls/hash.pyx +++ b/src/mbedtls/hash.py @@ -1,12 +1,13 @@ """Generic message digest wrapper (hash algorithm).""" __author__ = "Mathias Laurin" -__copyright__ = "Copyright 2015, Elaborated Networks GmbH" +__copyright__ = ( + "Copyright 2015, Elaborated Networks GmbH, " + "Copyright 2019, Mathias Laurin" +) __license__ = "MIT License" -from libc.stdlib cimport malloc, free -cimport mbedtls._md as _md import mbedtls._md as _md from mbedtls.exceptions import * @@ -15,45 +16,7 @@ algorithms_available = _md.algorithms_available -cdef class Hash(_md.MDBase): - - """Wrap and encapsulate hash calculations. - - This class is a wrapper for the hash calculations in the md module - of mbed TLS. The interface follows the recommendation from PEP 452 - for unkeyed hashes. - - Parameters: - name (str): The MD name known to mbed TLS. - - Attributes: - digest_size (int): The size of the message digest, in bytes. - block_size (int): The internal block size of the hash - algorithm in bytes. - name (str): The name of the message digest. - - """ - def __init__(self, name, buffer=None): - super().__init__(name, buffer, 0) - check_error(_md.mbedtls_md_starts(&self._ctx)) - self.update(buffer) - - def update(self, const unsigned char[:] buffer): - """Update the hash object with the `buffer`.""" - if buffer is None or buffer.size == 0: - return - check_error( - _md.mbedtls_md_update(&self._ctx, &buffer[0], buffer.size)) - - cdef _finish(self, unsigned char *output): - """Return the digest output of `message`.""" - return _md.mbedtls_md_finish(&self._ctx, output) - - def copy(self): - """Return a copy ("clone") of the hash object.""" - obj = Hash(self.name) - check_error(_md.mbedtls_md_clone(&obj._ctx, &self._ctx)) - return obj +Hash = _md.Hash def new(name, buffer=None): diff --git a/src/mbedtls/hkdf.pyx b/src/mbedtls/hkdf.pyx index 65889e0d..bba3078f 100644 --- a/src/mbedtls/hkdf.pyx +++ b/src/mbedtls/hkdf.pyx @@ -11,7 +11,7 @@ __license__ = "MIT License" from libc.stdlib cimport malloc, free -cimport mbedtls.hmac as _hmac +cimport mbedtls._md as _hmac cimport mbedtls.hkdf as _hkdf import mbedtls.hmac as _hmac diff --git a/src/mbedtls/hmac.pxd b/src/mbedtls/hmac.pxd deleted file mode 100644 index b49d0078..00000000 --- a/src/mbedtls/hmac.pxd +++ /dev/null @@ -1,12 +0,0 @@ -"""Generic message digest wrapper (hash algorithm).""" - -__author__ = "Mathias Laurin" -__copyright__ = "Copyright 2019, Mathias Laurin" -__license__ = "MIT License" - - -cimport mbedtls._md as _md - - -cdef class Hmac(_md.MDBase): - pass diff --git a/src/mbedtls/hmac.py b/src/mbedtls/hmac.py new file mode 100644 index 00000000..8bbf5edd --- /dev/null +++ b/src/mbedtls/hmac.py @@ -0,0 +1,75 @@ +"""Generic message digest wrapper (hash algorithm).""" + +__author__ = "Mathias Laurin" +__copyright__ = ( + "Copyright 2015, Elaborated Networks GmbH, " + "Copyright 2019, Mathias Laurin" +) +__license__ = "MIT License" + + +import mbedtls._md as _md +from mbedtls.exceptions import * + + +algorithms_guaranteed = _md.algorithms_guaranteed +algorithms_available = _md.algorithms_available + + +Hmac = _md.Hmac + + +def new(key, buffer=None, digestmod=None): + """A generic constructor that takes the key algorithm as its first + parameter. + + """ + if digestmod is None: + digestmod = "md5" + return Hmac(key, digestmod, buffer) + + +def md2(key, buffer=None): + """MD2 message-digest algorithm.""" + return Hmac(key, "md2", buffer) + + +def md4(key, buffer=None): + """MD4 message-digest algorithm.""" + return Hmac(key, "md4", buffer) + + +def md5(key, buffer=None): + """MD5 message-digest algorithm.""" + return Hmac(key, "md5", buffer) + + +def sha1(key, buffer=None): + """Secure Hmac Algorithm 1 (SHA-1).""" + return Hmac(key, "sha1", buffer) + + +def sha224(key, buffer=None): + """Secure Hmac Algorithm 2 (SHA-2) with 224 bits hash value.""" + return Hmac(key, "sha224", buffer) + + +def sha256(key, buffer=None): + """Secure Hmac Algorithm 2 (SHA-2) with 256 bits hash value.""" + return Hmac(key, "sha256", buffer) + + +def sha384(key, buffer=None): + """Secure Hmac Algorithm 2 (SHA-2) with 384 bits hash value.""" + return Hmac(key, "sha384", buffer) + + +def sha512(key, buffer=None): + """Secure Hmac Algorithm 2 (SHA-2) with 512 bits hash value.""" + return Hmac(key, "sha512", buffer) + + +def ripemd160(key, buffer=None): + """RACE Integrity Primitives Evaluation Message Digest (RIPEMD) with + 160 bits hash value.""" + return Hmac(key, "ripemd160", buffer) diff --git a/src/mbedtls/hmac.pyx b/src/mbedtls/hmac.pyx deleted file mode 100644 index 0b29a9c5..00000000 --- a/src/mbedtls/hmac.pyx +++ /dev/null @@ -1,126 +0,0 @@ -"""Generic message digest wrapper (hash algorithm).""" - -__author__ = "Mathias Laurin" -__copyright__ = "Copyright 2015, Elaborated Networks GmbH" -__license__ = "MIT License" - - -from libc.stdlib cimport malloc, free -cimport mbedtls._md as _md -import mbedtls._md as _md -from mbedtls.exceptions import * - - -algorithms_guaranteed = _md.algorithms_guaranteed -algorithms_available = _md.algorithms_available - - -cdef class Hmac(_md.MDBase): - - """Wrap and encapsulate HMAC calculations. - - This class is a wrapper for the HMAC calculations in the md module - of mbed TLS. The interface follows the recommendation from PEP 452 - for keyed hashes. - - Parameters: - key (bytes): The key to use. - name (bytes): The MD name known to mbed TLS. - - Warning: - The message is cleared after calculation of the digest. Only - call :meth:`digest` or :meth:`hexdigest` once per message. - - Attributes: - digest_size (int): The size of the message digest, in bytes. - block_size (int): The internal block size of the hash - algorithm in bytes. - name (bytes): The name of the message digest. - - """ - def __init__( - self, const unsigned char[:] key not None, name, buffer=None): - super().__init__(name, buffer, 1) - if not key.size: - key = b"\0" - check_error(_md.mbedtls_md_hmac_starts(&self._ctx, &key[0], key.size)) - self.update(buffer) - - def update(self, const unsigned char[:] buffer): - """Update the HMAC object with `buffer`.""" - if buffer is None or buffer.size == 0: - return - check_error( - _md.mbedtls_md_hmac_update(&self._ctx, &buffer[0], buffer.size)) - - cdef _finish(self, unsigned char *output): - """Return the HMAC of key and message.""" - ret = _md.mbedtls_md_hmac_finish(&self._ctx, output) - if ret != 0: - return ret - return _md.mbedtls_md_hmac_reset(&self._ctx) - - def copy(self): - """Return a copy ("clone") of the HMAC object. - - Warning: - Not implemented in mbed TLS, raises NotImplementedError. - - """ - raise NotImplementedError - - -def new(key, buffer=None, digestmod=None): - """A generic constructor that takes the key algorithm as its first - parameter. - - """ - if digestmod is None: - digestmod = "md5" - return Hmac(key, digestmod, buffer) - - -def md2(key, buffer=None): - """MD2 message-digest algorithm.""" - return Hmac(key, "md2", buffer) - - -def md4(key, buffer=None): - """MD4 message-digest algorithm.""" - return Hmac(key, "md4", buffer) - - -def md5(key, buffer=None): - """MD5 message-digest algorithm.""" - return Hmac(key, "md5", buffer) - - -def sha1(key, buffer=None): - """Secure Hmac Algorithm 1 (SHA-1).""" - return Hmac(key, "sha1", buffer) - - -def sha224(key, buffer=None): - """Secure Hmac Algorithm 2 (SHA-2) with 224 bits hash value.""" - return Hmac(key, "sha224", buffer) - - -def sha256(key, buffer=None): - """Secure Hmac Algorithm 2 (SHA-2) with 256 bits hash value.""" - return Hmac(key, "sha256", buffer) - - -def sha384(key, buffer=None): - """Secure Hmac Algorithm 2 (SHA-2) with 384 bits hash value.""" - return Hmac(key, "sha384", buffer) - - -def sha512(key, buffer=None): - """Secure Hmac Algorithm 2 (SHA-2) with 512 bits hash value.""" - return Hmac(key, "sha512", buffer) - - -def ripemd160(key, buffer=None): - """RACE Integrity Primitives Evaluation Message Digest (RIPEMD) with - 160 bits hash value.""" - return Hmac(key, "ripemd160", buffer)