slight update

This commit is contained in:
2024-12-01 04:19:04 +09:00
parent 00b0afd17a
commit 4dbe1bee11
3130 changed files with 508084 additions and 0 deletions

View File

@ -0,0 +1,247 @@
# ===================================================================
#
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from binascii import unhexlify
from Crypto.Util.py3compat import bord, tobytes
from Crypto.Random import get_random_bytes
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_blake2b_lib = load_pycryptodome_raw_lib("Crypto.Hash._BLAKE2b",
"""
int blake2b_init(void **state,
const uint8_t *key,
size_t key_size,
size_t digest_size);
int blake2b_destroy(void *state);
int blake2b_update(void *state,
const uint8_t *buf,
size_t len);
int blake2b_digest(const void *state,
uint8_t digest[64]);
int blake2b_copy(const void *src, void *dst);
""")
class BLAKE2b_Hash(object):
"""A BLAKE2b hash object.
Do not instantiate directly. Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The internal block size of the hash algorithm in bytes.
block_size = 64
def __init__(self, data, key, digest_bytes, update_after_digest):
# The size of the resulting hash in bytes.
self.digest_size = digest_bytes
self._update_after_digest = update_after_digest
self._digest_done = False
# See https://tools.ietf.org/html/rfc7693
if digest_bytes in (20, 32, 48, 64) and not key:
self.oid = "1.3.6.1.4.1.1722.12.2.1." + str(digest_bytes)
state = VoidPointer()
result = _raw_blake2b_lib.blake2b_init(state.address_of(),
c_uint8_ptr(key),
c_size_t(len(key)),
c_size_t(digest_bytes)
)
if result:
raise ValueError("Error %d while instantiating BLAKE2b" % result)
self._state = SmartPointer(state.get(),
_raw_blake2b_lib.blake2b_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (bytes/bytearray/memoryview): The next chunk of the message being hashed.
"""
if self._digest_done and not self._update_after_digest:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
result = _raw_blake2b_lib.blake2b_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while hashing BLAKE2b data" % result)
return self
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(64)
result = _raw_blake2b_lib.blake2b_digest(self._state.get(),
bfr)
if result:
raise ValueError("Error %d while creating BLAKE2b digest" % result)
self._digest_done = True
return get_raw_buffer(bfr)[:self.digest_size]
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in tuple(self.digest())])
def verify(self, mac_tag):
"""Verify that a given **binary** MAC (computed by another party)
is valid.
Args:
mac_tag (bytes/bytearray/memoryview): the expected MAC of the message.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
secret = get_random_bytes(16)
mac1 = new(digest_bits=160, key=secret, data=mac_tag)
mac2 = new(digest_bits=160, key=secret, data=self.digest())
if mac1.digest() != mac2.digest():
raise ValueError("MAC check failed")
def hexverify(self, hex_mac_tag):
"""Verify that a given **printable** MAC (computed by another party)
is valid.
Args:
hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
self.verify(unhexlify(tobytes(hex_mac_tag)))
def new(self, **kwargs):
"""Return a new instance of a BLAKE2b hash object.
See :func:`new`.
"""
if "digest_bytes" not in kwargs and "digest_bits" not in kwargs:
kwargs["digest_bytes"] = self.digest_size
return new(**kwargs)
def new(**kwargs):
"""Create a new hash object.
Args:
data (bytes/bytearray/memoryview):
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`BLAKE2b_Hash.update`.
digest_bytes (integer):
Optional. The size of the digest, in bytes (1 to 64). Default is 64.
digest_bits (integer):
Optional and alternative to ``digest_bytes``.
The size of the digest, in bits (8 to 512, in steps of 8).
Default is 512.
key (bytes/bytearray/memoryview):
Optional. The key to use to compute the MAC (1 to 64 bytes).
If not specified, no key will be used.
update_after_digest (boolean):
Optional. By default, a hash object cannot be updated anymore after
the digest is computed. When this flag is ``True``, such check
is no longer enforced.
Returns:
A :class:`BLAKE2b_Hash` hash object
"""
data = kwargs.pop("data", None)
update_after_digest = kwargs.pop("update_after_digest", False)
digest_bytes = kwargs.pop("digest_bytes", None)
digest_bits = kwargs.pop("digest_bits", None)
if None not in (digest_bytes, digest_bits):
raise TypeError("Only one digest parameter must be provided")
if (None, None) == (digest_bytes, digest_bits):
digest_bytes = 64
if digest_bytes is not None:
if not (1 <= digest_bytes <= 64):
raise ValueError("'digest_bytes' not in range 1..64")
else:
if not (8 <= digest_bits <= 512) or (digest_bits % 8):
raise ValueError("'digest_bits' not in range 8..512, "
"with steps of 8")
digest_bytes = digest_bits // 8
key = kwargs.pop("key", b"")
if len(key) > 64:
raise ValueError("BLAKE2b key cannot exceed 64 bytes")
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return BLAKE2b_Hash(data, key, digest_bytes, update_after_digest)

View File

@ -0,0 +1,32 @@
from typing import Any, Union
from types import ModuleType
Buffer = Union[bytes, bytearray, memoryview]
class BLAKE2b_Hash(object):
block_size: int
digest_size: int
oid: str
def __init__(self,
data: Buffer,
key: Buffer,
digest_bytes: bytes,
update_after_digest: bool) -> None: ...
def update(self, data: Buffer) -> BLAKE2b_Hash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def verify(self, mac_tag: Buffer) -> None: ...
def hexverify(self, hex_mac_tag: str) -> None: ...
def new(self,
data: Buffer = ...,
digest_bytes: int = ...,
digest_bits: int = ...,
key: Buffer = ...,
update_after_digest: bool = ...) -> BLAKE2b_Hash: ...
def new(data: Buffer = ...,
digest_bytes: int = ...,
digest_bits: int = ...,
key: Buffer = ...,
update_after_digest: bool = ...) -> BLAKE2b_Hash: ...

View File

