# =================================================================== # # Copyright (c) 2015, Legrandin # 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. # =================================================================== """SHAKE256 extendable-output function. SHAKE256 belongs to the SHA-3 family, as specified in `FIPS 202`_. As a XOF, SHAKE256 is a generalization of a cryptographic hash function. Instead of having a fixed-length output (e.g. 32 bytes like SHA-2/256), the output length for a XOF is unlimited. The *256* in its name indicates its maximum security level (in bits), as described in Section A.2 of `FIPS 202`_. For instance: >>> from Crypto.Hash import SHAKE256 >>> from binascii import hexlify >>> >>> shake = SHAKE256.new() >>> shake.update(b'Some data') >>> print hexlify(shake.read(26)) .. _FIPS 202: http://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf """ 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, expect_byte_string) from Crypto.Hash.keccak import _raw_keccak_lib class SHAKE256_XOF(object): """Class that implements a SHAKE256 XOF """ #: 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), 0x1F) if result: raise ValueError("Error %d while instantiating SHAKE256" % result) self._state = SmartPointer(state.get(), _raw_keccak_lib.keccak_destroy) self._is_squeezing = False 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) You cannot use ``update`` anymore after the first call to ``read``. :Parameters: data : byte string The next chunk of the message being hashed. """ if self._is_squeezing: raise TypeError("You cannot call 'update' after the first 'read'") expect_byte_string(data) result = _raw_keccak_lib.keccak_absorb(self._state.get(), data, c_size_t(len(data))) if result: raise ValueError("Error %d while updating SHAKE256 state" % result) return self def read(self, length): """Return the next ``length`` bytes of **binary** (non-printable) digest for the message. You cannot use ``update`` anymore after the first call to ``read``. :Return: A byte string of `length` bytes. """ self._is_squeezing = True bfr = create_string_buffer(length) result = _raw_keccak_lib.keccak_squeeze(self._state.get(), bfr, c_size_t(length)) 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. :Parameters: data : byte string The very first chunk of the message to hash. It is equivalent to an early call to ``update()``. Optional. :Return: A `SHAKE256_XOF` object """ return SHAKE256_XOF(data=data)