• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 absolute_import, division, print_function
6
7import abc
8
9import six
10
11from cryptography import utils
12
13
14@six.add_metaclass(abc.ABCMeta)
15class Mode(object):
16    @abc.abstractproperty
17    def name(self):
18        """
19        A string naming this mode (e.g. "ECB", "CBC").
20        """
21
22    @abc.abstractmethod
23    def validate_for_algorithm(self, algorithm):
24        """
25        Checks that all the necessary invariants of this (mode, algorithm)
26        combination are met.
27        """
28
29
30@six.add_metaclass(abc.ABCMeta)
31class ModeWithInitializationVector(object):
32    @abc.abstractproperty
33    def initialization_vector(self):
34        """
35        The value of the initialization vector for this mode as bytes.
36        """
37
38
39@six.add_metaclass(abc.ABCMeta)
40class ModeWithTweak(object):
41    @abc.abstractproperty
42    def tweak(self):
43        """
44        The value of the tweak for this mode as bytes.
45        """
46
47
48@six.add_metaclass(abc.ABCMeta)
49class ModeWithNonce(object):
50    @abc.abstractproperty
51    def nonce(self):
52        """
53        The value of the nonce for this mode as bytes.
54        """
55
56
57@six.add_metaclass(abc.ABCMeta)
58class ModeWithAuthenticationTag(object):
59    @abc.abstractproperty
60    def tag(self):
61        """
62        The value of the tag supplied to the constructor of this mode.
63        """
64
65
66def _check_aes_key_length(self, algorithm):
67    if algorithm.key_size > 256 and algorithm.name == "AES":
68        raise ValueError(
69            "Only 128, 192, and 256 bit keys are allowed for this AES mode"
70        )
71
72
73def _check_iv_length(self, algorithm):
74    if len(self.initialization_vector) * 8 != algorithm.block_size:
75        raise ValueError(
76            "Invalid IV size ({}) for {}.".format(
77                len(self.initialization_vector), self.name
78            )
79        )
80
81
82def _check_iv_and_key_length(self, algorithm):
83    _check_aes_key_length(self, algorithm)
84    _check_iv_length(self, algorithm)
85
86
87@utils.register_interface(Mode)
88@utils.register_interface(ModeWithInitializationVector)
89class CBC(object):
90    name = "CBC"
91
92    def __init__(self, initialization_vector):
93        utils._check_byteslike("initialization_vector", initialization_vector)
94        self._initialization_vector = initialization_vector
95
96    initialization_vector = utils.read_only_property("_initialization_vector")
97    validate_for_algorithm = _check_iv_and_key_length
98
99
100@utils.register_interface(Mode)
101@utils.register_interface(ModeWithTweak)
102class XTS(object):
103    name = "XTS"
104
105    def __init__(self, tweak):
106        utils._check_byteslike("tweak", tweak)
107
108        if len(tweak) != 16:
109            raise ValueError("tweak must be 128-bits (16 bytes)")
110
111        self._tweak = tweak
112
113    tweak = utils.read_only_property("_tweak")
114
115    def validate_for_algorithm(self, algorithm):
116        if algorithm.key_size not in (256, 512):
117            raise ValueError(
118                "The XTS specification requires a 256-bit key for AES-128-XTS"
119                " and 512-bit key for AES-256-XTS"
120            )
121
122
123@utils.register_interface(Mode)
124class ECB(object):
125    name = "ECB"
126
127    validate_for_algorithm = _check_aes_key_length
128
129
130@utils.register_interface(Mode)
131@utils.register_interface(ModeWithInitializationVector)
132class OFB(object):
133    name = "OFB"
134
135    def __init__(self, initialization_vector):
136        utils._check_byteslike("initialization_vector", initialization_vector)
137        self._initialization_vector = initialization_vector
138
139    initialization_vector = utils.read_only_property("_initialization_vector")
140    validate_for_algorithm = _check_iv_and_key_length
141
142
143@utils.register_interface(Mode)
144@utils.register_interface(ModeWithInitializationVector)
145class CFB(object):
146    name = "CFB"
147
148    def __init__(self, initialization_vector):
149        utils._check_byteslike("initialization_vector", initialization_vector)
150        self._initialization_vector = initialization_vector
151
152    initialization_vector = utils.read_only_property("_initialization_vector")
153    validate_for_algorithm = _check_iv_and_key_length
154
155
156@utils.register_interface(Mode)
157@utils.register_interface(ModeWithInitializationVector)
158class CFB8(object):
159    name = "CFB8"
160
161    def __init__(self, initialization_vector):
162        utils._check_byteslike("initialization_vector", initialization_vector)
163        self._initialization_vector = initialization_vector
164
165    initialization_vector = utils.read_only_property("_initialization_vector")
166    validate_for_algorithm = _check_iv_and_key_length
167
168
169@utils.register_interface(Mode)
170@utils.register_interface(ModeWithNonce)
171class CTR(object):
172    name = "CTR"
173
174    def __init__(self, nonce):
175        utils._check_byteslike("nonce", nonce)
176        self._nonce = nonce
177
178    nonce = utils.read_only_property("_nonce")
179
180    def validate_for_algorithm(self, algorithm):
181        _check_aes_key_length(self, algorithm)
182        if len(self.nonce) * 8 != algorithm.block_size:
183            raise ValueError(
184                "Invalid nonce size ({}) for {}.".format(
185                    len(self.nonce), self.name
186                )
187            )
188
189
190@utils.register_interface(Mode)
191@utils.register_interface(ModeWithInitializationVector)
192@utils.register_interface(ModeWithAuthenticationTag)
193class GCM(object):
194    name = "GCM"
195    _MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8
196    _MAX_AAD_BYTES = (2 ** 64) // 8
197
198    def __init__(self, initialization_vector, tag=None, min_tag_length=16):
199        # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive
200        # This is a sane limit anyway so we'll enforce it here.
201        utils._check_byteslike("initialization_vector", initialization_vector)
202        if len(initialization_vector) < 8 or len(initialization_vector) > 128:
203            raise ValueError(
204                "initialization_vector must be between 8 and 128 bytes (64 "
205                "and 1024 bits)."
206            )
207        self._initialization_vector = initialization_vector
208        if tag is not None:
209            utils._check_bytes("tag", tag)
210            if min_tag_length < 4:
211                raise ValueError("min_tag_length must be >= 4")
212            if len(tag) < min_tag_length:
213                raise ValueError(
214                    "Authentication tag must be {} bytes or longer.".format(
215                        min_tag_length
216                    )
217                )
218        self._tag = tag
219        self._min_tag_length = min_tag_length
220
221    tag = utils.read_only_property("_tag")
222    initialization_vector = utils.read_only_property("_initialization_vector")
223
224    def validate_for_algorithm(self, algorithm):
225        _check_aes_key_length(self, algorithm)
226