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
5from __future__ import annotations
6
7import abc
8
9from cryptography import utils
10from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
11from cryptography.hazmat.primitives._cipheralgorithm import (
12 BlockCipherAlgorithm,
13 CipherAlgorithm,
14)
15
16
17class Mode(metaclass=abc.ABCMeta):
18 @property
19 @abc.abstractmethod
20 def name(self) -> str:
21 """
22 A string naming this mode (e.g. "ECB", "CBC").
23 """
24
25 @abc.abstractmethod
26 def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None:
27 """
28 Checks that all the necessary invariants of this (mode, algorithm)
29 combination are met.
30 """
31
32
33class ModeWithInitializationVector(Mode, metaclass=abc.ABCMeta):
34 @property
35 @abc.abstractmethod
36 def initialization_vector(self) -> utils.Buffer:
37 """
38 The value of the initialization vector for this mode as bytes.
39 """
40
41
42class ModeWithTweak(Mode, metaclass=abc.ABCMeta):
43 @property
44 @abc.abstractmethod
45 def tweak(self) -> utils.Buffer:
46 """
47 The value of the tweak for this mode as bytes.
48 """
49
50
51class ModeWithNonce(Mode, metaclass=abc.ABCMeta):
52 @property
53 @abc.abstractmethod
54 def nonce(self) -> utils.Buffer:
55 """
56 The value of the nonce for this mode as bytes.
57 """
58
59
60class ModeWithAuthenticationTag(Mode, metaclass=abc.ABCMeta):
61 @property
62 @abc.abstractmethod
63 def tag(self) -> bytes | None:
64 """
65 The value of the tag supplied to the constructor of this mode.
66 """
67
68
69def _check_aes_key_length(self: Mode, algorithm: CipherAlgorithm) -> None:
70 if algorithm.key_size > 256 and algorithm.name == "AES":
71 raise ValueError(
72 "Only 128, 192, and 256 bit keys are allowed for this AES mode"
73 )
74
75
76def _check_iv_length(
77 self: ModeWithInitializationVector, algorithm: BlockCipherAlgorithm
78) -> None:
79 iv_len = len(self.initialization_vector)
80 if iv_len * 8 != algorithm.block_size:
81 raise ValueError(f"Invalid IV size ({iv_len}) for {self.name}.")
82
83
84def _check_nonce_length(
85 nonce: utils.Buffer, name: str, algorithm: CipherAlgorithm
86) -> None:
87 if not isinstance(algorithm, BlockCipherAlgorithm):
88 raise UnsupportedAlgorithm(
89 f"{name} requires a block cipher algorithm",
90 _Reasons.UNSUPPORTED_CIPHER,
91 )
92 if len(nonce) * 8 != algorithm.block_size:
93 raise ValueError(f"Invalid nonce size ({len(nonce)}) for {name}.")
94
95
96def _check_iv_and_key_length(
97 self: ModeWithInitializationVector, algorithm: CipherAlgorithm
98) -> None:
99 if not isinstance(algorithm, BlockCipherAlgorithm):
100 raise UnsupportedAlgorithm(
101 f"{self} requires a block cipher algorithm",
102 _Reasons.UNSUPPORTED_CIPHER,
103 )
104 _check_aes_key_length(self, algorithm)
105 _check_iv_length(self, algorithm)