@ -0,0 +1,247 @@
# ===================================================================
#
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from binascii import unhexlify
from Crypto.Util.py3compat import bord, tobytes
from Crypto.Random import get_random_bytes
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_blake2s_lib = load_pycryptodome_raw_lib("Crypto.Hash._BLAKE2s",
"""
int blake2s_init(void **state,
const uint8_t *key,
size_t key_size,
size_t digest_size);
int blake2s_destroy(void *state);
int blake2s_update(void *state,
const uint8_t *buf,
size_t len);
int blake2s_digest(const void *state,
uint8_t digest[32]);
int blake2s_copy(const void *src, void *dst);
""")
class BLAKE2s_Hash(object):
"""A BLAKE2s hash object.
Do not instantiate directly. Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The internal block size of the hash algorithm in bytes.
block_size = 32
def __init__(self, data, key, digest_bytes, update_after_digest):
# The size of the resulting hash in bytes.
self.digest_size = digest_bytes
self._update_after_digest = update_after_digest
self._digest_done = False
# See https://tools.ietf.org/html/rfc7693
if digest_bytes in (16, 20, 28, 32) and not key:
self.oid = "1.3.6.1.4.1.1722.12.2.2." + str(digest_bytes)
state = VoidPointer()
result = _raw_blake2s_lib.blake2s_init(state.address_of(),
c_uint8_ptr(key),
c_size_t(len(key)),
c_size_t(digest_bytes)
)
if result:
raise ValueError("Error %d while instantiating BLAKE2s" % result)
self._state = SmartPointer(state.get(),
_raw_blake2s_lib.blake2s_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._digest_done and not self._update_after_digest:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
result = _raw_blake2s_lib.blake2s_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while hashing BLAKE2s data" % result)
return self
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(32)
result = _raw_blake2s_lib.blake2s_digest(self._state.get(),
bfr)
if result:
raise ValueError("Error %d while creating BLAKE2s digest" % result)
self._digest_done = True
return get_raw_buffer(bfr)[:self.digest_size]
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in tuple(self.digest())])
def verify(self, mac_tag):
"""Verify that a given **binary** MAC (computed by another party)
is valid.
Args:
mac_tag (byte string/byte array/memoryview): the expected MAC of the message.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
secret = get_random_bytes(16)
mac1 = new(digest_bits=160, key=secret, data=mac_tag)
mac2 = new(digest_bits=160, key=secret, data=self.digest())
if mac1.digest() != mac2.digest():
raise ValueError("MAC check failed")
def hexverify(self, hex_mac_tag):
"""Verify that a given **printable** MAC (computed by another party)
is valid.
Args:
hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
self.verify(unhexlify(tobytes(hex_mac_tag)))
def new(self, **kwargs):
"""Return a new instance of a BLAKE2s hash object.
See :func:`new`.
"""
if "digest_bytes" not in kwargs and "digest_bits" not in kwargs:
kwargs["digest_bytes"] = self.digest_size
return new(**kwargs)
def new(**kwargs):
"""Create a new hash object.
Args:
data (byte string/byte array/memoryview):
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`BLAKE2s_Hash.update`.
digest_bytes (integer):
Optional. The size of the digest, in bytes (1 to 32). Default is 32.
digest_bits (integer):
Optional and alternative to ``digest_bytes``.
The size of the digest, in bits (8 to 256, in steps of 8).
Default is 256.
key (byte string):
Optional. The key to use to compute the MAC (1 to 64 bytes).
If not specified, no key will be used.
update_after_digest (boolean):
Optional. By default, a hash object cannot be updated anymore after
the digest is computed. When this flag is ``True``, such check
is no longer enforced.
Returns:
A :class:`BLAKE2s_Hash` hash object
"""
data = kwargs.pop("data", None)
update_after_digest = kwargs.pop("update_after_digest", False)
digest_bytes = kwargs.pop("digest_bytes", None)
digest_bits = kwargs.pop("digest_bits", None)
if None not in (digest_bytes, digest_bits):
raise TypeError("Only one digest parameter must be provided")
if (None, None) == (digest_bytes, digest_bits):
digest_bytes = 32
if digest_bytes is not None:
if not (1 <= digest_bytes <= 32):
raise ValueError("'digest_bytes' not in range 1..32")
else:
if not (8 <= digest_bits <= 256) or (digest_bits % 8):
raise ValueError("'digest_bits' not in range 8..256, "
"with steps of 8")
digest_bytes = digest_bits // 8
key = kwargs.pop("key", b"")
if len(key) > 32:
raise ValueError("BLAKE2s key cannot exceed 32 bytes")
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return BLAKE2s_Hash(data, key, digest_bytes, update_after_digest)

View File

@ -0,0 +1,26 @@
from typing import Any, Union
Buffer = Union[bytes, bytearray, memoryview]
class BLAKE2s_Hash(object):
block_size: int
digest_size: int
oid: str
def __init__(self,
data: Buffer,
key: Buffer,
digest_bytes: bytes,
update_after_digest: bool) -> None: ...
def update(self, data: Buffer) -> BLAKE2s_Hash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def verify(self, mac_tag: Buffer) -> None: ...
def hexverify(self, hex_mac_tag: str) -> None: ...
def new(self, **kwargs: Any) -> BLAKE2s_Hash: ...
def new(data: Buffer = ...,
digest_bytes: int = ...,
digest_bits: int = ...,
key: Buffer = ...,
update_after_digest: bool = ...) -> BLAKE2s_Hash: ...

View File

@ -0,0 +1,306 @@
# -*- coding: utf-8 -*-
#
# Hash/CMAC.py - Implements the CMAC algorithm
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from binascii import unhexlify
from Crypto.Hash import BLAKE2s
from Crypto.Util.strxor import strxor
from Crypto.Util.number import long_to_bytes, bytes_to_long
from Crypto.Util.py3compat import bord, tobytes, _copy_bytes
from Crypto.Random import get_random_bytes
# The size of the authentication tag produced by the MAC.
digest_size = None
def _shift_bytes(bs, xor_lsb=0):
num = (bytes_to_long(bs) << 1) ^ xor_lsb
return long_to_bytes(num, len(bs))[-len(bs):]
class CMAC(object):
"""A CMAC hash object.
Do not instantiate directly. Use the :func:`new` function.
:ivar digest_size: the size in bytes of the resulting MAC tag
:vartype digest_size: integer
"""
digest_size = None
def __init__(self, key, msg, ciphermod, cipher_params, mac_len,
update_after_digest):
self.digest_size = mac_len
self._key = _copy_bytes(None, None, key)
self._factory = ciphermod
self._cipher_params = cipher_params
self._block_size = bs = ciphermod.block_size
self._mac_tag = None
self._update_after_digest = update_after_digest
# Section 5.3 of NIST SP 800 38B and Appendix B
if bs == 8:
const_Rb = 0x1B
self._max_size = 8 * (2 ** 21)
elif bs == 16:
const_Rb = 0x87
self._max_size = 16 * (2 ** 48)
else:
raise TypeError("CMAC requires a cipher with a block size"
" of 8 or 16 bytes, not %d" % bs)
# Compute sub-keys
zero_block = b'\x00' * bs
self._ecb = ciphermod.new(key,
ciphermod.MODE_ECB,
**self._cipher_params)
L = self._ecb.encrypt(zero_block)
if bord(L[0]) & 0x80:
self._k1 = _shift_bytes(L, const_Rb)
else:
self._k1 = _shift_bytes(L)
if bord(self._k1[0]) & 0x80:
self._k2 = _shift_bytes(self._k1, const_Rb)
else:
self._k2 = _shift_bytes(self._k1)
# Initialize CBC cipher with zero IV
self._cbc = ciphermod.new(key,
ciphermod.MODE_CBC,
zero_block,
**self._cipher_params)
# Cache for outstanding data to authenticate
self._cache = bytearray(bs)
self._cache_n = 0
# Last piece of ciphertext produced
self._last_ct = zero_block
# Last block that was encrypted with AES
self._last_pt = None
# Counter for total message size
self._data_size = 0
if msg:
self.update(msg)
def update(self, msg):
"""Authenticate the next chunk of message.
Args:
data (byte string/byte array/memoryview): The next chunk of data
"""
if self._mac_tag is not None and not self._update_after_digest:
raise TypeError("update() cannot be called after digest() or verify()")
self._data_size += len(msg)
bs = self._block_size
if self._cache_n > 0:
filler = min(bs - self._cache_n, len(msg))
self._cache[self._cache_n:self._cache_n+filler] = msg[:filler]
self._cache_n += filler
if self._cache_n < bs:
return self
msg = memoryview(msg)[filler:]
self._update(self._cache)
self._cache_n = 0
remain = len(msg) % bs
if remain > 0:
self._update(msg[:-remain])
self._cache[:remain] = msg[-remain:]
else:
self._update(msg)
self._cache_n = remain
return self
def _update(self, data_block):
"""Update a block aligned to the block boundary"""
bs = self._block_size
assert len(data_block) % bs == 0
if len(data_block) == 0:
return
ct = self._cbc.encrypt(data_block)
if len(data_block) == bs:
second_last = self._last_ct
else:
second_last = ct[-bs*2:-bs]
self._last_ct = ct[-bs:]
self._last_pt = strxor(second_last, data_block[-bs:])
def copy(self):
"""Return a copy ("clone") of the CMAC object.
The copy will have the same internal state as the original CMAC
object.
This can be used to efficiently compute the MAC tag of byte
strings that share a common initial substring.
:return: An :class:`CMAC`
"""
obj = self.__new__(CMAC)
obj.__dict__ = self.__dict__.copy()
obj._cbc = self._factory.new(self._key,
self._factory.MODE_CBC,
self._last_ct,
**self._cipher_params)
obj._cache = self._cache[:]
obj._last_ct = self._last_ct[:]
return obj
def digest(self):
"""Return the **binary** (non-printable) MAC tag of the message
that has been authenticated so far.
:return: The MAC tag, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bs = self._block_size
if self._mac_tag is not None and not self._update_after_digest:
return self._mac_tag
if self._data_size > self._max_size:
raise ValueError("MAC is unsafe for this message")
if self._cache_n == 0 and self._data_size > 0:
# Last block was full
pt = strxor(self._last_pt, self._k1)
else:
# Last block is partial (or message length is zero)
partial = self._cache[:]
partial[self._cache_n:] = b'\x80' + b'\x00' * (bs - self._cache_n - 1)
pt = strxor(strxor(self._last_ct, partial), self._k2)
self._mac_tag = self._ecb.encrypt(pt)[:self.digest_size]
return self._mac_tag
def hexdigest(self):
"""Return the **printable** MAC tag of the message authenticated so far.
:return: The MAC tag, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x)
for x in tuple(self.digest())])
def verify(self, mac_tag):
"""Verify that a given **binary** MAC (computed by another party)
is valid.
Args:
mac_tag (byte string/byte array/memoryview): the expected MAC of the message.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
secret = get_random_bytes(16)
mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag)
mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest())
if mac1.digest() != mac2.digest():
raise ValueError("MAC check failed")
def hexverify(self, hex_mac_tag):
"""Verify that a given **printable** MAC (computed by another party)
is valid.
Args:
hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
self.verify(unhexlify(tobytes(hex_mac_tag)))
def new(key, msg=None, ciphermod=None, cipher_params=None, mac_len=None,
update_after_digest=False):
"""Create a new MAC object.
Args:
key (byte string/byte array/memoryview):
key for the CMAC object.
The key must be valid for the underlying cipher algorithm.
For instance, it must be 16 bytes long for AES-128.
ciphermod (module):
A cipher module from :mod:`Crypto.Cipher`.
The cipher's block size has to be 128 bits,
like :mod:`Crypto.Cipher.AES`, to reduce the probability
of collisions.
msg (byte string/byte array/memoryview):
Optional. The very first chunk of the message to authenticate.
It is equivalent to an early call to `CMAC.update`. Optional.
cipher_params (dict):
Optional. A set of parameters to use when instantiating a cipher
object.
mac_len (integer):
Length of the MAC, in bytes.
It must be at least 4 bytes long.
The default (and recommended) length matches the size of a cipher block.
update_after_digest (boolean):
Optional. By default, a hash object cannot be updated anymore after
the digest is computed. When this flag is ``True``, such check
is no longer enforced.
Returns:
A :class:`CMAC` object
"""
if ciphermod is None:
raise TypeError("ciphermod must be specified (try AES)")
cipher_params = {} if cipher_params is None else dict(cipher_params)
if mac_len is None:
mac_len = ciphermod.block_size
if mac_len < 4:
raise ValueError("MAC tag length must be at least 4 bytes long")
if mac_len > ciphermod.block_size:
raise ValueError("MAC tag length cannot be larger than a cipher block (%d) bytes" % ciphermod.block_size)
return CMAC(key, msg, ciphermod, cipher_params, mac_len,
update_after_digest)

View File

@ -0,0 +1,30 @@
from types import ModuleType
from typing import Union, Dict, Any
Buffer = Union[bytes, bytearray, memoryview]
digest_size: int
class CMAC(object):
digest_size: int
def __init__(self,
key: Buffer,
msg: Buffer,
ciphermod: ModuleType,
cipher_params: Dict[str, Any],
mac_len: int, update_after_digest: bool) -> None: ...
def update(self, data: Buffer) -> CMAC: ...
def copy(self) -> CMAC: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def verify(self, mac_tag: Buffer) -> None: ...
def hexverify(self, hex_mac_tag: str) -> None: ...
def new(key: Buffer,
msg: Buffer = ...,
ciphermod: ModuleType = ...,
cipher_params: Dict[str, Any] = ...,
mac_len: int = ...,
update_after_digest: bool = ...) -> CMAC: ...

View File

@ -0,0 +1,238 @@
#
# HMAC.py - Implements the HMAC algorithm as described by RFC 2104.
#
# ===================================================================
#
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.py3compat import bord, tobytes
from binascii import unhexlify
from Crypto.Hash import BLAKE2s
from Crypto.Util.strxor import strxor
from Crypto.Random import get_random_bytes
__all__ = ['new', 'HMAC']
_hash2hmac_oid = {
'1.3.14.3.2.26': '1.2.840.113549.2.7', # SHA-1
'2.16.840.1.101.3.4.2.4': '1.2.840.113549.2.8', # SHA-224
'2.16.840.1.101.3.4.2.1': '1.2.840.113549.2.9', # SHA-256
'2.16.840.1.101.3.4.2.2': '1.2.840.113549.2.10', # SHA-384
'2.16.840.1.101.3.4.2.3': '1.2.840.113549.2.11', # SHA-512
'2.16.840.1.101.3.4.2.5': '1.2.840.113549.2.12', # SHA-512_224
'2.16.840.1.101.3.4.2.6': '1.2.840.113549.2.13', # SHA-512_256
'2.16.840.1.101.3.4.2.7': '2.16.840.1.101.3.4.2.13', # SHA-3 224
'2.16.840.1.101.3.4.2.8': '2.16.840.1.101.3.4.2.14', # SHA-3 256
'2.16.840.1.101.3.4.2.9': '2.16.840.1.101.3.4.2.15', # SHA-3 384
'2.16.840.1.101.3.4.2.10': '2.16.840.1.101.3.4.2.16', # SHA-3 512
}
_hmac2hash_oid = {v: k for k, v in _hash2hmac_oid.items()}
class HMAC(object):
"""An HMAC hash object.
Do not instantiate directly. Use the :func:`new` function.
:ivar digest_size: the size in bytes of the resulting MAC tag
:vartype digest_size: integer
:ivar oid: the ASN.1 object ID of the HMAC algorithm.
Only present if the algorithm was officially assigned one.
"""
def __init__(self, key, msg=b"", digestmod=None):
if digestmod is None:
from Crypto.Hash import MD5
digestmod = MD5
if msg is None:
msg = b""
# Size of the MAC tag
self.digest_size = digestmod.digest_size
self._digestmod = digestmod
# Hash OID --> HMAC OID
try:
self.oid = _hash2hmac_oid[digestmod.oid]
except (KeyError, AttributeError):
pass
if isinstance(key, memoryview):
key = key.tobytes()
try:
if len(key) <= digestmod.block_size:
# Step 1 or 2
key_0 = key + b"\x00" * (digestmod.block_size - len(key))
else:
# Step 3
hash_k = digestmod.new(key).digest()
key_0 = hash_k + b"\x00" * (digestmod.block_size - len(hash_k))
except AttributeError:
# Not all hash types have "block_size"
raise ValueError("Hash type incompatible to HMAC")
# Step 4
key_0_ipad = strxor(key_0, b"\x36" * len(key_0))
# Start step 5 and 6
self._inner = digestmod.new(key_0_ipad)
self._inner.update(msg)
# Step 7
key_0_opad = strxor(key_0, b"\x5c" * len(key_0))
# Start step 8 and 9
self._outer = digestmod.new(key_0_opad)
def update(self, msg):
"""Authenticate the next chunk of message.
Args:
data (byte string/byte array/memoryview): The next chunk of data
"""
self._inner.update(msg)
return self
def _pbkdf2_hmac_assist(self, first_digest, iterations):
"""Carry out the expensive inner loop for PBKDF2-HMAC"""
result = self._digestmod._pbkdf2_hmac_assist(
self._inner,
self._outer,
first_digest,
iterations)
return result
def copy(self):
"""Return a copy ("clone") of the HMAC object.
The copy will have the same internal state as the original HMAC
object.
This can be used to efficiently compute the MAC tag of byte
strings that share a common initial substring.
:return: An :class:`HMAC`
"""
new_hmac = HMAC(b"fake key", digestmod=self._digestmod)
# Syncronize the state
new_hmac._inner = self._inner.copy()
new_hmac._outer = self._outer.copy()
return new_hmac
def digest(self):
"""Return the **binary** (non-printable) MAC tag of the message
authenticated so far.
:return: The MAC tag digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
frozen_outer_hash = self._outer.copy()
frozen_outer_hash.update(self._inner.digest())
return frozen_outer_hash.digest()
def verify(self, mac_tag):
"""Verify that a given **binary** MAC (computed by another party)
is valid.
Args:
mac_tag (byte string/byte string/memoryview): the expected MAC of the message.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
secret = get_random_bytes(16)
mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag)
mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest())
if mac1.digest() != mac2.digest():
raise ValueError("MAC check failed")
def hexdigest(self):
"""Return the **printable** MAC tag of the message authenticated so far.
:return: The MAC tag, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x)
for x in tuple(self.digest())])
def hexverify(self, hex_mac_tag):
"""Verify that a given **printable** MAC (computed by another party)
is valid.
Args:
hex_mac_tag (string): the expected MAC of the message,
as a hexadecimal string.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
self.verify(unhexlify(tobytes(hex_mac_tag)))
def new(key, msg=b"", digestmod=None):
"""Create a new MAC object.
Args:
key (bytes/bytearray/memoryview):
key for the MAC object.
It must be long enough to match the expected security level of the
MAC.
msg (bytes/bytearray/memoryview):
Optional. The very first chunk of the message to authenticate.
It is equivalent to an early call to :meth:`HMAC.update`.
digestmod (module):
The hash to use to implement the HMAC.
Default is :mod:`Crypto.Hash.MD5`.
Returns:
An :class:`HMAC` object
"""
return HMAC(key, msg, digestmod)

View File

@ -0,0 +1,25 @@
from types import ModuleType
from typing import Union, Dict
Buffer = Union[bytes, bytearray, memoryview]
digest_size: int
class HMAC(object):
digest_size: int
def __init__(self,
key: Buffer,
msg: Buffer,
digestmod: ModuleType) -> None: ...
def update(self, msg: Buffer) -> HMAC: ...
def copy(self) -> HMAC: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def verify(self, mac_tag: Buffer) -> None: ...
def hexverify(self, hex_mac_tag: str) -> None: ...
def new(key: Buffer,
msg: Buffer = ...,
digestmod: ModuleType = ...) -> HMAC: ...

View File

@ -0,0 +1,179 @@
# ===================================================================
#
# Copyright (c) 2021, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from binascii import unhexlify
from Crypto.Util.py3compat import bord, tobytes, is_bytes
from Crypto.Random import get_random_bytes
from . import cSHAKE128, SHA3_256
from .cSHAKE128 import _bytepad, _encode_str, _right_encode
class KMAC_Hash(object):
"""A KMAC hash object.
Do not instantiate directly.
Use the :func:`new` function.
"""
def __init__(self, data, key, mac_len, custom,
oid_variant, cshake, rate):
# See https://tools.ietf.org/html/rfc8702
self.oid = "2.16.840.1.101.3.4.2." + oid_variant
self.digest_size = mac_len
self._mac = None
partial_newX = _bytepad(_encode_str(tobytes(key)), rate)
self._cshake = cshake._new(partial_newX, custom, b"KMAC")
if data:
self._cshake.update(data)
def update(self, data):
"""Authenticate the next chunk of message.
Args:
data (bytes/bytearray/memoryview): The next chunk of the message to
authenticate.
"""
if self._mac:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
self._cshake.update(data)
return self
def digest(self):
"""Return the **binary** (non-printable) MAC tag of the message.
:return: The MAC tag. Binary form.
:rtype: byte string
"""
if not self._mac:
self._cshake.update(_right_encode(self.digest_size * 8))
self._mac = self._cshake.read(self.digest_size)
return self._mac
def hexdigest(self):
"""Return the **printable** MAC tag of the message.
:return: The MAC tag. Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in tuple(self.digest())])
def verify(self, mac_tag):
"""Verify that a given **binary** MAC (computed by another party)
is valid.
Args:
mac_tag (bytes/bytearray/memoryview): the expected MAC of the message.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
secret = get_random_bytes(16)
mac1 = SHA3_256.new(secret + mac_tag)
mac2 = SHA3_256.new(secret + self.digest())
if mac1.digest() != mac2.digest():
raise ValueError("MAC check failed")
def hexverify(self, hex_mac_tag):
"""Verify that a given **printable** MAC (computed by another party)
is valid.
Args:
hex_mac_tag (string): the expected MAC of the message, as a hexadecimal string.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
self.verify(unhexlify(tobytes(hex_mac_tag)))
def new(self, **kwargs):
"""Return a new instance of a KMAC hash object.
See :func:`new`.
"""
if "mac_len" not in kwargs:
kwargs["mac_len"] = self.digest_size
return new(**kwargs)
def new(**kwargs):
"""Create a new KMAC128 object.
Args:
key (bytes/bytearray/memoryview):
The key to use to compute the MAC.
It must be at least 128 bits long (16 bytes).
data (bytes/bytearray/memoryview):
Optional. The very first chunk of the message to authenticate.
It is equivalent to an early call to :meth:`KMAC_Hash.update`.
mac_len (integer):
Optional. The size of the authentication tag, in bytes.
Default is 64. Minimum is 8.
custom (bytes/bytearray/memoryview):
Optional. A customization byte string (``S`` in SP 800-185).
Returns:
A :class:`KMAC_Hash` hash object
"""
key = kwargs.pop("key", None)
if not is_bytes(key):
raise TypeError("You must pass a key to KMAC128")
if len(key) < 16:
raise ValueError("The key must be at least 128 bits long (16 bytes)")
data = kwargs.pop("data", None)
mac_len = kwargs.pop("mac_len", 64)
if mac_len < 8:
raise ValueError("'mac_len' must be 8 bytes or more")
custom = kwargs.pop("custom", b"")
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return KMAC_Hash(data, key, mac_len, custom, "19", cSHAKE128, 168)

