Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/cryptography/hazmat/primitives/ciphers/modes.py : 63%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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.
6import abc
7import typing
9from cryptography import utils
10from cryptography.hazmat.primitives._cipheralgorithm import CipherAlgorithm
13class Mode(metaclass=abc.ABCMeta):
14 @abc.abstractproperty
15 def name(self) -> str:
16 """
17 A string naming this mode (e.g. "ECB", "CBC").
18 """
20 @abc.abstractmethod
21 def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None:
22 """
23 Checks that all the necessary invariants of this (mode, algorithm)
24 combination are met.
25 """
28class ModeWithInitializationVector(metaclass=abc.ABCMeta):
29 @abc.abstractproperty
30 def initialization_vector(self) -> bytes:
31 """
32 The value of the initialization vector for this mode as bytes.
33 """
36class ModeWithTweak(metaclass=abc.ABCMeta):
37 @abc.abstractproperty
38 def tweak(self) -> bytes:
39 """
40 The value of the tweak for this mode as bytes.
41 """
44class ModeWithNonce(metaclass=abc.ABCMeta):
45 @abc.abstractproperty
46 def nonce(self) -> bytes:
47 """
48 The value of the nonce for this mode as bytes.
49 """
52class ModeWithAuthenticationTag(metaclass=abc.ABCMeta):
53 @abc.abstractproperty
54 def tag(self) -> bytes:
55 """
56 The value of the tag supplied to the constructor of this mode.
57 """
60def _check_aes_key_length(self, algorithm):
61 if algorithm.key_size > 256 and algorithm.name == "AES":
62 raise ValueError(
63 "Only 128, 192, and 256 bit keys are allowed for this AES mode"
64 )
67def _check_iv_length(self, algorithm):
68 if len(self.initialization_vector) * 8 != algorithm.block_size:
69 raise ValueError(
70 "Invalid IV size ({}) for {}.".format(
71 len(self.initialization_vector), self.name
72 )
73 )
76def _check_nonce_length(nonce: bytes, name: str, algorithm):
77 if len(nonce) * 8 != algorithm.block_size:
78 raise ValueError(
79 "Invalid nonce size ({}) for {}.".format(len(nonce), name)
80 )
83def _check_iv_and_key_length(self, algorithm):
84 _check_aes_key_length(self, algorithm)
85 _check_iv_length(self, algorithm)
88class CBC(Mode, ModeWithInitializationVector):
89 name = "CBC"
91 def __init__(self, initialization_vector: bytes):
92 utils._check_byteslike("initialization_vector", initialization_vector)
93 self._initialization_vector = initialization_vector
95 initialization_vector = utils.read_only_property("_initialization_vector")
96 validate_for_algorithm = _check_iv_and_key_length
99class XTS(Mode, ModeWithTweak):
100 name = "XTS"
102 def __init__(self, tweak: bytes):
103 utils._check_byteslike("tweak", tweak)
105 if len(tweak) != 16:
106 raise ValueError("tweak must be 128-bits (16 bytes)")
108 self._tweak = tweak
110 tweak = utils.read_only_property("_tweak")
112 def validate_for_algorithm(self, algorithm: CipherAlgorithm):
113 if algorithm.key_size not in (256, 512):
114 raise ValueError(
115 "The XTS specification requires a 256-bit key for AES-128-XTS"
116 " and 512-bit key for AES-256-XTS"
117 )
120class ECB(Mode):
121 name = "ECB"
123 validate_for_algorithm = _check_aes_key_length
126class OFB(Mode, ModeWithInitializationVector):
127 name = "OFB"
129 def __init__(self, initialization_vector: bytes):
130 utils._check_byteslike("initialization_vector", initialization_vector)
131 self._initialization_vector = initialization_vector
133 initialization_vector = utils.read_only_property("_initialization_vector")
134 validate_for_algorithm = _check_iv_and_key_length
137class CFB(Mode, ModeWithInitializationVector):
138 name = "CFB"
140 def __init__(self, initialization_vector: bytes):
141 utils._check_byteslike("initialization_vector", initialization_vector)
142 self._initialization_vector = initialization_vector
144 initialization_vector = utils.read_only_property("_initialization_vector")
145 validate_for_algorithm = _check_iv_and_key_length
148class CFB8(Mode, ModeWithInitializationVector):
149 name = "CFB8"
151 def __init__(self, initialization_vector: bytes):
152 utils._check_byteslike("initialization_vector", initialization_vector)
153 self._initialization_vector = initialization_vector
155 initialization_vector = utils.read_only_property("_initialization_vector")
156 validate_for_algorithm = _check_iv_and_key_length
159class CTR(Mode, ModeWithNonce):
160 name = "CTR"
162 def __init__(self, nonce: bytes):
163 utils._check_byteslike("nonce", nonce)
164 self._nonce = nonce
166 nonce = utils.read_only_property("_nonce")
168 def validate_for_algorithm(self, algorithm: CipherAlgorithm):
169 _check_aes_key_length(self, algorithm)
170 _check_nonce_length(self.nonce, self.name, algorithm)
173class GCM(Mode, ModeWithInitializationVector, ModeWithAuthenticationTag):
174 name = "GCM"
175 _MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8
176 _MAX_AAD_BYTES = (2 ** 64) // 8
178 def __init__(
179 self,
180 initialization_vector: bytes,
181 tag: typing.Optional[bytes] = None,
182 min_tag_length: int = 16,
183 ):
184 # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive
185 # This is a sane limit anyway so we'll enforce it here.
186 utils._check_byteslike("initialization_vector", initialization_vector)
187 if len(initialization_vector) < 8 or len(initialization_vector) > 128:
188 raise ValueError(
189 "initialization_vector must be between 8 and 128 bytes (64 "
190 "and 1024 bits)."
191 )
192 self._initialization_vector = initialization_vector
193 if tag is not None:
194 utils._check_bytes("tag", tag)
195 if min_tag_length < 4:
196 raise ValueError("min_tag_length must be >= 4")
197 if len(tag) < min_tag_length:
198 raise ValueError(
199 "Authentication tag must be {} bytes or longer.".format(
200 min_tag_length
201 )
202 )
203 self._tag = tag
204 self._min_tag_length = min_tag_length
206 tag = utils.read_only_property("_tag")
207 initialization_vector = utils.read_only_property("_initialization_vector")
209 def validate_for_algorithm(self, algorithm: CipherAlgorithm):
210 _check_aes_key_length(self, algorithm)