• 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("Invalid IV size ({0}) for {1}.".format(
76            len(self.initialization_vector), self.name
77        ))
78
79
80def _check_iv_and_key_length(self, algorithm):
81    _check_aes_key_length(self, algorithm)
82    _check_iv_length(self, algorithm)
83
84
85@utils.register_interface(Mode)
86@utils.register_interface(ModeWithInitializationVector)
87class CBC(object):
88    name = "CBC"
89
90    def __init__(self, initialization_vector):
91        utils._check_byteslike("initialization_vector", initialization_vector)
92        self._initialization_vector = initialization_vector
93
94    initialization_vector = utils.read_only_property("_initialization_vector")
95    validate_for_algorithm = _check_iv_and_key_length
96
97
98@utils.register_interface(Mode)
99@utils.register_interface(ModeWithTweak)
100class XTS(object):
101    name = "XTS"
102
103    def __init__(self, tweak):
104        utils._check_byteslike("tweak", tweak)
105
106        if len(tweak) != 16:
107            raise ValueError("tweak must be 128-bits (16 bytes)")
108
109        self._tweak = tweak
110
111    tweak = utils.read_only_property("_tweak")
112
113    def validate_for_algorithm(self, algorithm):
114        if algorithm.key_size not in (256, 512):
115            raise ValueError(
116                "The XTS specification requires a 256-bit key for AES-128-XTS"
117                " and 512-bit key for AES-256-XTS"
118            )
119
120
121@utils.register_interface(Mode)
122class ECB(object):
123    name = "ECB"
124
125    validate_for_algorithm = _check_aes_key_length
126
127
128@utils.register_interface(Mode)
129@utils.register_interface(ModeWithInitializationVector)
130class OFB(object):
131    name = "OFB"
132
133    def __init__(self, initialization_vector):
134        utils._check_byteslike("initialization_vector", initialization_vector)
135        self._initialization_vector = initialization_vector
136
137    initialization_vector = utils.read_only_property("_initialization_vector")
138    validate_for_algorithm = _check_iv_and_key_length
139
140
141@utils.register_interface(Mode)
142@utils.register_interface(ModeWithInitializationVector)
143class CFB(object):
144    name = "CFB"
145
146    def __init__(self, initialization_vector):
147        utils._check_byteslike("initialization_vector", initialization_vector)
148        self._initialization_vector = initialization_vector
149
150    initialization_vector = utils.read_only_property("_initialization_vector")
151    validate_for_algorithm = _check_iv_and_key_length
152
153
154@utils.register_interface(Mode)
155@utils.register_interface(ModeWithInitializationVector)
156class CFB8(object):
157    name = "CFB8"
158
159    def __init__(self, initialization_vector):
160        utils._check_byteslike("initialization_vector", initialization_vector)
161        self._initialization_vector = initialization_vector
162
163    initialization_vector = utils.read_only_property("_initialization_vector")
164    validate_for_algorithm = _check_iv_and_key_length
165
166
167@utils.register_interface(Mode)
168@utils.register_interface(ModeWithNonce)
169class CTR(object):
170    name = "CTR"
171
172    def __init__(self, nonce):
173        utils._check_byteslike("nonce", nonce)
174        self._nonce = nonce
175
176    nonce = utils.read_only_property("_nonce")
177
178    def validate_for_algorithm(self, algorithm):
179        _check_aes_key_length(self, algorithm)
180        if len(self.nonce) * 8 != algorithm.block_size:
181            raise ValueError("Invalid nonce size ({0}) for {1}.".format(
182                len(self.nonce), self.name
183            ))
184
185
186@utils.register_interface(Mode)
187@utils.register_interface(ModeWithInitializationVector)
188@utils.register_interface(ModeWithAuthenticationTag)
189class GCM(object):
190    name = "GCM"
191    _MAX_ENCRYPTED_BYTES = (2 ** 39 - 256) // 8
192    _MAX_AAD_BYTES = (2 ** 64) // 8
193
194    def __init__(self, initialization_vector, tag=None, min_tag_length=16):
195        # len(initialization_vector) must in [1, 2 ** 64), but it's impossible
196        # to actually construct a bytes object that large, so we don't check
197        # for it
198        utils._check_byteslike("initialization_vector", initialization_vector)
199        if len(initialization_vector) == 0:
200            raise ValueError("initialization_vector must be at least 1 byte")
201        self._initialization_vector = initialization_vector
202        if tag is not None:
203            utils._check_bytes("tag", tag)
204            if min_tag_length < 4:
205                raise ValueError("min_tag_length must be >= 4")
206            if len(tag) < min_tag_length:
207                raise ValueError(
208                    "Authentication tag must be {0} bytes or longer.".format(
209                        min_tag_length)
210                )
211        self._tag = tag
212        self._min_tag_length = min_tag_length
213
214    tag = utils.read_only_property("_tag")
215    initialization_vector = utils.read_only_property("_initialization_vector")
216
217    def validate_for_algorithm(self, algorithm):
218        _check_aes_key_length(self, algorithm)
219