View File

@ -0,0 +1,33 @@
from typing import Union
from types import ModuleType
Buffer = Union[bytes, bytearray, memoryview]
class KMAC_Hash(object):
def __init__(self,
data: Buffer,
key: Buffer,
mac_len: int,
custom: Buffer,
oid_variant: str,
cshake: ModuleType,
rate: int) -> None: ...
def update(self, data: Buffer) -> KMAC_Hash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def verify(self, mac_tag: Buffer) -> None: ...
def hexverify(self, hex_mac_tag: str) -> None: ...
def new(self,
data: Buffer = ...,
mac_len: int = ...,
key: Buffer = ...,
custom: Buffer = ...) -> KMAC_Hash: ...
def new(key: Buffer,
data: Buffer = ...,
mac_len: int = ...,
custom: Buffer = ...) -> KMAC_Hash: ...

View File

@ -0,0 +1,74 @@
# ===================================================================
#
# Copyright (c) 2021, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.py3compat import is_bytes
from .KMAC128 import KMAC_Hash
from . import cSHAKE256
def new(**kwargs):
"""Create a new KMAC256 object.
Args:
key (bytes/bytearray/memoryview):
The key to use to compute the MAC.
It must be at least 256 bits long (32 bytes).
data (bytes/bytearray/memoryview):
Optional. The very first chunk of the message to authenticate.
It is equivalent to an early call to :meth:`KMAC_Hash.update`.
mac_len (integer):
Optional. The size of the authentication tag, in bytes.
Default is 64. Minimum is 8.
custom (bytes/bytearray/memoryview):
Optional. A customization byte string (``S`` in SP 800-185).
Returns:
A :class:`KMAC_Hash` hash object
"""
key = kwargs.pop("key", None)
if not is_bytes(key):
raise TypeError("You must pass a key to KMAC256")
if len(key) < 32:
raise ValueError("The key must be at least 256 bits long (32 bytes)")
data = kwargs.pop("data", None)
mac_len = kwargs.pop("mac_len", 64)
if mac_len < 8:
raise ValueError("'mac_len' must be 8 bytes or more")
custom = kwargs.pop("custom", b"")
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return KMAC_Hash(data, key, mac_len, custom, "20", cSHAKE256, 136)

View File

@ -0,0 +1,10 @@
from typing import Union
from .KMAC128 import KMAC_Hash
Buffer = Union[bytes, bytearray, memoryview]
def new(key: Buffer,
data: Buffer = ...,
mac_len: int = ...,
custom: Buffer = ...) -> KMAC_Hash: ...

View File

@ -0,0 +1,222 @@
# ===================================================================
#
# Copyright (c) 2021, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.number import long_to_bytes
from Crypto.Util.py3compat import bchr
from . import TurboSHAKE128
def _length_encode(x):
if x == 0:
return b'\x00'
S = long_to_bytes(x)
return S + bchr(len(S))
# Possible states for a KangarooTwelve instance, which depend on the amount of data processed so far.
SHORT_MSG = 1 # Still within the first 8192 bytes, but it is not certain we will exceed them.
LONG_MSG_S0 = 2 # Still within the first 8192 bytes, and it is certain we will exceed them.
LONG_MSG_SX = 3 # Beyond the first 8192 bytes.
SQUEEZING = 4 # No more data to process.
class K12_XOF(object):
"""A KangarooTwelve hash object.
Do not instantiate directly.
Use the :func:`new` function.
"""
def __init__(self, data, custom):
if custom == None:
custom = b''
self._custom = custom + _length_encode(len(custom))
self._state = SHORT_MSG
self._padding = None # Final padding is only decided in read()
# Internal hash that consumes FinalNode
# The real domain separation byte will be known before squeezing
self._hash1 = TurboSHAKE128.new(domain=1)
self._length1 = 0
# Internal hash that produces CV_i (reset each time)
self._hash2 = None
self._length2 = 0
# Incremented by one for each 8192-byte block
self._ctr = 0
if data:
self.update(data)
def update(self, data):
"""Hash the next piece of data.
.. note::
For better performance, submit chunks with a length multiple of 8192 bytes.
Args:
data (byte string/byte array/memoryview): The next chunk of the
message to hash.
"""
if self._state == SQUEEZING:
raise TypeError("You cannot call 'update' after the first 'read'")
if self._state == SHORT_MSG:
next_length = self._length1 + len(data)
if next_length + len(self._custom) <= 8192:
self._length1 = next_length
self._hash1.update(data)
return self
# Switch to tree hashing
self._state = LONG_MSG_S0
if self._state == LONG_MSG_S0:
data_mem = memoryview(data)
assert(self._length1 < 8192)
dtc = min(len(data), 8192 - self._length1)
self._hash1.update(data_mem[:dtc])
self._length1 += dtc
if self._length1 < 8192:
return self
# Finish hashing S_0 and start S_1
assert(self._length1 == 8192)
divider = b'\x03' + b'\x00' * 7
self._hash1.update(divider)
self._length1 += 8
self._hash2 = TurboSHAKE128.new(domain=0x0B)
self._length2 = 0
self._ctr = 1
self._state = LONG_MSG_SX
return self.update(data_mem[dtc:])
# LONG_MSG_SX
assert(self._state == LONG_MSG_SX)
index = 0
len_data = len(data)
# All iteractions could actually run in parallel
data_mem = memoryview(data)
while index < len_data:
new_index = min(index + 8192 - self._length2, len_data)
self._hash2.update(data_mem[index:new_index])
self._length2 += new_index - index
index = new_index
if self._length2 == 8192:
cv_i = self._hash2.read(32)
self._hash1.update(cv_i)
self._length1 += 32
self._hash2._reset()
self._length2 = 0
self._ctr += 1
return self
def read(self, length):
"""
Produce more bytes of the digest.
.. note::
You cannot use :meth:`update` anymore after the first call to
:meth:`read`.
Args:
length (integer): the amount of bytes this method must return
:return: the next piece of XOF output (of the given length)
:rtype: byte string
"""
custom_was_consumed = False
if self._state == SHORT_MSG:
self._hash1.update(self._custom)
self._padding = 0x07
self._state = SQUEEZING
if self._state == LONG_MSG_S0:
self.update(self._custom)
custom_was_consumed = True
assert(self._state == LONG_MSG_SX)
if self._state == LONG_MSG_SX:
if not custom_was_consumed:
self.update(self._custom)
# Is there still some leftover data in hash2?
if self._length2 > 0:
cv_i = self._hash2.read(32)
self._hash1.update(cv_i)
self._length1 += 32
self._hash2._reset()
self._length2 = 0
self._ctr += 1
trailer = _length_encode(self._ctr - 1) + b'\xFF\xFF'
self._hash1.update(trailer)
self._padding = 0x06
self._state = SQUEEZING
self._hash1._domain = self._padding
return self._hash1.read(length)
def new(self, data=None, custom=b''):
return type(self)(data, custom)
def new(data=None, custom=None):
"""Return a fresh instance of a KangarooTwelve object.
Args:
data (bytes/bytearray/memoryview):
Optional.
The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
custom (bytes):
Optional.
A customization byte string.
:Return: A :class:`K12_XOF` object
"""
return K12_XOF(data, custom)

