cmac.py 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. # This file is dual licensed under the terms of the Apache License, Version
  2. # 2.0, and the BSD License. See the LICENSE file in the root of this repository
  3. # for complete details.
  4. from __future__ import absolute_import, division, print_function
  5. from cryptography import utils
  6. from cryptography.exceptions import (
  7. InvalidSignature,
  8. UnsupportedAlgorithm,
  9. _Reasons,
  10. )
  11. from cryptography.hazmat.primitives import constant_time
  12. from cryptography.hazmat.primitives.ciphers.modes import CBC
  13. class _CMACContext(object):
  14. def __init__(self, backend, algorithm, ctx=None):
  15. if not backend.cmac_algorithm_supported(algorithm):
  16. raise UnsupportedAlgorithm(
  17. "This backend does not support CMAC.",
  18. _Reasons.UNSUPPORTED_CIPHER,
  19. )
  20. self._backend = backend
  21. self._key = algorithm.key
  22. self._algorithm = algorithm
  23. self._output_length = algorithm.block_size // 8
  24. if ctx is None:
  25. registry = self._backend._cipher_registry
  26. adapter = registry[type(algorithm), CBC]
  27. evp_cipher = adapter(self._backend, algorithm, CBC)
  28. ctx = self._backend._lib.CMAC_CTX_new()
  29. self._backend.openssl_assert(ctx != self._backend._ffi.NULL)
  30. ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free)
  31. key_ptr = self._backend._ffi.from_buffer(self._key)
  32. res = self._backend._lib.CMAC_Init(
  33. ctx,
  34. key_ptr,
  35. len(self._key),
  36. evp_cipher,
  37. self._backend._ffi.NULL,
  38. )
  39. self._backend.openssl_assert(res == 1)
  40. self._ctx = ctx
  41. algorithm = utils.read_only_property("_algorithm")
  42. def update(self, data):
  43. res = self._backend._lib.CMAC_Update(self._ctx, data, len(data))
  44. self._backend.openssl_assert(res == 1)
  45. def finalize(self):
  46. buf = self._backend._ffi.new("unsigned char[]", self._output_length)
  47. length = self._backend._ffi.new("size_t *", self._output_length)
  48. res = self._backend._lib.CMAC_Final(self._ctx, buf, length)
  49. self._backend.openssl_assert(res == 1)
  50. self._ctx = None
  51. return self._backend._ffi.buffer(buf)[:]
  52. def copy(self):
  53. copied_ctx = self._backend._lib.CMAC_CTX_new()
  54. copied_ctx = self._backend._ffi.gc(
  55. copied_ctx, self._backend._lib.CMAC_CTX_free
  56. )
  57. res = self._backend._lib.CMAC_CTX_copy(copied_ctx, self._ctx)
  58. self._backend.openssl_assert(res == 1)
  59. return _CMACContext(self._backend, self._algorithm, ctx=copied_ctx)
  60. def verify(self, signature):
  61. digest = self.finalize()
  62. if not constant_time.bytes_eq(digest, signature):
  63. raise InvalidSignature("Signature did not match digest.")