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