View File

@ -0,0 +1,16 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class K12_XOF(object):
def __init__(self,
data: Optional[Buffer] = ...,
custom: Optional[bytes] = ...) -> None: ...
def update(self, data: Buffer) -> K12_XOF: ...
def read(self, length: int) -> bytes: ...
def new(self,
data: Optional[Buffer] = ...,
custom: Optional[bytes] = ...) -> None: ...
def new(data: Optional[Buffer] = ...,
custom: Optional[Buffer] = ...) -> K12_XOF: ...

View File

@ -0,0 +1,166 @@
# ===================================================================
#
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_md2_lib = load_pycryptodome_raw_lib(
"Crypto.Hash._MD2",
"""
int md2_init(void **shaState);
int md2_destroy(void *shaState);
int md2_update(void *hs,
const uint8_t *buf,
size_t len);
int md2_digest(const void *shaState,
uint8_t digest[20]);
int md2_copy(const void *src, void *dst);
""")
class MD2Hash(object):
"""An MD2 hash object.
Do not instantiate directly. Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 16
# The internal block size of the hash algorithm in bytes.
block_size = 16
# ASN.1 Object ID
oid = "1.2.840.113549.2.2"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_md2_lib.md2_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating MD2"
% result)
self._state = SmartPointer(state.get(),
_raw_md2_lib.md2_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_md2_lib.md2_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while instantiating MD2"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_md2_lib.md2_digest(self._state.get(),
bfr)
if result:
raise ValueError("Error %d while instantiating MD2"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = MD2Hash()
result = _raw_md2_lib.md2_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying MD2" % result)
return clone
def new(self, data=None):
return MD2Hash(data)
def new(data=None):
"""Create a new hash object.
:parameter data:
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`MD2Hash.update`.
:type data: bytes/bytearray/memoryview
:Return: A :class:`MD2Hash` hash object
"""
return MD2Hash().new(data)
# The size of the resulting hash in bytes.
digest_size = MD2Hash.digest_size
# The internal block size of the hash algorithm in bytes.
block_size = MD2Hash.block_size

View File

@ -0,0 +1,19 @@
from typing import Union
Buffer = Union[bytes, bytearray, memoryview]
class MD4Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Buffer = ...) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> MD4Hash: ...
def new(self, data: Buffer = ...) -> MD4Hash: ...
def new(data: Buffer = ...) -> MD4Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,185 @@
# ===================================================================
#
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
"""
MD4 is specified in RFC1320_ and produces the 128 bit digest of a message.
>>> from Crypto.Hash import MD4
>>>
>>> h = MD4.new()
>>> h.update(b'Hello')
>>> print h.hexdigest()
MD4 stand for Message Digest version 4, and it was invented by Rivest in 1990.
This algorithm is insecure. Do not use it for new designs.
.. _RFC1320: http://tools.ietf.org/html/rfc1320
"""
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_md4_lib = load_pycryptodome_raw_lib(
"Crypto.Hash._MD4",
"""
int md4_init(void **shaState);
int md4_destroy(void *shaState);
int md4_update(void *hs,
const uint8_t *buf,
size_t len);
int md4_digest(const void *shaState,
uint8_t digest[20]);
int md4_copy(const void *src, void *dst);
""")
class MD4Hash(object):
"""Class that implements an MD4 hash
"""
#: The size of the resulting hash in bytes.
digest_size = 16
#: The internal block size of the hash algorithm in bytes.
block_size = 64
#: ASN.1 Object ID
oid = "1.2.840.113549.2.4"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_md4_lib.md4_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating MD4"
% result)
self._state = SmartPointer(state.get(),
_raw_md4_lib.md4_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Repeated calls are equivalent to a single call with the concatenation
of all the arguments. In other words:
>>> m.update(a); m.update(b)
is equivalent to:
>>> m.update(a+b)
:Parameters:
data : byte string/byte array/memoryview
The next chunk of the message being hashed.
"""
result = _raw_md4_lib.md4_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while instantiating MD4"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that
has been hashed so far.
This method does not change the state of the hash object.
You can continue updating the object after calling this function.
:Return: A byte string of `digest_size` bytes. It may contain non-ASCII
characters, including null bytes.
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_md4_lib.md4_digest(self._state.get(),
bfr)
if result:
raise ValueError("Error %d while instantiating MD4"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been
hashed so far.
This method does not change the state of the hash object.
:Return: A string of 2* `digest_size` characters. It contains only
hexadecimal ASCII digits.
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:Return: A hash object of the same type
"""
clone = MD4Hash()
result = _raw_md4_lib.md4_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying MD4" % result)
return clone
def new(self, data=None):
return MD4Hash(data)
def new(data=None):
"""Return a fresh instance of the hash object.
:Parameters:
data : byte string/byte array/memoryview
The very first chunk of the message to hash.
It is equivalent to an early call to `MD4Hash.update()`.
Optional.
:Return: A `MD4Hash` object
"""
return MD4Hash().new(data)
#: The size of the resulting hash in bytes.
digest_size = MD4Hash.digest_size
#: The internal block size of the hash algorithm in bytes.
block_size = MD4Hash.block_size

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class MD4Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer] = ...) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> MD4Hash: ...
def new(self, data: Optional[Buffer] = ...) -> MD4Hash: ...
def new(data: Optional[Buffer] = ...) -> MD4Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,184 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import *
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_md5_lib = load_pycryptodome_raw_lib("Crypto.Hash._MD5",
"""
#define MD5_DIGEST_SIZE 16
int MD5_init(void **shaState);
int MD5_destroy(void *shaState);
int MD5_update(void *hs,
const uint8_t *buf,
size_t len);
int MD5_digest(const void *shaState,
uint8_t digest[MD5_DIGEST_SIZE]);
int MD5_copy(const void *src, void *dst);
int MD5_pbkdf2_hmac_assist(const void *inner,
const void *outer,
const uint8_t first_digest[MD5_DIGEST_SIZE],
uint8_t final_digest[MD5_DIGEST_SIZE],
size_t iterations);
""")
class MD5Hash(object):
"""A MD5 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 16
# The internal block size of the hash algorithm in bytes.
block_size = 64
# ASN.1 Object ID
oid = "1.2.840.113549.2.5"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_md5_lib.MD5_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating MD5"
% result)
self._state = SmartPointer(state.get(),
_raw_md5_lib.MD5_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_md5_lib.MD5_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while instantiating MD5"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_md5_lib.MD5_digest(self._state.get(),
bfr)
if result:
raise ValueError("Error %d while instantiating MD5"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = MD5Hash()
result = _raw_md5_lib.MD5_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying MD5" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA-1 hash object."""
return MD5Hash(data)
def new(data=None):
"""Create a new hash object.
:parameter data:
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`MD5Hash.update`.
:type data: byte string/byte array/memoryview
:Return: A :class:`MD5Hash` hash object
"""
return MD5Hash().new(data)
# The size of the resulting hash in bytes.
digest_size = 16
# The internal block size of the hash algorithm in bytes.
block_size = 64
def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations):
"""Compute the expensive inner loop in PBKDF-HMAC."""
assert len(first_digest) == digest_size
assert iterations > 0
bfr = create_string_buffer(digest_size);
result = _raw_md5_lib.MD5_pbkdf2_hmac_assist(
inner._state.get(),
outer._state.get(),
first_digest,
bfr,
c_size_t(iterations))
if result:
raise ValueError("Error %d with PBKDF2-HMAC assis for MD5" % result)
return get_raw_buffer(bfr)

View File

