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