modes.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. import abc
  5. import typing
  6. from cryptography import utils
  7. from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm
  8. class Mode(metaclass=abc.ABCMeta):
  9. @abc.abstractproperty
  10. def name(self) -> str:
  11. """
  12. A string naming this mode (e.g. "ECB", "CBC").
  13. """
  14. @abc.abstractmethod
  15. def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None:
  16. """
  17. Checks that all the necessary invariants of this (mode, algorithm)
  18. combination are met.
  19. """
  20. class ModeWithInitializationVector(metaclass=abc.ABCMeta):
  21. @abc.abstractproperty
  22. def initialization_vector(self) -> bytes:
  23. """
  24. The value of the initialization vector for this mode as bytes.
  25. """
  26. class ModeWithTweak(metaclass=abc.ABCMeta):
  27. @abc.abstractproperty
  28. def tweak(self) -> bytes:
  29. """
  30. The value of the tweak for this mode as bytes.
  31. """
  32. class ModeWithNonce(metaclass=abc.ABCMeta):
  33. @abc.abstractproperty
  34. def nonce(self) -> bytes:
  35. """
  36. The value of the nonce for this mode as bytes.
  37. """
  38. class ModeWithAuthenticationTag(metaclass=abc.ABCMeta):
  39. @abc.abstractproperty
  40. def tag(self) -> bytes:
  41. """
  42. The value of the tag supplied to the constructor of this mode.
  43. """
  44. def _check_aes_key_length(self, algorithm):
  45. if algorithm.key_size > 256 and algorithm.name == "AES":
  46. raise ValueError(
  47. "Only 128, 192, and 256 bit keys are allowed for this AES mode"
  48. )
  49. def _check_iv_length(self, algorithm):
  50. if len(self.initialization_vector) * 8 != algorithm.block_size:
  51. raise ValueError(
  52. "Invalid IV size ({}) for {}.".format(
  53. len(self.initialization_vector), self.name
  54. )
  55. )
  56. def _check_nonce_length(nonce: bytes, name: str, algorithm):
  57. if len(nonce) * 8 != algorithm.block_size:
  58. raise ValueError(
  59. "Invalid nonce size ({}) for {}.".format(len(nonce), name)
  60. )
  61. def _check_iv_and_key_length(self, algorithm):
  62. _check_aes_key_length(self, algorithm)
  63. _check_iv_length(self, algorithm)
  64. class CBC(Mode, ModeWithInitializationVector):
  65. name = "CBC"
  66. def __init__(self, initialization_vector: bytes):
  67. utils._check_byteslike("initialization_vector", initialization_vector)
  68. self._initialization_vector = initialization_vector
  69. initialization_vector = utils.read_only_property("_initialization_vector")
  70. validate_for_algorithm = _check_iv_and_key_length
  71. class XTS(Mode, ModeWithTweak):
  72. name = "XTS"
  73. def __init__(self, tweak: bytes):
  74. utils._check_byteslike("tweak", tweak)
  75. if len(tweak) != 16:
  76. raise ValueError("tweak must be 128-bits (16 bytes)")
  77. self._tweak = tweak
  78. tweak = utils.read_only_property("_tweak")
  79. def validate_for_algorithm(self, algorithm: CipherAlgorithm):
  80. if algorithm.key_size not in (256, 512):
  81. raise ValueError(
  82. "The XTS specification requires a 256-bit key for AES-128-XTS"
  83. " and 512-bit key for AES-256-XTS"
  84. )
  85. class ECB(Mode):
  86. name = "ECB"
  87. validate_for_algorithm = _check_aes_key_length
  88. class OFB(Mode, ModeWithInitializationVector):
  89. name = "OFB"
  90. def __init__(self, initialization_vector: bytes):
  91. utils._check_byteslike("initialization_vector", initialization_vector)
  92. self._initialization_vector = initialization_vector
  93. initialization_vector = utils.read_only_property("_initialization_vector")
  94. validate_for_algorithm = _check_iv_and_key_length
  95. class CFB(Mode, ModeWithInitializationVector):
  96. name = "CFB"
  97. def __init__(self, initialization_vector: bytes):
  98. utils._check_byteslike("initialization_vector", initialization_vector)
  99. self._initialization_vector = initialization_vector
  100. initialization_vector = utils.read_only_property("_initialization_vector")
  101. validate_for_algorithm = _check_iv_and_key_length
  102. class CFB8(Mode, ModeWithInitializationVector):
  103. name = "CFB8"
  104. def __init__(self, initialization_vector: bytes):
  105. utils._check_byteslike("initialization_vector", initialization_vector)
  106. self._initialization_vector = initialization_vector
  107. initialization_vector = utils.read_only_property("_initialization_vector")
  108. validate_for_algorithm = _check_iv_and_key_length
  109. class CTR(Mode, ModeWithNonce):
  110. name = "CTR"
  111. def __init__(self, nonce: bytes):
  112. utils._check_byteslike("nonce", nonce)
  113. self._nonce = nonce
  114. nonce = utils.read_only_property("_nonce")
  115. def validate_for_algorithm(self, algorithm: CipherAlgorithm):
  116. _check_aes_key_length(self, algorithm)
  117. _check_nonce_length(self.nonce, self.name, algorithm)
  118. class GCM(Mode, ModeWithInitializationVector, ModeWithAuthenticationTag):
  119. name = "GCM"
  120. _MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8
  121. _MAX_AAD_BYTES = (2 ** 64) // 8
  122. def __init__(
  123. self,
  124. initialization_vector: bytes,
  125. tag: typing.Optional[bytes] = None,
  126. min_tag_length: int = 16,
  127. ):
  128. # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive
  129. # This is a sane limit anyway so we'll enforce it here.
  130. utils._check_byteslike("initialization_vector", initialization_vector)
  131. if len(initialization_vector) < 8 or len(initialization_vector) > 128:
  132. raise ValueError(
  133. "initialization_vector must be between 8 and 128 bytes (64 "
  134. "and 1024 bits)."
  135. )
  136. self._initialization_vector = initialization_vector
  137. if tag is not None:
  138. utils._check_bytes("tag", tag)
  139. if min_tag_length < 4:
  140. raise ValueError("min_tag_length must be >= 4")
  141. if len(tag) < min_tag_length:
  142. raise ValueError(
  143. "Authentication tag must be {} bytes or longer.".format(
  144. min_tag_length
  145. )
  146. )
  147. self._tag = tag
  148. self._min_tag_length = min_tag_length
  149. tag = utils.read_only_property("_tag")
  150. initialization_vector = utils.read_only_property("_initialization_vector")
  151. def validate_for_algorithm(self, algorithm: CipherAlgorithm):
  152. _check_aes_key_length(self, algorithm)