cSHAKE128.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # ===================================================================
  2. #
  3. # Copyright (c) 2021, Legrandin <helderijs@gmail.com>
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions
  8. # are met:
  9. #
  10. # 1. Redistributions of source code must retain the above copyright
  11. # notice, this list of conditions and the following disclaimer.
  12. # 2. Redistributions in binary form must reproduce the above copyright
  13. # notice, this list of conditions and the following disclaimer in
  14. # the documentation and/or other materials provided with the
  15. # distribution.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  18. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  19. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  20. # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  21. # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  22. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  23. # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  27. # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. # POSSIBILITY OF SUCH DAMAGE.
  29. # ===================================================================
  30. from Crypto.Util.py3compat import bchr, concat_buffers
  31. from Crypto.Util._raw_api import (VoidPointer, SmartPointer,
  32. create_string_buffer,
  33. get_raw_buffer, c_size_t,
  34. c_uint8_ptr, c_ubyte)
  35. from Crypto.Util.number import long_to_bytes
  36. from Crypto.Hash.keccak import _raw_keccak_lib
  37. def _left_encode(x):
  38. """Left encode function as defined in NIST SP 800-185"""
  39. assert (x < (1 << 2040) and x >= 0)
  40. # Get number of bytes needed to represent this integer.
  41. num = 1 if x == 0 else (x.bit_length() + 7) // 8
  42. return bchr(num) + long_to_bytes(x)
  43. def _right_encode(x):
  44. """Right encode function as defined in NIST SP 800-185"""
  45. assert (x < (1 << 2040) and x >= 0)
  46. # Get number of bytes needed to represent this integer.
  47. num = 1 if x == 0 else (x.bit_length() + 7) // 8
  48. return long_to_bytes(x) + bchr(num)
  49. def _encode_str(x):
  50. """Encode string function as defined in NIST SP 800-185"""
  51. bitlen = len(x) * 8
  52. if bitlen >= (1 << 2040):
  53. raise ValueError("String too large to encode in cSHAKE")
  54. return concat_buffers(_left_encode(bitlen), x)
  55. def _bytepad(x, length):
  56. """Zero pad byte string as defined in NIST SP 800-185"""
  57. to_pad = concat_buffers(_left_encode(length), x)
  58. # Note: this implementation works with byte aligned strings,
  59. # hence no additional bit padding is needed at this point.
  60. npad = (length - len(to_pad) % length) % length
  61. return to_pad + b'\x00' * npad
  62. class cSHAKE_XOF(object):
  63. """A cSHAKE hash object.
  64. Do not instantiate directly.
  65. Use the :func:`new` function.
  66. """
  67. def __init__(self, data, custom, capacity, function):
  68. state = VoidPointer()
  69. if custom or function:
  70. prefix_unpad = _encode_str(function) + _encode_str(custom)
  71. prefix = _bytepad(prefix_unpad, (1600 - capacity)//8)
  72. self._padding = 0x04
  73. else:
  74. prefix = None
  75. self._padding = 0x1F # for SHAKE
  76. result = _raw_keccak_lib.keccak_init(state.address_of(),
  77. c_size_t(capacity//8),
  78. c_ubyte(24))
  79. if result:
  80. raise ValueError("Error %d while instantiating cSHAKE"
  81. % result)
  82. self._state = SmartPointer(state.get(),
  83. _raw_keccak_lib.keccak_destroy)
  84. self._is_squeezing = False
  85. if prefix:
  86. self.update(prefix)
  87. if data:
  88. self.update(data)
  89. def update(self, data):
  90. """Continue hashing of a message by consuming the next chunk of data.
  91. Args:
  92. data (byte string/byte array/memoryview): The next chunk of the message being hashed.
  93. """
  94. if self._is_squeezing:
  95. raise TypeError("You cannot call 'update' after the first 'read'")
  96. result = _raw_keccak_lib.keccak_absorb(self._state.get(),
  97. c_uint8_ptr(data),
  98. c_size_t(len(data)))
  99. if result:
  100. raise ValueError("Error %d while updating %s state"
  101. % (result, self.name))
  102. return self
  103. def read(self, length):
  104. """
  105. Compute the next piece of XOF output.
  106. .. note::
  107. You cannot use :meth:`update` anymore after the first call to
  108. :meth:`read`.
  109. Args:
  110. length (integer): the amount of bytes this method must return
  111. :return: the next piece of XOF output (of the given length)
  112. :rtype: byte string
  113. """
  114. self._is_squeezing = True
  115. bfr = create_string_buffer(length)
  116. result = _raw_keccak_lib.keccak_squeeze(self._state.get(),
  117. bfr,
  118. c_size_t(length),
  119. c_ubyte(self._padding))
  120. if result:
  121. raise ValueError("Error %d while extracting from %s"
  122. % (result, self.name))
  123. return get_raw_buffer(bfr)
  124. def _new(data, custom, function):
  125. # Use Keccak[256]
  126. return cSHAKE_XOF(data, custom, 256, function)
  127. def new(data=None, custom=None):
  128. """Return a fresh instance of a cSHAKE128 object.
  129. Args:
  130. data (bytes/bytearray/memoryview):
  131. Optional.
  132. The very first chunk of the message to hash.
  133. It is equivalent to an early call to :meth:`update`.
  134. custom (bytes):
  135. Optional.
  136. A customization bytestring (``S`` in SP 800-185).
  137. :Return: A :class:`cSHAKE_XOF` object
  138. """
  139. # Use Keccak[256]
  140. return cSHAKE_XOF(data, custom, 256, b'')