@ -0,0 +1,19 @@
from typing import Union
Buffer = Union[bytes, bytearray, memoryview]
class MD5Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Buffer = ...) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> MD5Hash: ...
def new(self, data: Buffer = ...) -> MD5Hash: ...
def new(data: Buffer = ...) -> MD5Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,217 @@
# -*- coding: utf-8 -*-
#
# Hash/Poly1305.py - Implements the Poly1305 MAC
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from binascii import unhexlify
from Crypto.Util.py3compat import bord, tobytes, _copy_bytes
from Crypto.Hash import BLAKE2s
from Crypto.Random import get_random_bytes
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_poly1305 = load_pycryptodome_raw_lib("Crypto.Hash._poly1305",
"""
int poly1305_init(void **state,
const uint8_t *r,
size_t r_len,
const uint8_t *s,
size_t s_len);
int poly1305_destroy(void *state);
int poly1305_update(void *state,
const uint8_t *in,
size_t len);
int poly1305_digest(const void *state,
uint8_t *digest,
size_t len);
""")
class Poly1305_MAC(object):
"""An Poly1305 MAC object.
Do not instantiate directly. Use the :func:`new` function.
:ivar digest_size: the size in bytes of the resulting MAC tag
:vartype digest_size: integer
"""
digest_size = 16
def __init__(self, r, s, data):
if len(r) != 16:
raise ValueError("Parameter r is not 16 bytes long")
if len(s) != 16:
raise ValueError("Parameter s is not 16 bytes long")
self._mac_tag = None
state = VoidPointer()
result = _raw_poly1305.poly1305_init(state.address_of(),
c_uint8_ptr(r),
c_size_t(len(r)),
c_uint8_ptr(s),
c_size_t(len(s))
)
if result:
raise ValueError("Error %d while instantiating Poly1305" % result)
self._state = SmartPointer(state.get(),
_raw_poly1305.poly1305_destroy)
if data:
self.update(data)
def update(self, data):
"""Authenticate the next chunk of message.
Args:
data (byte string/byte array/memoryview): The next chunk of data
"""
if self._mac_tag:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
result = _raw_poly1305.poly1305_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while hashing Poly1305 data" % result)
return self
def copy(self):
raise NotImplementedError()
def digest(self):
"""Return the **binary** (non-printable) MAC tag of the message
authenticated so far.
:return: The MAC tag digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
if self._mac_tag:
return self._mac_tag
bfr = create_string_buffer(16)
result = _raw_poly1305.poly1305_digest(self._state.get(),
bfr,
c_size_t(len(bfr)))
if result:
raise ValueError("Error %d while creating Poly1305 digest" % result)
self._mac_tag = get_raw_buffer(bfr)
return self._mac_tag
def hexdigest(self):
"""Return the **printable** MAC tag of the message authenticated so far.
:return: The MAC tag, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x)
for x in tuple(self.digest())])
def verify(self, mac_tag):
"""Verify that a given **binary** MAC (computed by another party)
is valid.
Args:
mac_tag (byte string/byte string/memoryview): the expected MAC of the message.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
secret = get_random_bytes(16)
mac1 = BLAKE2s.new(digest_bits=160, key=secret, data=mac_tag)
mac2 = BLAKE2s.new(digest_bits=160, key=secret, data=self.digest())
if mac1.digest() != mac2.digest():
raise ValueError("MAC check failed")
def hexverify(self, hex_mac_tag):
"""Verify that a given **printable** MAC (computed by another party)
is valid.
Args:
hex_mac_tag (string): the expected MAC of the message,
as a hexadecimal string.
Raises:
ValueError: if the MAC does not match. It means that the message
has been tampered with or that the MAC key is incorrect.
"""
self.verify(unhexlify(tobytes(hex_mac_tag)))
def new(**kwargs):
"""Create a new Poly1305 MAC object.
Args:
key (bytes/bytearray/memoryview):
The 32-byte key for the Poly1305 object.
cipher (module from ``Crypto.Cipher``):
The cipher algorithm to use for deriving the Poly1305
key pair *(r, s)*.
It can only be ``Crypto.Cipher.AES`` or ``Crypto.Cipher.ChaCha20``.
nonce (bytes/bytearray/memoryview):
Optional. The non-repeatable value to use for the MAC of this message.
It must be 16 bytes long for ``AES`` and 8 or 12 bytes for ``ChaCha20``.
If not passed, a random nonce is created; you will find it in the
``nonce`` attribute of the new object.
data (bytes/bytearray/memoryview):
Optional. The very first chunk of the message to authenticate.
It is equivalent to an early call to ``update()``.
Returns:
A :class:`Poly1305_MAC` object
"""
cipher = kwargs.pop("cipher", None)
if not hasattr(cipher, '_derive_Poly1305_key_pair'):
raise ValueError("Parameter 'cipher' must be AES or ChaCha20")
cipher_key = kwargs.pop("key", None)
if cipher_key is None:
raise TypeError("You must pass a parameter 'key'")
nonce = kwargs.pop("nonce", None)
data = kwargs.pop("data", None)
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
r, s, nonce = cipher._derive_Poly1305_key_pair(cipher_key, nonce)
new_mac = Poly1305_MAC(r, s, data)
new_mac.nonce = _copy_bytes(None, None, nonce) # nonce may still be just a memoryview
return new_mac

View File

@ -0,0 +1,24 @@
from types import ModuleType
from typing import Union
Buffer = Union[bytes, bytearray, memoryview]
class Poly1305_MAC(object):
block_size: int
digest_size: int
oid: str
def __init__(self,
r : int,
s : int,
data : Buffer) -> None: ...
def update(self, data: Buffer) -> Poly1305_MAC: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def verify(self, mac_tag: Buffer) -> None: ...
def hexverify(self, hex_mac_tag: str) -> None: ...
def new(key: Buffer,
cipher: ModuleType,
nonce: Buffer = ...,
data: Buffer = ...) -> Poly1305_MAC: ...

View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
# This file exists for backward compatibility with old code that refers to
# Crypto.Hash.RIPEMD
"""Deprecated alias for `Crypto.Hash.RIPEMD160`"""
from Crypto.Hash.RIPEMD160 import new, block_size, digest_size

View File

@ -0,0 +1,3 @@
# This file exists for backward compatibility with old code that refers to
# Crypto.Hash.SHA

View File

@ -0,0 +1,169 @@
# ===================================================================
#
# Copyright (c) 2014, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_ripemd160_lib = load_pycryptodome_raw_lib(
"Crypto.Hash._RIPEMD160",
"""
int ripemd160_init(void **shaState);
int ripemd160_destroy(void *shaState);
int ripemd160_update(void *hs,
const uint8_t *buf,
size_t len);
int ripemd160_digest(const void *shaState,
uint8_t digest[20]);
int ripemd160_copy(const void *src, void *dst);
""")
class RIPEMD160Hash(object):
"""A RIPEMD-160 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 20
# The internal block size of the hash algorithm in bytes.
block_size = 64
# ASN.1 Object ID
oid = "1.3.36.3.2.1"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_ripemd160_lib.ripemd160_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating RIPEMD160"
% result)
self._state = SmartPointer(state.get(),
_raw_ripemd160_lib.ripemd160_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_ripemd160_lib.ripemd160_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while instantiating ripemd160"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_ripemd160_lib.ripemd160_digest(self._state.get(),
bfr)
if result:
raise ValueError("Error %d while instantiating ripemd160"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = RIPEMD160Hash()
result = _raw_ripemd160_lib.ripemd160_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying ripemd160" % result)
return clone
def new(self, data=None):
"""Create a fresh RIPEMD-160 hash object."""
return RIPEMD160Hash(data)
def new(data=None):
"""Create a new hash object.
:parameter data:
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`RIPEMD160Hash.update`.
:type data: byte string/byte array/memoryview
:Return: A :class:`RIPEMD160Hash` hash object
"""
return RIPEMD160Hash().new(data)
# The size of the resulting hash in bytes.
digest_size = RIPEMD160Hash.digest_size
# The internal block size of the hash algorithm in bytes.
block_size = RIPEMD160Hash.block_size

View File

@ -0,0 +1,19 @@
from typing import Union
Buffer = Union[bytes, bytearray, memoryview]
class RIPEMD160Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Buffer = ...) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> RIPEMD160Hash: ...
def new(self, data: Buffer = ...) -> RIPEMD160Hash: ...
def new(data: Buffer = ...) -> RIPEMD160Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
# This file exists for backward compatibility with old code that refers to
# Crypto.Hash.SHA
from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size

View File

@ -0,0 +1,4 @@
# This file exists for backward compatibility with old code that refers to
# Crypto.Hash.SHA
from Crypto.Hash.SHA1 import __doc__, new, block_size, digest_size

View File

@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import *
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_sha1_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA1",
"""
#define SHA1_DIGEST_SIZE 20
int SHA1_init(void **shaState);
int SHA1_destroy(void *shaState);
int SHA1_update(void *hs,
const uint8_t *buf,
size_t len);
int SHA1_digest(const void *shaState,
uint8_t digest[SHA1_DIGEST_SIZE]);
int SHA1_copy(const void *src, void *dst);
int SHA1_pbkdf2_hmac_assist(const void *inner,
const void *outer,
const uint8_t first_digest[SHA1_DIGEST_SIZE],
uint8_t final_digest[SHA1_DIGEST_SIZE],
size_t iterations);
""")
class SHA1Hash(object):
"""A SHA-1 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 20
# The internal block size of the hash algorithm in bytes.
block_size = 64
# ASN.1 Object ID
oid = "1.3.14.3.2.26"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_sha1_lib.SHA1_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating SHA1"
% result)
self._state = SmartPointer(state.get(),
_raw_sha1_lib.SHA1_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_sha1_lib.SHA1_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while instantiating SHA1"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_sha1_lib.SHA1_digest(self._state.get(),
bfr)
if result:
raise ValueError("Error %d while instantiating SHA1"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = SHA1Hash()
result = _raw_sha1_lib.SHA1_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA1" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA-1 hash object."""
return SHA1Hash(data)
def new(data=None):
"""Create a new hash object.
:parameter data:
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`SHA1Hash.update`.
:type data: byte string/byte array/memoryview
:Return: A :class:`SHA1Hash` hash object
"""
return SHA1Hash().new(data)
# The size of the resulting hash in bytes.
digest_size = SHA1Hash.digest_size
# The internal block size of the hash algorithm in bytes.
block_size = SHA1Hash.block_size
def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations):
"""Compute the expensive inner loop in PBKDF-HMAC."""
assert len(first_digest) == digest_size
assert iterations > 0
bfr = create_string_buffer(digest_size);
result = _raw_sha1_lib.SHA1_pbkdf2_hmac_assist(
inner._state.get(),
outer._state.get(),
first_digest,
bfr,
c_size_t(iterations))
if result:
raise ValueError("Error %d with PBKDF2-HMAC assis for SHA1" % result)
return get_raw_buffer(bfr)

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA1Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer] = ...) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA1Hash: ...
def new(self, data: Optional[Buffer] = ...) -> SHA1Hash: ...
def new(data: Optional[Buffer] = ...) -> SHA1Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,186 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_sha224_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA224",
"""
int SHA224_init(void **shaState);
int SHA224_destroy(void *shaState);
int SHA224_update(void *hs,
const uint8_t *buf,
size_t len);
int SHA224_digest(const void *shaState,
uint8_t *digest,
size_t digest_size);
int SHA224_copy(const void *src, void *dst);
int SHA224_pbkdf2_hmac_assist(const void *inner,
const void *outer,
const uint8_t *first_digest,
uint8_t *final_digest,
size_t iterations,
size_t digest_size);
""")
class SHA224Hash(object):
"""A SHA-224 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 28
# The internal block size of the hash algorithm in bytes.
block_size = 64
# ASN.1 Object ID
oid = '2.16.840.1.101.3.4.2.4'
def __init__(self, data=None):
state = VoidPointer()
result = _raw_sha224_lib.SHA224_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating SHA224"
% result)
self._state = SmartPointer(state.get(),
_raw_sha224_lib.SHA224_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_sha224_lib.SHA224_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while hashing data with SHA224"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_sha224_lib.SHA224_digest(self._state.get(),
bfr,
c_size_t(self.digest_size))
if result:
raise ValueError("Error %d while making SHA224 digest"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = SHA224Hash()
result = _raw_sha224_lib.SHA224_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA224" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA-224 hash object."""
return SHA224Hash(data)
def new(data=None):
"""Create a new hash object.
:parameter data:
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`SHA224Hash.update`.
:type data: byte string/byte array/memoryview
:Return: A :class:`SHA224Hash` hash object
"""
return SHA224Hash().new(data)
# The size of the resulting hash in bytes.
digest_size = SHA224Hash.digest_size
# The internal block size of the hash algorithm in bytes.
block_size = SHA224Hash.block_size
def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations):
"""Compute the expensive inner loop in PBKDF-HMAC."""
assert iterations > 0
bfr = create_string_buffer(len(first_digest));
result = _raw_sha224_lib.SHA224_pbkdf2_hmac_assist(
inner._state.get(),
outer._state.get(),
first_digest,
bfr,
c_size_t(iterations),
c_size_t(len(first_digest)))
if result:
raise ValueError("Error %d with PBKDF2-HMAC assist for SHA224" % result)
return get_raw_buffer(bfr)

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA224Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer] = ...) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA224Hash: ...
def new(self, data: Optional[Buffer] = ...) -> SHA224Hash: ...
def new(data: Optional[Buffer] = ...) -> SHA224Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_sha256_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA256",
"""
int SHA256_init(void **shaState);
int SHA256_destroy(void *shaState);
int SHA256_update(void *hs,
const uint8_t *buf,
size_t len);
int SHA256_digest(const void *shaState,
uint8_t *digest,
size_t digest_size);
int SHA256_copy(const void *src, void *dst);
int SHA256_pbkdf2_hmac_assist(const void *inner,
const void *outer,
const uint8_t *first_digest,
uint8_t *final_digest,
size_t iterations,
size_t digest_size);
""")
class SHA256Hash(object):
"""A SHA-256 hash object.
Do not instantiate directly. Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 32
# The internal block size of the hash algorithm in bytes.
block_size = 64
# ASN.1 Object ID
oid = "2.16.840.1.101.3.4.2.1"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_sha256_lib.SHA256_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating SHA256"
% result)
self._state = SmartPointer(state.get(),
_raw_sha256_lib.SHA256_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_sha256_lib.SHA256_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while hashing data with SHA256"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_sha256_lib.SHA256_digest(self._state.get(),
bfr,
c_size_t(self.digest_size))
if result:
raise ValueError("Error %d while making SHA256 digest"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = SHA256Hash()
result = _raw_sha256_lib.SHA256_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA256" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA-256 hash object."""
return SHA256Hash(data)
def new(data=None):
"""Create a new hash object.
:parameter data:
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`SHA256Hash.update`.
:type data: byte string/byte array/memoryview
:Return: A :class:`SHA256Hash` hash object
"""
return SHA256Hash().new(data)
# The size of the resulting hash in bytes.
digest_size = SHA256Hash.digest_size
# The internal block size of the hash algorithm in bytes.
block_size = SHA256Hash.block_size
def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations):
"""Compute the expensive inner loop in PBKDF-HMAC."""
assert iterations > 0
bfr = create_string_buffer(len(first_digest));
result = _raw_sha256_lib.SHA256_pbkdf2_hmac_assist(
inner._state.get(),
outer._state.get(),
first_digest,
bfr,
c_size_t(iterations),
c_size_t(len(first_digest)))
if result:
raise ValueError("Error %d with PBKDF2-HMAC assist for SHA256" % result)
return get_raw_buffer(bfr)

View File

