first add files
This commit is contained in:
247
lib/Crypto/Hash/BLAKE2b.py
Normal file
247
lib/Crypto/Hash/BLAKE2b.py
Normal 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_bytes' 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("BLAKE2s key cannot exceed 64 bytes")
|
||||
|
||||
if kwargs:
|
||||
raise TypeError("Unknown parameters: " + str(kwargs))
|
||||
|
||||
return BLAKE2b_Hash(data, key, digest_bytes, update_after_digest)
|
||||
32
lib/Crypto/Hash/BLAKE2b.pyi
Normal file
32
lib/Crypto/Hash/BLAKE2b.pyi
Normal 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: ...
|
||||
247
lib/Crypto/Hash/BLAKE2s.py
Normal file
247
lib/Crypto/Hash/BLAKE2s.py
Normal 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_bytes' 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)
|
||||
26
lib/Crypto/Hash/BLAKE2s.pyi
Normal file
26
lib/Crypto/Hash/BLAKE2s.pyi
Normal 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: ...
|
||||
302
lib/Crypto/Hash/CMAC.py
Normal file
302
lib/Crypto/Hash/CMAC.py
Normal file
@@ -0,0 +1,302 @@
|
||||
# -*- 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):
|
||||
"""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
|
||||
"""
|
||||
|
||||
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)
|
||||
30
lib/Crypto/Hash/CMAC.pyi
Normal file
30
lib/Crypto/Hash/CMAC.pyi
Normal 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: ...
|
||||
213
lib/Crypto/Hash/HMAC.py
Normal file
213
lib/Crypto/Hash/HMAC.py
Normal file
@@ -0,0 +1,213 @@
|
||||
#
|
||||
# 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 MD5
|
||||
from Crypto.Hash import BLAKE2s
|
||||
from Crypto.Util.strxor import strxor
|
||||
from Crypto.Random import get_random_bytes
|
||||
|
||||
__all__ = ['new', 'HMAC']
|
||||
|
||||
|
||||
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
|
||||
"""
|
||||
|
||||
def __init__(self, key, msg=b"", digestmod=None):
|
||||
|
||||
if digestmod is None:
|
||||
digestmod = MD5
|
||||
|
||||
if msg is None:
|
||||
msg = b""
|
||||
|
||||
# Size of the MAC tag
|
||||
self.digest_size = digestmod.digest_size
|
||||
|
||||
self._digestmod = digestmod
|
||||
|
||||
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)
|
||||
25
lib/Crypto/Hash/HMAC.pyi
Normal file
25
lib/Crypto/Hash/HMAC.pyi
Normal 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: ...
|
||||
179
lib/Crypto/Hash/KMAC128.py
Normal file
179
lib/Crypto/Hash/KMAC128.py
Normal 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)
|
||||
33
lib/Crypto/Hash/KMAC128.pyi
Normal file
33
lib/Crypto/Hash/KMAC128.pyi
Normal 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: ...
|
||||
74
lib/Crypto/Hash/KMAC256.py
Normal file
74
lib/Crypto/Hash/KMAC256.py
Normal 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)
|
||||
10
lib/Crypto/Hash/KMAC256.pyi
Normal file
10
lib/Crypto/Hash/KMAC256.pyi
Normal 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: ...
|
||||
262
lib/Crypto/Hash/KangarooTwelve.py
Normal file
262
lib/Crypto/Hash/KangarooTwelve.py
Normal file
@@ -0,0 +1,262 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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._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
|
||||
|
||||
|
||||
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
|
||||
self._hash1 = self._create_keccak()
|
||||
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 _create_keccak(self):
|
||||
state = VoidPointer()
|
||||
result = _raw_keccak_lib.keccak_init(state.address_of(),
|
||||
c_size_t(32), # 32 bytes of capacity (256 bits)
|
||||
c_ubyte(12)) # Reduced number of rounds
|
||||
if result:
|
||||
raise ValueError("Error %d while instantiating KangarooTwelve"
|
||||
% result)
|
||||
return SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy)
|
||||
|
||||
def _update(self, data, hash_obj):
|
||||
result = _raw_keccak_lib.keccak_absorb(hash_obj.get(),
|
||||
c_uint8_ptr(data),
|
||||
c_size_t(len(data)))
|
||||
if result:
|
||||
raise ValueError("Error %d while updating KangarooTwelve state"
|
||||
% result)
|
||||
|
||||
def _squeeze(self, hash_obj, length, padding):
|
||||
bfr = create_string_buffer(length)
|
||||
result = _raw_keccak_lib.keccak_squeeze(hash_obj.get(),
|
||||
bfr,
|
||||
c_size_t(length),
|
||||
c_ubyte(padding))
|
||||
if result:
|
||||
raise ValueError("Error %d while extracting from KangarooTwelve"
|
||||
% result)
|
||||
|
||||
return get_raw_buffer(bfr)
|
||||
|
||||
def _reset(self, hash_obj):
|
||||
result = _raw_keccak_lib.keccak_reset(hash_obj.get())
|
||||
if result:
|
||||
raise ValueError("Error %d while resetting KangarooTwelve state"
|
||||
% result)
|
||||
|
||||
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._update(data, self._hash1)
|
||||
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._update(data_mem[:dtc], self._hash1)
|
||||
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._update(divider, self._hash1)
|
||||
self._length1 += 8
|
||||
|
||||
self._hash2 = self._create_keccak()
|
||||
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._update(data_mem[index:new_index], self._hash2)
|
||||
self._length2 += new_index - index
|
||||
index = new_index
|
||||
|
||||
if self._length2 == 8192:
|
||||
cv_i = self._squeeze(self._hash2, 32, 0x0B)
|
||||
self._update(cv_i, self._hash1)
|
||||
self._length1 += 32
|
||||
self._reset(self._hash2)
|
||||
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._update(self._custom, self._hash1)
|
||||
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._squeeze(self._hash2, 32, 0x0B)
|
||||
self._update(cv_i, self._hash1)
|
||||
self._length1 += 32
|
||||
self._reset(self._hash2)
|
||||
self._length2 = 0
|
||||
self._ctr += 1
|
||||
|
||||
trailer = _length_encode(self._ctr - 1) + b'\xFF\xFF'
|
||||
self._update(trailer, self._hash1)
|
||||
|
||||
self._padding = 0x06
|
||||
self._state = SQUEEZING
|
||||
|
||||
return self._squeeze(self._hash1, length, self._padding)
|
||||
|
||||
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)
|
||||
16
lib/Crypto/Hash/KangarooTwelve.pyi
Normal file
16
lib/Crypto/Hash/KangarooTwelve.pyi
Normal 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: ...
|
||||
166
lib/Crypto/Hash/MD2.py
Normal file
166
lib/Crypto/Hash/MD2.py
Normal 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
|
||||
19
lib/Crypto/Hash/MD2.pyi
Normal file
19
lib/Crypto/Hash/MD2.pyi
Normal 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
|
||||
185
lib/Crypto/Hash/MD4.py
Normal file
185
lib/Crypto/Hash/MD4.py
Normal 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
|
||||
19
lib/Crypto/Hash/MD4.pyi
Normal file
19
lib/Crypto/Hash/MD4.pyi
Normal 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
|
||||
184
lib/Crypto/Hash/MD5.py
Normal file
184
lib/Crypto/Hash/MD5.py
Normal 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)
|
||||
19
lib/Crypto/Hash/MD5.pyi
Normal file
19
lib/Crypto/Hash/MD5.pyi
Normal 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
|
||||
217
lib/Crypto/Hash/Poly1305.py
Normal file
217
lib/Crypto/Hash/Poly1305.py
Normal 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
|
||||
24
lib/Crypto/Hash/Poly1305.pyi
Normal file
24
lib/Crypto/Hash/Poly1305.pyi
Normal 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: ...
|
||||
26
lib/Crypto/Hash/RIPEMD.py
Normal file
26
lib/Crypto/Hash/RIPEMD.py
Normal 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
|
||||
3
lib/Crypto/Hash/RIPEMD.pyi
Normal file
3
lib/Crypto/Hash/RIPEMD.pyi
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file exists for backward compatibility with old code that refers to
|
||||
# Crypto.Hash.SHA
|
||||
|
||||
169
lib/Crypto/Hash/RIPEMD160.py
Normal file
169
lib/Crypto/Hash/RIPEMD160.py
Normal 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
|
||||
19
lib/Crypto/Hash/RIPEMD160.pyi
Normal file
19
lib/Crypto/Hash/RIPEMD160.pyi
Normal 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
|
||||
24
lib/Crypto/Hash/SHA.py
Normal file
24
lib/Crypto/Hash/SHA.py
Normal 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
|
||||
4
lib/Crypto/Hash/SHA.pyi
Normal file
4
lib/Crypto/Hash/SHA.pyi
Normal 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
|
||||
185
lib/Crypto/Hash/SHA1.py
Normal file
185
lib/Crypto/Hash/SHA1.py
Normal 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)
|
||||
19
lib/Crypto/Hash/SHA1.pyi
Normal file
19
lib/Crypto/Hash/SHA1.pyi
Normal 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
|
||||
186
lib/Crypto/Hash/SHA224.py
Normal file
186
lib/Crypto/Hash/SHA224.py
Normal 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)
|
||||
19
lib/Crypto/Hash/SHA224.pyi
Normal file
19
lib/Crypto/Hash/SHA224.pyi
Normal 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
|
||||
185
lib/Crypto/Hash/SHA256.py
Normal file
185
lib/Crypto/Hash/SHA256.py
Normal 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)
|
||||
18
lib/Crypto/Hash/SHA256.pyi
Normal file
18
lib/Crypto/Hash/SHA256.pyi
Normal 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
|
||||
186
lib/Crypto/Hash/SHA384.py
Normal file
186
lib/Crypto/Hash/SHA384.py
Normal 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)
|
||||
19
lib/Crypto/Hash/SHA384.pyi
Normal file
19
lib/Crypto/Hash/SHA384.pyi
Normal 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
|
||||
174
lib/Crypto/Hash/SHA3_224.py
Normal file
174
lib/Crypto/Hash/SHA3_224.py
Normal 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
|
||||
19
lib/Crypto/Hash/SHA3_224.pyi
Normal file
19
lib/Crypto/Hash/SHA3_224.pyi
Normal 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
|
||||
174
lib/Crypto/Hash/SHA3_256.py
Normal file
174
lib/Crypto/Hash/SHA3_256.py
Normal 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
|
||||
19
lib/Crypto/Hash/SHA3_256.pyi
Normal file
19
lib/Crypto/Hash/SHA3_256.pyi
Normal 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
|
||||
179
lib/Crypto/Hash/SHA3_384.py
Normal file
179
lib/Crypto/Hash/SHA3_384.py
Normal 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
|
||||
19
lib/Crypto/Hash/SHA3_384.pyi
Normal file
19
lib/Crypto/Hash/SHA3_384.pyi
Normal 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
|
||||
174
lib/Crypto/Hash/SHA3_512.py
Normal file
174
lib/Crypto/Hash/SHA3_512.py
Normal 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
|
||||
19
lib/Crypto/Hash/SHA3_512.pyi
Normal file
19
lib/Crypto/Hash/SHA3_512.pyi
Normal 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
|
||||
204
lib/Crypto/Hash/SHA512.py
Normal file
204
lib/Crypto/Hash/SHA512.py
Normal 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)
|
||||
22
lib/Crypto/Hash/SHA512.pyi
Normal file
22
lib/Crypto/Hash/SHA512.pyi
Normal 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
|
||||
129
lib/Crypto/Hash/SHAKE128.py
Normal file
129
lib/Crypto/Hash/SHAKE128.py
Normal 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)
|
||||
13
lib/Crypto/Hash/SHAKE128.pyi
Normal file
13
lib/Crypto/Hash/SHAKE128.pyi
Normal 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: ...
|
||||
130
lib/Crypto/Hash/SHAKE256.py
Normal file
130
lib/Crypto/Hash/SHAKE256.py
Normal 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)
|
||||
13
lib/Crypto/Hash/SHAKE256.pyi
Normal file
13
lib/Crypto/Hash/SHAKE256.pyi
Normal 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: ...
|
||||
138
lib/Crypto/Hash/TupleHash128.py
Normal file
138
lib/Crypto/Hash/TupleHash128.py
Normal file
@@ -0,0 +1,138 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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 byte string in the tuple.
|
||||
|
||||
Args:
|
||||
data (bytes/bytearray/memoryview): The next byte string.
|
||||
"""
|
||||
|
||||
if self._digest is not None:
|
||||
raise TypeError("You cannot call 'update' after 'digest' or 'hexdigest'")
|
||||
|
||||
if not is_bytes(data):
|
||||
raise TypeError("You can only call 'update' on bytes")
|
||||
|
||||
self._cshake.update(_encode_str(tobytes(data)))
|
||||
|
||||
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'')
|
||||
|
||||
if kwargs:
|
||||
raise TypeError("Unknown parameters: " + str(kwargs))
|
||||
|
||||
return TupleHash(custom, cSHAKE128, digest_bytes)
|
||||
22
lib/Crypto/Hash/TupleHash128.pyi
Normal file
22
lib/Crypto/Hash/TupleHash128.pyi
Normal file
@@ -0,0 +1,22 @@
|
||||
from typing import Any, Union
|
||||
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: ...
|
||||
73
lib/Crypto/Hash/TupleHash256.py
Normal file
73
lib/Crypto/Hash/TupleHash256.py
Normal file
@@ -0,0 +1,73 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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'')
|
||||
|
||||
if kwargs:
|
||||
raise TypeError("Unknown parameters: " + str(kwargs))
|
||||
|
||||
return TupleHash(custom, cSHAKE256, digest_bytes)
|
||||
5
lib/Crypto/Hash/TupleHash256.pyi
Normal file
5
lib/Crypto/Hash/TupleHash256.pyi
Normal file
@@ -0,0 +1,5 @@
|
||||
from .TupleHash128 import TupleHash
|
||||
|
||||
def new(digest_bytes: int = ...,
|
||||
digest_bits: int = ...,
|
||||
custom: int = ...) -> TupleHash: ...
|
||||
BIN
lib/Crypto/Hash/_BLAKE2b.abi3.so
Executable file
BIN
lib/Crypto/Hash/_BLAKE2b.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_BLAKE2s.abi3.so
Executable file
BIN
lib/Crypto/Hash/_BLAKE2s.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_MD2.abi3.so
Executable file
BIN
lib/Crypto/Hash/_MD2.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_MD4.abi3.so
Executable file
BIN
lib/Crypto/Hash/_MD4.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_MD5.abi3.so
Executable file
BIN
lib/Crypto/Hash/_MD5.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_RIPEMD160.abi3.so
Executable file
BIN
lib/Crypto/Hash/_RIPEMD160.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_SHA1.abi3.so
Executable file
BIN
lib/Crypto/Hash/_SHA1.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_SHA224.abi3.so
Executable file
BIN
lib/Crypto/Hash/_SHA224.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_SHA256.abi3.so
Executable file
BIN
lib/Crypto/Hash/_SHA256.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_SHA384.abi3.so
Executable file
BIN
lib/Crypto/Hash/_SHA384.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_SHA512.abi3.so
Executable file
BIN
lib/Crypto/Hash/_SHA512.abi3.so
Executable file
Binary file not shown.
24
lib/Crypto/Hash/__init__.py
Normal file
24
lib/Crypto/Hash/__init__.py
Normal 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.
|
||||
# ===================================================================
|
||||
|
||||
__all__ = ['HMAC', 'MD2', 'MD4', 'MD5', 'RIPEMD160', 'SHA1',
|
||||
'SHA224', 'SHA256', 'SHA384', 'SHA512', 'CMAC', 'Poly1305',
|
||||
'cSHAKE128', 'cSHAKE256', 'KMAC128', 'KMAC256',
|
||||
'TupleHash128', 'TupleHash256', 'KangarooTwelve']
|
||||
0
lib/Crypto/Hash/__init__.pyi
Normal file
0
lib/Crypto/Hash/__init__.pyi
Normal file
BIN
lib/Crypto/Hash/_ghash_clmul.abi3.so
Executable file
BIN
lib/Crypto/Hash/_ghash_clmul.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_ghash_portable.abi3.so
Executable file
BIN
lib/Crypto/Hash/_ghash_portable.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_keccak.abi3.so
Executable file
BIN
lib/Crypto/Hash/_keccak.abi3.so
Executable file
Binary file not shown.
BIN
lib/Crypto/Hash/_poly1305.abi3.so
Executable file
BIN
lib/Crypto/Hash/_poly1305.abi3.so
Executable file
Binary file not shown.
187
lib/Crypto/Hash/cSHAKE128.py
Normal file
187
lib/Crypto/Hash/cSHAKE128.py
Normal file
@@ -0,0 +1,187 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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 bchr
|
||||
|
||||
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.Hash.keccak import _raw_keccak_lib
|
||||
|
||||
|
||||
def _left_encode(x):
|
||||
"""Left encode function as defined in NIST SP 800-185"""
|
||||
|
||||
assert (x < (1 << 2040) and x >= 0)
|
||||
|
||||
# Get number of bytes needed to represent this integer.
|
||||
num = 1 if x == 0 else (x.bit_length() + 7) // 8
|
||||
|
||||
return bchr(num) + long_to_bytes(x)
|
||||
|
||||
|
||||
def _right_encode(x):
|
||||
"""Right encode function as defined in NIST SP 800-185"""
|
||||
|
||||
assert (x < (1 << 2040) and x >= 0)
|
||||
|
||||
# Get number of bytes needed to represent this integer.
|
||||
num = 1 if x == 0 else (x.bit_length() + 7) // 8
|
||||
|
||||
return long_to_bytes(x) + bchr(num)
|
||||
|
||||
|
||||
def _encode_str(x):
|
||||
"""Encode string function as defined in NIST SP 800-185"""
|
||||
|
||||
bitlen = len(x) * 8
|
||||
if bitlen >= (1 << 2040):
|
||||
raise ValueError("String too large to encode in cSHAKE")
|
||||
|
||||
return _left_encode(bitlen) + x
|
||||
|
||||
|
||||
def _bytepad(x, length):
|
||||
"""Zero pad byte string as defined in NIST SP 800-185"""
|
||||
|
||||
to_pad = _left_encode(length) + x
|
||||
|
||||
# Note: this implementation works with byte aligned strings,
|
||||
# hence no additional bit padding is needed at this point.
|
||||
npad = (length - len(to_pad) % length) % length
|
||||
|
||||
return to_pad + b'\x00' * npad
|
||||
|
||||
|
||||
class cSHAKE_XOF(object):
|
||||
"""A cSHAKE hash object.
|
||||
Do not instantiate directly.
|
||||
Use the :func:`new` function.
|
||||
"""
|
||||
|
||||
def __init__(self, data, custom, capacity, function):
|
||||
state = VoidPointer()
|
||||
|
||||
if custom or function:
|
||||
prefix_unpad = _encode_str(function) + _encode_str(custom)
|
||||
prefix = _bytepad(prefix_unpad, (1600 - capacity)//8)
|
||||
self._padding = 0x04
|
||||
else:
|
||||
prefix = None
|
||||
self._padding = 0x1F # for SHAKE
|
||||
|
||||
result = _raw_keccak_lib.keccak_init(state.address_of(),
|
||||
c_size_t(capacity//8),
|
||||
c_ubyte(24))
|
||||
if result:
|
||||
raise ValueError("Error %d while instantiating cSHAKE"
|
||||
% result)
|
||||
self._state = SmartPointer(state.get(),
|
||||
_raw_keccak_lib.keccak_destroy)
|
||||
self._is_squeezing = False
|
||||
|
||||
if prefix:
|
||||
self.update(prefix)
|
||||
|
||||
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 %s state"
|
||||
% (result, self.name))
|
||||
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 %s"
|
||||
% (result, self.name))
|
||||
|
||||
return get_raw_buffer(bfr)
|
||||
|
||||
|
||||
def _new(data, custom, function):
|
||||
# Use Keccak[256]
|
||||
return cSHAKE_XOF(data, custom, 256, function)
|
||||
|
||||
|
||||
def new(data=None, custom=None):
|
||||
"""Return a fresh instance of a cSHAKE128 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 bytestring (``S`` in SP 800-185).
|
||||
|
||||
:Return: A :class:`cSHAKE_XOF` object
|
||||
"""
|
||||
|
||||
# Use Keccak[256]
|
||||
return cSHAKE_XOF(data, custom, 256, b'')
|
||||
14
lib/Crypto/Hash/cSHAKE128.pyi
Normal file
14
lib/Crypto/Hash/cSHAKE128.pyi
Normal file
@@ -0,0 +1,14 @@
|
||||
from typing import Union, Optional
|
||||
|
||||
Buffer = Union[bytes, bytearray, memoryview]
|
||||
|
||||
class cSHAKE_XOF(object):
|
||||
def __init__(self,
|
||||
data: Optional[Buffer] = ...,
|
||||
function: Optional[bytes] = ...,
|
||||
custom: Optional[bytes] = ...) -> None: ...
|
||||
def update(self, data: Buffer) -> cSHAKE_XOF: ...
|
||||
def read(self, length: int) -> bytes: ...
|
||||
|
||||
def new(data: Optional[Buffer] = ...,
|
||||
custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ...
|
||||
56
lib/Crypto/Hash/cSHAKE256.py
Normal file
56
lib/Crypto/Hash/cSHAKE256.py
Normal file
@@ -0,0 +1,56 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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._raw_api import c_size_t
|
||||
from Crypto.Hash.cSHAKE128 import cSHAKE_XOF
|
||||
|
||||
|
||||
def _new(data, custom, function):
|
||||
# Use Keccak[512]
|
||||
return cSHAKE_XOF(data, custom, 512, function)
|
||||
|
||||
|
||||
def new(data=None, custom=None):
|
||||
"""Return a fresh instance of a cSHAKE256 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.
|
||||
custom (bytes):
|
||||
Optional.
|
||||
A customization bytestring (``S`` in SP 800-185).
|
||||
|
||||
:Return: A :class:`cSHAKE_XOF` object
|
||||
"""
|
||||
|
||||
# Use Keccak[512]
|
||||
return cSHAKE_XOF(data, custom, 512, b'')
|
||||
8
lib/Crypto/Hash/cSHAKE256.pyi
Normal file
8
lib/Crypto/Hash/cSHAKE256.pyi
Normal file
@@ -0,0 +1,8 @@
|
||||
from typing import Union, Optional
|
||||
|
||||
from Crypto.Hash.cSHAKE128 import cSHAKE_XOF
|
||||
|
||||
Buffer = Union[bytes, bytearray, memoryview]
|
||||
|
||||
def new(data: Optional[Buffer] = ...,
|
||||
custom: Optional[Buffer] = ...) -> cSHAKE_XOF: ...
|
||||
181
lib/Crypto/Hash/keccak.py
Normal file
181
lib/Crypto/Hash/keccak.py
Normal file
@@ -0,0 +1,181 @@
|
||||
# ===================================================================
|
||||
#
|
||||
# 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)
|
||||
|
||||
_raw_keccak_lib = load_pycryptodome_raw_lib("Crypto.Hash._keccak",
|
||||
"""
|
||||
int keccak_init(void **state,
|
||||
size_t capacity_bytes,
|
||||
uint8_t rounds);
|
||||
int keccak_destroy(void *state);
|
||||
int keccak_absorb(void *state,
|
||||
const uint8_t *in,
|
||||
size_t len);
|
||||
int keccak_squeeze(const void *state,
|
||||
uint8_t *out,
|
||||
size_t len,
|
||||
uint8_t padding);
|
||||
int keccak_digest(void *state,
|
||||
uint8_t *digest,
|
||||
size_t len,
|
||||
uint8_t padding);
|
||||
int keccak_copy(const void *src, void *dst);
|
||||
int keccak_reset(void *state);
|
||||
""")
|
||||
|
||||
class Keccak_Hash(object):
|
||||
"""A Keccak hash object.
|
||||
Do not instantiate directly.
|
||||
Use the :func:`new` function.
|
||||
|
||||
:ivar digest_size: the size in bytes of the resulting hash
|
||||
:vartype digest_size: integer
|
||||
"""
|
||||
|
||||
def __init__(self, data, 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
|
||||
self._padding = 0x01
|
||||
|
||||
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 keccak" % 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 keccak" % 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 squeezing keccak" % 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 new(self, **kwargs):
|
||||
"""Create a fresh Keccak hash object."""
|
||||
|
||||
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):
|
||||
The very first chunk of the message to hash.
|
||||
It is equivalent to an early call to :meth:`Keccak_Hash.update`.
|
||||
digest_bytes (integer):
|
||||
The size of the digest, in bytes (28, 32, 48, 64).
|
||||
digest_bits (integer):
|
||||
The size of the digest, in bits (224, 256, 384, 512).
|
||||
update_after_digest (boolean):
|
||||
Whether :meth:`Keccak.digest` can be followed by another
|
||||
:meth:`Keccak.update` (default: ``False``).
|
||||
|
||||
:Return: A :class:`Keccak_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):
|
||||
raise TypeError("Digest size (bits, bytes) not provided")
|
||||
if digest_bytes is not None:
|
||||
if digest_bytes not in (28, 32, 48, 64):
|
||||
raise ValueError("'digest_bytes' must be: 28, 32, 48 or 64")
|
||||
else:
|
||||
if digest_bits not in (224, 256, 384, 512):
|
||||
raise ValueError("'digest_bytes' must be: 224, 256, 384 or 512")
|
||||
digest_bytes = digest_bits // 8
|
||||
|
||||
if kwargs:
|
||||
raise TypeError("Unknown parameters: " + str(kwargs))
|
||||
|
||||
return Keccak_Hash(data, digest_bytes, update_after_digest)
|
||||
23
lib/Crypto/Hash/keccak.pyi
Normal file
23
lib/Crypto/Hash/keccak.pyi
Normal file
@@ -0,0 +1,23 @@
|
||||
from typing import Union, Any
|
||||
|
||||
Buffer = Union[bytes, bytearray, memoryview]
|
||||
|
||||
class Keccak_Hash(object):
|
||||
digest_size: int
|
||||
def __init__(self,
|
||||
data: Buffer,
|
||||
digest_bytes: int,
|
||||
update_after_digest: bool) -> None: ...
|
||||
def update(self, data: Buffer) -> Keccak_Hash: ...
|
||||
def digest(self) -> bytes: ...
|
||||
def hexdigest(self) -> str: ...
|
||||
def new(self,
|
||||
data: Buffer = ...,
|
||||
digest_bytes: int = ...,
|
||||
digest_bits: int = ...,
|
||||
update_after_digest: bool = ...) -> Keccak_Hash: ...
|
||||
|
||||
def new(data: Buffer = ...,
|
||||
digest_bytes: int = ...,
|
||||
digest_bits: int = ...,
|
||||
update_after_digest: bool = ...) -> Keccak_Hash: ...
|
||||
Reference in New Issue
Block a user