@ -0,0 +1,18 @@
from typing import Union, Optional
class SHA256Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> None: ...
def update(self, data: Union[bytes, bytearray, memoryview]) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA256Hash: ...
def new(self, data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ...
def new(data: Optional[Union[bytes, bytearray, memoryview]]=None) -> SHA256Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,186 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_sha384_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA384",
"""
int SHA384_init(void **shaState);
int SHA384_destroy(void *shaState);
int SHA384_update(void *hs,
const uint8_t *buf,
size_t len);
int SHA384_digest(const void *shaState,
uint8_t *digest,
size_t digest_size);
int SHA384_copy(const void *src, void *dst);
int SHA384_pbkdf2_hmac_assist(const void *inner,
const void *outer,
const uint8_t *first_digest,
uint8_t *final_digest,
size_t iterations,
size_t digest_size);
""")
class SHA384Hash(object):
"""A SHA-384 hash object.
Do not instantiate directly. Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 48
# The internal block size of the hash algorithm in bytes.
block_size = 128
# ASN.1 Object ID
oid = '2.16.840.1.101.3.4.2.2'
def __init__(self, data=None):
state = VoidPointer()
result = _raw_sha384_lib.SHA384_init(state.address_of())
if result:
raise ValueError("Error %d while instantiating SHA384"
% result)
self._state = SmartPointer(state.get(),
_raw_sha384_lib.SHA384_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_sha384_lib.SHA384_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while hashing data with SHA384"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_sha384_lib.SHA384_digest(self._state.get(),
bfr,
c_size_t(self.digest_size))
if result:
raise ValueError("Error %d while making SHA384 digest"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = SHA384Hash()
result = _raw_sha384_lib.SHA384_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA384" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA-384 hash object."""
return SHA384Hash(data)
def new(data=None):
"""Create a new hash object.
:parameter data:
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`SHA384Hash.update`.
:type data: byte string/byte array/memoryview
:Return: A :class:`SHA384Hash` hash object
"""
return SHA384Hash().new(data)
# The size of the resulting hash in bytes.
digest_size = SHA384Hash.digest_size
# The internal block size of the hash algorithm in bytes.
block_size = SHA384Hash.block_size
def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations):
"""Compute the expensive inner loop in PBKDF-HMAC."""
assert iterations > 0
bfr = create_string_buffer(len(first_digest));
result = _raw_sha384_lib.SHA384_pbkdf2_hmac_assist(
inner._state.get(),
outer._state.get(),
first_digest,
bfr,
c_size_t(iterations),
c_size_t(len(first_digest)))
if result:
raise ValueError("Error %d with PBKDF2-HMAC assist for SHA384" % result)
return get_raw_buffer(bfr)

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA384Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer] = ...) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA384Hash: ...
def new(self, data: Optional[Buffer] = ...) -> SHA384Hash: ...
def new(data: Optional[Buffer] = ...) -> SHA384Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr, c_ubyte)
from Crypto.Hash.keccak import _raw_keccak_lib
class SHA3_224_Hash(object):
"""A SHA3-224 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 28
# ASN.1 Object ID
oid = "2.16.840.1.101.3.4.2.7"
# Input block size for HMAC
block_size = 144
def __init__(self, data, update_after_digest):
self._update_after_digest = update_after_digest
self._digest_done = False
self._padding = 0x06
state = VoidPointer()
result = _raw_keccak_lib.keccak_init(state.address_of(),
c_size_t(self.digest_size * 2),
c_ubyte(24))
if result:
raise ValueError("Error %d while instantiating SHA-3/224"
% result)
self._state = SmartPointer(state.get(),
_raw_keccak_lib.keccak_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._digest_done and not self._update_after_digest:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
result = _raw_keccak_lib.keccak_absorb(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data))
)
if result:
raise ValueError("Error %d while updating SHA-3/224"
% result)
return self
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
self._digest_done = True
bfr = create_string_buffer(self.digest_size)
result = _raw_keccak_lib.keccak_digest(self._state.get(),
bfr,
c_size_t(self.digest_size),
c_ubyte(self._padding))
if result:
raise ValueError("Error %d while instantiating SHA-3/224"
% result)
self._digest_value = get_raw_buffer(bfr)
return self._digest_value
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = self.new()
result = _raw_keccak_lib.keccak_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA3-224" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA3-224 hash object."""
return type(self)(data, self._update_after_digest)
def new(*args, **kwargs):
"""Create a new hash object.
Args:
data (byte string/byte array/memoryview):
The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
update_after_digest (boolean):
Whether :meth:`digest` can be followed by another :meth:`update`
(default: ``False``).
:Return: A :class:`SHA3_224_Hash` hash object
"""
data = kwargs.pop("data", None)
update_after_digest = kwargs.pop("update_after_digest", False)
if len(args) == 1:
if data:
raise ValueError("Initial data for hash specified twice")
data = args[0]
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return SHA3_224_Hash(data, update_after_digest)
# The size of the resulting hash in bytes.
digest_size = SHA3_224_Hash.digest_size
# Input block size for HMAC
block_size = 144

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA3_224_Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ...
def update(self, data: Buffer) -> SHA3_224_Hash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA3_224_Hash: ...
def new(self, data: Optional[Buffer]) -> SHA3_224_Hash: ...
def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_224_Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr, c_ubyte)
from Crypto.Hash.keccak import _raw_keccak_lib
class SHA3_256_Hash(object):
"""A SHA3-256 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 32
# ASN.1 Object ID
oid = "2.16.840.1.101.3.4.2.8"
# Input block size for HMAC
block_size = 136
def __init__(self, data, update_after_digest):
self._update_after_digest = update_after_digest
self._digest_done = False
self._padding = 0x06
state = VoidPointer()
result = _raw_keccak_lib.keccak_init(state.address_of(),
c_size_t(self.digest_size * 2),
c_ubyte(24))
if result:
raise ValueError("Error %d while instantiating SHA-3/256"
% result)
self._state = SmartPointer(state.get(),
_raw_keccak_lib.keccak_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._digest_done and not self._update_after_digest:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
result = _raw_keccak_lib.keccak_absorb(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data))
)
if result:
raise ValueError("Error %d while updating SHA-3/256"
% result)
return self
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
self._digest_done = True
bfr = create_string_buffer(self.digest_size)
result = _raw_keccak_lib.keccak_digest(self._state.get(),
bfr,
c_size_t(self.digest_size),
c_ubyte(self._padding))
if result:
raise ValueError("Error %d while instantiating SHA-3/256"
% result)
self._digest_value = get_raw_buffer(bfr)
return self._digest_value
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = self.new()
result = _raw_keccak_lib.keccak_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA3-256" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA3-256 hash object."""
return type(self)(data, self._update_after_digest)
def new(*args, **kwargs):
"""Create a new hash object.
Args:
data (byte string/byte array/memoryview):
The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
update_after_digest (boolean):
Whether :meth:`digest` can be followed by another :meth:`update`
(default: ``False``).
:Return: A :class:`SHA3_256_Hash` hash object
"""
data = kwargs.pop("data", None)
update_after_digest = kwargs.pop("update_after_digest", False)
if len(args) == 1:
if data:
raise ValueError("Initial data for hash specified twice")
data = args[0]
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return SHA3_256_Hash(data, update_after_digest)
# The size of the resulting hash in bytes.
digest_size = SHA3_256_Hash.digest_size
# Input block size for HMAC
block_size = 136

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA3_256_Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ...
def update(self, data: Buffer) -> SHA3_256_Hash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA3_256_Hash: ...
def new(self, data: Optional[Buffer]) -> SHA3_256_Hash: ...
def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_256_Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,179 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr, c_ubyte)
from Crypto.Hash.keccak import _raw_keccak_lib
class SHA3_384_Hash(object):
"""A SHA3-384 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 48
# ASN.1 Object ID
oid = "2.16.840.1.101.3.4.2.9"
# Input block size for HMAC
block_size = 104
def __init__(self, data, update_after_digest):
self._update_after_digest = update_after_digest
self._digest_done = False
self._padding = 0x06
state = VoidPointer()
result = _raw_keccak_lib.keccak_init(state.address_of(),
c_size_t(self.digest_size * 2),
c_ubyte(24))
if result:
raise ValueError("Error %d while instantiating SHA-3/384"
% result)
self._state = SmartPointer(state.get(),
_raw_keccak_lib.keccak_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._digest_done and not self._update_after_digest:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
result = _raw_keccak_lib.keccak_absorb(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while updating SHA-3/384"
% result)
return self
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
self._digest_done = True
bfr = create_string_buffer(self.digest_size)
result = _raw_keccak_lib.keccak_digest(self._state.get(),
bfr,
c_size_t(self.digest_size),
c_ubyte(self._padding))
if result:
raise ValueError("Error %d while instantiating SHA-3/384"
% result)
self._digest_value = get_raw_buffer(bfr)
return self._digest_value
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = self.new()
result = _raw_keccak_lib.keccak_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA3-384" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA3-256 hash object."""
return type(self)(data, self._update_after_digest)
def new(self, data=None):
"""Create a fresh SHA3-384 hash object."""
return type(self)(data, self._update_after_digest)
def new(*args, **kwargs):
"""Create a new hash object.
Args:
data (byte string/byte array/memoryview):
The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
update_after_digest (boolean):
Whether :meth:`digest` can be followed by another :meth:`update`
(default: ``False``).
:Return: A :class:`SHA3_384_Hash` hash object
"""
data = kwargs.pop("data", None)
update_after_digest = kwargs.pop("update_after_digest", False)
if len(args) == 1:
if data:
raise ValueError("Initial data for hash specified twice")
data = args[0]
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return SHA3_384_Hash(data, update_after_digest)
# The size of the resulting hash in bytes.
digest_size = SHA3_384_Hash.digest_size
# Input block size for HMAC
block_size = 104

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA3_384_Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ...
def update(self, data: Buffer) -> SHA3_384_Hash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA3_384_Hash: ...
def new(self, data: Optional[Buffer]) -> SHA3_384_Hash: ...
def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_384_Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,174 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr, c_ubyte)
from Crypto.Hash.keccak import _raw_keccak_lib
class SHA3_512_Hash(object):
"""A SHA3-512 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The size of the resulting hash in bytes.
digest_size = 64
# ASN.1 Object ID
oid = "2.16.840.1.101.3.4.2.10"
# Input block size for HMAC
block_size = 72
def __init__(self, data, update_after_digest):
self._update_after_digest = update_after_digest
self._digest_done = False
self._padding = 0x06
state = VoidPointer()
result = _raw_keccak_lib.keccak_init(state.address_of(),
c_size_t(self.digest_size * 2),
c_ubyte(24))
if result:
raise ValueError("Error %d while instantiating SHA-3/512"
% result)
self._state = SmartPointer(state.get(),
_raw_keccak_lib.keccak_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._digest_done and not self._update_after_digest:
raise TypeError("You can only call 'digest' or 'hexdigest' on this object")
result = _raw_keccak_lib.keccak_absorb(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while updating SHA-3/512"
% result)
return self
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
self._digest_done = True
bfr = create_string_buffer(self.digest_size)
result = _raw_keccak_lib.keccak_digest(self._state.get(),
bfr,
c_size_t(self.digest_size),
c_ubyte(self._padding))
if result:
raise ValueError("Error %d while instantiating SHA-3/512"
% result)
self._digest_value = get_raw_buffer(bfr)
return self._digest_value
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = self.new()
result = _raw_keccak_lib.keccak_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA3-512" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA3-521 hash object."""
return type(self)(data, self._update_after_digest)
def new(*args, **kwargs):
"""Create a new hash object.
Args:
data (byte string/byte array/memoryview):
The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
update_after_digest (boolean):
Whether :meth:`digest` can be followed by another :meth:`update`
(default: ``False``).
:Return: A :class:`SHA3_512_Hash` hash object
"""
data = kwargs.pop("data", None)
update_after_digest = kwargs.pop("update_after_digest", False)
if len(args) == 1:
if data:
raise ValueError("Initial data for hash specified twice")
data = args[0]
if kwargs:
raise TypeError("Unknown parameters: " + str(kwargs))
return SHA3_512_Hash(data, update_after_digest)
# The size of the resulting hash in bytes.
digest_size = SHA3_512_Hash.digest_size
# Input block size for HMAC
block_size = 72

View File

@ -0,0 +1,19 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA3_512_Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self, data: Optional[Buffer], update_after_digest: bool) -> None: ...
def update(self, data: Buffer) -> SHA3_512_Hash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA3_512_Hash: ...
def new(self, data: Optional[Buffer]) -> SHA3_512_Hash: ...
def new(__data: Buffer = ..., update_after_digest: bool = ...) -> SHA3_512_Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,204 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr)
_raw_sha512_lib = load_pycryptodome_raw_lib("Crypto.Hash._SHA512",
"""
int SHA512_init(void **shaState,
size_t digest_size);
int SHA512_destroy(void *shaState);
int SHA512_update(void *hs,
const uint8_t *buf,
size_t len);
int SHA512_digest(const void *shaState,
uint8_t *digest,
size_t digest_size);
int SHA512_copy(const void *src, void *dst);
int SHA512_pbkdf2_hmac_assist(const void *inner,
const void *outer,
const uint8_t *first_digest,
uint8_t *final_digest,
size_t iterations,
size_t digest_size);
""")
class SHA512Hash(object):
"""A SHA-512 hash object (possibly in its truncated version SHA-512/224 or
SHA-512/256.
Do not instantiate directly. Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
:ivar block_size: the size in bytes of the internal message block,
input to the compression function
:vartype block_size: integer
:ivar digest_size: the size in bytes of the resulting hash
:vartype digest_size: integer
"""
# The internal block size of the hash algorithm in bytes.
block_size = 128
def __init__(self, data, truncate):
self._truncate = truncate
if truncate is None:
self.oid = "2.16.840.1.101.3.4.2.3"
self.digest_size = 64
elif truncate == "224":
self.oid = "2.16.840.1.101.3.4.2.5"
self.digest_size = 28
elif truncate == "256":
self.oid = "2.16.840.1.101.3.4.2.6"
self.digest_size = 32
else:
raise ValueError("Incorrect truncation length. It must be '224' or '256'.")
state = VoidPointer()
result = _raw_sha512_lib.SHA512_init(state.address_of(),
c_size_t(self.digest_size))
if result:
raise ValueError("Error %d while instantiating SHA-512"
% result)
self._state = SmartPointer(state.get(),
_raw_sha512_lib.SHA512_destroy)
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
result = _raw_sha512_lib.SHA512_update(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while hashing data with SHA512"
% result)
def digest(self):
"""Return the **binary** (non-printable) digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Binary form.
:rtype: byte string
"""
bfr = create_string_buffer(self.digest_size)
result = _raw_sha512_lib.SHA512_digest(self._state.get(),
bfr,
c_size_t(self.digest_size))
if result:
raise ValueError("Error %d while making SHA512 digest"
% result)
return get_raw_buffer(bfr)
def hexdigest(self):
"""Return the **printable** digest of the message that has been hashed so far.
:return: The hash digest, computed over the data processed so far.
Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in self.digest()])
def copy(self):
"""Return a copy ("clone") of the hash object.
The copy will have the same internal state as the original hash
object.
This can be used to efficiently compute the digests of strings that
share a common initial substring.
:return: A hash object of the same type
"""
clone = SHA512Hash(None, self._truncate)
result = _raw_sha512_lib.SHA512_copy(self._state.get(),
clone._state.get())
if result:
raise ValueError("Error %d while copying SHA512" % result)
return clone
def new(self, data=None):
"""Create a fresh SHA-512 hash object."""
return SHA512Hash(data, self._truncate)
def new(data=None, truncate=None):
"""Create a new hash object.
Args:
data (bytes/bytearray/memoryview):
Optional. The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`SHA512Hash.update`.
truncate (string):
Optional. The desired length of the digest. It can be either "224" or
"256". If not present, the digest is 512 bits long.
Passing this parameter is **not** equivalent to simply truncating
the output digest.
:Return: A :class:`SHA512Hash` hash object
"""
return SHA512Hash(data, truncate)
# The size of the full SHA-512 hash in bytes.
digest_size = 64
# The internal block size of the hash algorithm in bytes.
block_size = 128
def _pbkdf2_hmac_assist(inner, outer, first_digest, iterations):
"""Compute the expensive inner loop in PBKDF-HMAC."""
assert iterations > 0
bfr = create_string_buffer(len(first_digest));
result = _raw_sha512_lib.SHA512_pbkdf2_hmac_assist(
inner._state.get(),
outer._state.get(),
first_digest,
bfr,
c_size_t(iterations),
c_size_t(len(first_digest)))
if result:
raise ValueError("Error %d with PBKDF2-HMAC assist for SHA512" % result)
return get_raw_buffer(bfr)

View File

@ -0,0 +1,22 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHA512Hash(object):
digest_size: int
block_size: int
oid: str
def __init__(self,
data: Optional[Buffer],
truncate: Optional[str]) -> None: ...
def update(self, data: Buffer) -> None: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def copy(self) -> SHA512Hash: ...
def new(self, data: Optional[Buffer] = ...) -> SHA512Hash: ...
def new(data: Optional[Buffer] = ...,
truncate: Optional[str] = ...) -> SHA512Hash: ...
digest_size: int
block_size: int

View File

@ -0,0 +1,129 @@
# ===================================================================
#
# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr, c_ubyte)
from Crypto.Hash.keccak import _raw_keccak_lib
class SHAKE128_XOF(object):
"""A SHAKE128 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
"""
# ASN.1 Object ID
oid = "2.16.840.1.101.3.4.2.11"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_keccak_lib.keccak_init(state.address_of(),
c_size_t(32),
c_ubyte(24))
if result:
raise ValueError("Error %d while instantiating SHAKE128"
% result)
self._state = SmartPointer(state.get(),
_raw_keccak_lib.keccak_destroy)
self._is_squeezing = False
self._padding = 0x1F
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._is_squeezing:
raise TypeError("You cannot call 'update' after the first 'read'")
result = _raw_keccak_lib.keccak_absorb(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while updating SHAKE128 state"
% result)
return self
def read(self, length):
"""
Compute the next piece of XOF output.
.. note::
You cannot use :meth:`update` anymore after the first call to
:meth:`read`.
Args:
length (integer): the amount of bytes this method must return
:return: the next piece of XOF output (of the given length)
:rtype: byte string
"""
self._is_squeezing = True
bfr = create_string_buffer(length)
result = _raw_keccak_lib.keccak_squeeze(self._state.get(),
bfr,
c_size_t(length),
c_ubyte(self._padding))
if result:
raise ValueError("Error %d while extracting from SHAKE128"
% result)
return get_raw_buffer(bfr)
def new(self, data=None):
return type(self)(data=data)
def new(data=None):
"""Return a fresh instance of a SHAKE128 object.
Args:
data (bytes/bytearray/memoryview):
The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
Optional.
:Return: A :class:`SHAKE128_XOF` object
"""
return SHAKE128_XOF(data=data)

View File

@ -0,0 +1,13 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHAKE128_XOF(object):
oid: str
def __init__(self,
data: Optional[Buffer] = ...) -> None: ...
def update(self, data: Buffer) -> SHAKE128_XOF: ...
def read(self, length: int) -> bytes: ...
def new(self, data: Optional[Buffer] = ...) -> SHAKE128_XOF: ...
def new(data: Optional[Buffer] = ...) -> SHAKE128_XOF: ...

View File

@ -0,0 +1,130 @@
# ===================================================================
#
# Copyright (c) 2015, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.py3compat import bord
from Crypto.Util._raw_api import (load_pycryptodome_raw_lib,
VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr, c_ubyte)
from Crypto.Hash.keccak import _raw_keccak_lib
class SHAKE256_XOF(object):
"""A SHAKE256 hash object.
Do not instantiate directly.
Use the :func:`new` function.
:ivar oid: ASN.1 Object ID
:vartype oid: string
"""
# ASN.1 Object ID
oid = "2.16.840.1.101.3.4.2.12"
def __init__(self, data=None):
state = VoidPointer()
result = _raw_keccak_lib.keccak_init(state.address_of(),
c_size_t(64),
c_ubyte(24))
if result:
raise ValueError("Error %d while instantiating SHAKE256"
% result)
self._state = SmartPointer(state.get(),
_raw_keccak_lib.keccak_destroy)
self._is_squeezing = False
self._padding = 0x1F
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._is_squeezing:
raise TypeError("You cannot call 'update' after the first 'read'")
result = _raw_keccak_lib.keccak_absorb(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while updating SHAKE256 state"
% result)
return self
def read(self, length):
"""
Compute the next piece of XOF output.
.. note::
You cannot use :meth:`update` anymore after the first call to
:meth:`read`.
Args:
length (integer): the amount of bytes this method must return
:return: the next piece of XOF output (of the given length)
:rtype: byte string
"""
self._is_squeezing = True
bfr = create_string_buffer(length)
result = _raw_keccak_lib.keccak_squeeze(self._state.get(),
bfr,
c_size_t(length),
c_ubyte(self._padding))
if result:
raise ValueError("Error %d while extracting from SHAKE256"
% result)
return get_raw_buffer(bfr)
def new(self, data=None):
return type(self)(data=data)
def new(data=None):
"""Return a fresh instance of a SHAKE256 object.
Args:
data (bytes/bytearray/memoryview):
The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
Optional.
:Return: A :class:`SHAKE256_XOF` object
"""
return SHAKE256_XOF(data=data)

View File

@ -0,0 +1,13 @@
from typing import Union, Optional
Buffer = Union[bytes, bytearray, memoryview]
class SHAKE256_XOF(object):
oid: str
def __init__(self,
data: Optional[Buffer] = ...) -> None: ...
def update(self, data: Buffer) -> SHAKE256_XOF: ...
def read(self, length: int) -> bytes: ...
def new(self, data: Optional[Buffer] = ...) -> SHAKE256_XOF: ...
def new(data: Optional[Buffer] = ...) -> SHAKE256_XOF: ...

View File

@ -0,0 +1,136 @@
# ===================================================================
#
# Copyright (c) 2021, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from Crypto.Util.py3compat import bord, is_bytes, tobytes
from . import cSHAKE128
from .cSHAKE128 import _encode_str, _right_encode
class TupleHash(object):
"""A Tuple hash object.
Do not instantiate directly.
Use the :func:`new` function.
"""
def __init__(self, custom, cshake, digest_size):
self.digest_size = digest_size
self._cshake = cshake._new(b'', custom, b'TupleHash')
self._digest = None
def update(self, *data):
"""Authenticate the next tuple of byte strings.
TupleHash guarantees the logical separation between each byte string.
Args:
data (bytes/bytearray/memoryview): One or more items to hash.
"""
if self._digest is not None:
raise TypeError("You cannot call 'update' after 'digest' or 'hexdigest'")
for item in data:
if not is_bytes(item):
raise TypeError("You can only call 'update' on bytes" )
self._cshake.update(_encode_str(item))
return self
def digest(self):
"""Return the **binary** (non-printable) digest of the tuple of byte strings.
:return: The hash digest. Binary form.
:rtype: byte string
"""
if self._digest is None:
self._cshake.update(_right_encode(self.digest_size * 8))
self._digest = self._cshake.read(self.digest_size)
return self._digest
def hexdigest(self):
"""Return the **printable** digest of the tuple of byte strings.
:return: The hash digest. Hexadecimal encoded.
:rtype: string
"""
return "".join(["%02x" % bord(x) for x in tuple(self.digest())])
def new(self, **kwargs):
"""Return a new instance of a TupleHash object.
See :func:`new`.
"""
if "digest_bytes" not in kwargs and "digest_bits" not in kwargs:
kwargs["digest_bytes"] = self.digest_size
return new(**kwargs)
def new(**kwargs):
"""Create a new TupleHash128 object.
Args:
digest_bytes (integer):
Optional. The size of the digest, in bytes.
Default is 64. Minimum is 8.
digest_bits (integer):
Optional and alternative to ``digest_bytes``.
The size of the digest, in bits (and in steps of 8).
Default is 512. Minimum is 64.
custom (bytes):
Optional.
A customization bytestring (``S`` in SP 800-185).
:Return: A :class:`TupleHash` object
"""
digest_bytes = kwargs.pop("digest_bytes", None)
digest_bits = kwargs.pop("digest_bits", None)
if None not in (digest_bytes, digest_bits):
raise TypeError("Only one digest parameter must be provided")
if (None, None) == (digest_bytes, digest_bits):
digest_bytes = 64
if digest_bytes is not None:
if digest_bytes < 8:
raise ValueError("'digest_bytes' must be at least 8")
else:
if digest_bits < 64 or digest_bits % 8:
raise ValueError("'digest_bytes' must be at least 64 "
"in steps of 8")
digest_bytes = digest_bits // 8
custom = kwargs.pop("custom", b'')
return TupleHash(custom, cSHAKE128, digest_bytes)

View File

@ -0,0 +1,22 @@
from typing import Any, Union, List, Tuple
from types import ModuleType
Buffer = Union[bytes, bytearray, memoryview]
class TupleHash(object):
digest_size: int
def __init__(self,
custom: bytes,
cshake: ModuleType,
digest_size: int) -> None: ...
def update(self, *data: Buffer) -> TupleHash: ...
def digest(self) -> bytes: ...
def hexdigest(self) -> str: ...
def new(self,
digest_bytes: int = ...,
digest_bits: int = ...,
custom: int = ...) -> TupleHash: ...
def new(digest_bytes: int = ...,
digest_bits: int = ...,
custom: int = ...) -> TupleHash: ...

View File

@ -0,0 +1,70 @@
# ===================================================================
#
# Copyright (c) 2021, Legrandin <helderijs@gmail.com>
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ===================================================================
from . import cSHAKE256
from .TupleHash128 import TupleHash
def new(**kwargs):
"""Create a new TupleHash256 object.
Args:
digest_bytes (integer):
Optional. The size of the digest, in bytes.
Default is 64. Minimum is 8.
digest_bits (integer):
Optional and alternative to ``digest_bytes``.
The size of the digest, in bits (and in steps of 8).
Default is 512. Minimum is 64.
custom (bytes):
Optional.
A customization bytestring (``S`` in SP 800-185).
:Return: A :class:`TupleHash` object
"""
digest_bytes = kwargs.pop("digest_bytes", None)
digest_bits = kwargs.pop("digest_bits", None)
if None not in (digest_bytes, digest_bits):
raise TypeError("Only one digest parameter must be provided")
if (None, None) == (digest_bytes, digest_bits):
digest_bytes = 64
if digest_bytes is not None:
if digest_bytes < 8:
raise ValueError("'digest_bytes' must be at least 8")
else:
if digest_bits < 64 or digest_bits % 8:
raise ValueError("'digest_bytes' must be at least 64 "
"in steps of 8")
digest_bytes = digest_bits // 8
custom = kwargs.pop("custom", b'')
return TupleHash(custom, cSHAKE256, digest_bytes)

View File

@ -0,0 +1,5 @@
from .TupleHash128 import TupleHash
def new(digest_bytes: int = ...,
digest_bits: int = ...,
custom: int = ...) -> TupleHash: ...

View File

@ -0,0 +1,112 @@
from Crypto.Util._raw_api import (VoidPointer, SmartPointer,
create_string_buffer,
get_raw_buffer, c_size_t,
c_uint8_ptr, c_ubyte)
from Crypto.Util.number import long_to_bytes
from Crypto.Util.py3compat import bchr
from .keccak import _raw_keccak_lib
class TurboSHAKE(object):
"""A TurboSHAKE hash object.
Do not instantiate directly.
Use the :func:`new` function.
"""
def __init__(self, capacity, domain_separation, data):
state = VoidPointer()
result = _raw_keccak_lib.keccak_init(state.address_of(),
c_size_t(capacity),
c_ubyte(12)) # Reduced number of rounds
if result:
raise ValueError("Error %d while instantiating TurboSHAKE"
% result)
self._state = SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy)
self._is_squeezing = False
self._capacity = capacity
self._domain = domain_separation
if data:
self.update(data)
def update(self, data):
"""Continue hashing of a message by consuming the next chunk of data.
Args:
data (byte string/byte array/memoryview): The next chunk of the message being hashed.
"""
if self._is_squeezing:
raise TypeError("You cannot call 'update' after the first 'read'")
result = _raw_keccak_lib.keccak_absorb(self._state.get(),
c_uint8_ptr(data),
c_size_t(len(data)))
if result:
raise ValueError("Error %d while updating TurboSHAKE state"
% result)
return self
def read(self, length):
"""
Compute the next piece of XOF output.
.. note::
You cannot use :meth:`update` anymore after the first call to
:meth:`read`.
Args:
length (integer): the amount of bytes this method must return
:return: the next piece of XOF output (of the given length)
:rtype: byte string
"""
self._is_squeezing = True
bfr = create_string_buffer(length)
result = _raw_keccak_lib.keccak_squeeze(self._state.get(),
bfr,
c_size_t(length),
c_ubyte(self._domain))
if result:
raise ValueError("Error %d while extracting from TurboSHAKE"
% result)
return get_raw_buffer(bfr)
def new(self, data=None):
return type(self)(self._capacity, self._domain, data)
def _reset(self):
result = _raw_keccak_lib.keccak_reset(self._state.get())
if result:
raise ValueError("Error %d while resetting TurboSHAKE state"
% result)
self._is_squeezing = False
def new(**kwargs):
"""Create a new TurboSHAKE128 object.
Args:
domain (integer):
Optional - A domain separation byte, between 0x01 and 0x7F.
The default value is 0x1F.
data (bytes/bytearray/memoryview):
Optional - The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
:Return: A :class:`TurboSHAKE` object
"""
domain_separation = kwargs.get('domain', 0x1F)
if not (0x01 <= domain_separation <= 0x7F):
raise ValueError("Incorrect domain separation value (%d)" %
domain_separation)
data = kwargs.get('data')
return TurboSHAKE(32, domain_separation, data=data)

View File

@ -0,0 +1,17 @@
from typing import Union, Optional
from typing_extensions import TypedDict, Unpack, NotRequired
Buffer = Union[bytes, bytearray, memoryview]
class TurboSHAKE(object):
def __init__(self, capacity: int, domain_separation: int, data: Union[Buffer, None]) -> None: ...
def update(self, data: Buffer) -> TurboSHAKE : ...
def read(self, length: int) -> bytes: ...
def new(self, data: Optional[Buffer]=None) -> TurboSHAKE: ...
class Args(TypedDict):
domain: NotRequired[int]
data: NotRequired[Buffer]
def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ...

View File

@ -0,0 +1,22 @@
from .TurboSHAKE128 import TurboSHAKE
def new(**kwargs):
"""Create a new TurboSHAKE256 object.
Args:
domain (integer):
Optional - A domain separation byte, between 0x01 and 0x7F.
The default value is 0x1F.
data (bytes/bytearray/memoryview):
Optional - The very first chunk of the message to hash.
It is equivalent to an early call to :meth:`update`.
:Return: A :class:`TurboSHAKE` object
"""
domain_separation = kwargs.get('domain', 0x1F)
if not (0x01 <= domain_separation <= 0x7F):
raise ValueError("Incorrect domain separation value (%d)" %
domain_separation)
data = kwargs.get('data')
return TurboSHAKE(64, domain_separation, data=data)

View File

@ -0,0 +1,12 @@
from typing import Union
from typing_extensions import TypedDict, Unpack, NotRequired
from .TurboSHAKE128 import TurboSHAKE
Buffer = Union[bytes, bytearray, memoryview]
class Args(TypedDict):
domain: NotRequired[int]
data: NotRequired[Buffer]
def new(**kwargs: Unpack[Args]) -> TurboSHAKE: ...

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
#
# ===================================================================
# The contents of this file are dedicated to the public domain. To
# the extent that dedication to the public domain is not available,
# everyone is granted a worldwide, perpetual, royalty-free,
# non-exclusive license to exercise all rights associated with the
# contents of this file for any purpose whatsoever.
# No rights are reserved.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# ===================================================================
__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1',
'SHA224', 'SHA256', 'SHA384', 'SHA512',
'SHA3_224', 'SHA3_256', 'SHA3_384', 'SHA3_512',
'CMAC', 'Poly1305',
'cSHAKE128', 'cSHAKE256', 'KMAC128', 'KMAC256',
'TupleHash128', 'TupleHash256', 'KangarooTwelve',
'TurboSHAKE128', 'TurboSHAKE256']
def new(name):
"""Return a new hash instance, based on its name or
on its ASN.1 Object ID"""
name = name.upper()
if name in ("1.3.14.3.2.26", "SHA1", "SHA-1"):
from . import SHA1
return SHA1.new()
if name in ("2.16.840.1.101.3.4.2.4", "SHA224", "SHA-224"):
from . import SHA224
return SHA224.new()
if name in ("2.16.840.1.101.3.4.2.1", "SHA256", "SHA-256"):
from . import SHA256
return SHA256.new()
if name in ("2.16.840.1.101.3.4.2.2", "SHA384", "SHA-384"):
from . import SHA384
return SHA384.new()
if name in ("2.16.840.1.101.3.4.2.3", "SHA512", "SHA-512"):
from . import SHA512
return SHA512.new()
if name in ("2.16.840.1.101.3.4.2.5", "SHA512-224", "SHA-512-224"):
from . import SHA512
return SHA512.new(truncate='224')
if name in ("2.16.840.1.101.3.4.2.6", "SHA512-256", "SHA-512-256"):
from . import SHA512
return SHA512.new(truncate='256')
if name in ("2.16.840.1.101.3.4.2.7", "SHA3-224", "SHA-3-224"):
from . import SHA3_224
return SHA3_224.new()
if name in ("2.16.840.1.101.3.4.2.8", "SHA3-256", "SHA-3-256"):
from . import SHA3_256
return SHA3_256.new()
if name in ("2.16.840.1.101.3.4.2.9", "SHA3-384", "SHA-3-384"):
from . import SHA3_384
return SHA3_384.new()
if name in ("2.16.840.1.101.3.4.2.10", "SHA3-512", "SHA-3-512"):
from . import SHA3_512
return SHA3_512.new()
else:
raise ValueError("Unknown hash %s" % str(name))

View File

@ -0,0 +1,57 @@
from typing import overload
from typing_extensions import Literal
from Crypto.Hash.SHA1 import SHA1Hash
from Crypto.Hash.SHA224 import SHA224Hash
from Crypto.Hash.SHA256 import SHA256Hash
from Crypto.Hash.SHA384 import SHA384Hash
from Crypto.Hash.SHA512 import SHA512Hash
from Crypto.Hash.SHA3_224 import SHA3_224_Hash
from Crypto.Hash.SHA3_256 import SHA3_256_Hash
from Crypto.Hash.SHA3_384 import SHA3_384_Hash
from Crypto.Hash.SHA3_512 import SHA3_512_Hash
@overload
def new(name: Literal["1.3.14.3.2.26"]) -> SHA1Hash: ...
@overload
def new(name: Literal["SHA1"]) -> SHA1Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.4"]) -> SHA224Hash: ...
@overload
def new(name: Literal["SHA224"]) -> SHA224Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.1"]) -> SHA256Hash: ...
@overload
def new(name: Literal["SHA256"]) -> SHA256Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.2"]) -> SHA384Hash: ...
@overload
def new(name: Literal["SHA384"]) -> SHA384Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.3"]) -> SHA512Hash: ...
@overload
def new(name: Literal["SHA512"]) -> SHA512Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.5"]) -> SHA512Hash: ...
@overload
def new(name: Literal["SHA512-224"]) -> SHA512Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.6"]) -> SHA512Hash: ...
@overload
def new(name: Literal["SHA512-256"]) -> SHA512Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.7"]) -> SHA3_224_Hash: ...
@overload
def new(name: Literal["SHA3-224"]) -> SHA3_224_Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.8"]) -> SHA3_256_Hash: ...
@overload
def new(name: Literal["SHA3-256"]) -> SHA3_256_Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.9"]) -> SHA3_384_Hash: ...
@overload
def new(name: Literal["SHA3-384"]) -> SHA3_384_Hash: ...
@overload
def new(name: Literal["2.16.840.1.101.3.4.2.10"]) -> SHA3_512_Hash: ...
@overload
def new(name: Literal["SHA3-512"]) -> SHA3_512_Hash: ...

Some files were not shown because too many files have changed in this diff Show More