Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/modes.py: 57%

134 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

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 

5 

6import abc 

7import typing 

8 

9from cryptography import utils 

10from cryptography.exceptions import UnsupportedAlgorithm, _Reasons 

11from cryptography.hazmat.primitives._cipheralgorithm import ( 

12 BlockCipherAlgorithm, 

13 CipherAlgorithm, 

14) 

15from cryptography.hazmat.primitives.ciphers import algorithms 

16 

17 

18class Mode(metaclass=abc.ABCMeta): 

19 @abc.abstractproperty 

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 @abc.abstractproperty 

35 def initialization_vector(self) -> bytes: 

36 """ 

37 The value of the initialization vector for this mode as bytes. 

38 """ 

39 

40 

41class ModeWithTweak(Mode, metaclass=abc.ABCMeta): 

42 @abc.abstractproperty 

43 def tweak(self) -> bytes: 

44 """ 

45 The value of the tweak for this mode as bytes. 

46 """ 

47 

48 

49class ModeWithNonce(Mode, metaclass=abc.ABCMeta): 

50 @abc.abstractproperty 

51 def nonce(self) -> bytes: 

52 """ 

53 The value of the nonce for this mode as bytes. 

54 """ 

55 

56 

57class ModeWithAuthenticationTag(Mode, metaclass=abc.ABCMeta): 

58 @abc.abstractproperty 

59 def tag(self) -> typing.Optional[bytes]: 

60 """ 

61 The value of the tag supplied to the constructor of this mode. 

62 """ 

63 

64 

65def _check_aes_key_length(self: Mode, algorithm: CipherAlgorithm) -> None: 

66 if algorithm.key_size > 256 and algorithm.name == "AES": 

67 raise ValueError( 

68 "Only 128, 192, and 256 bit keys are allowed for this AES mode" 

69 ) 

70 

71 

72def _check_iv_length( 

73 self: ModeWithInitializationVector, algorithm: BlockCipherAlgorithm 

74) -> None: 

75 if len(self.initialization_vector) * 8 != algorithm.block_size: 

76 raise ValueError( 

77 "Invalid IV size ({}) for {}.".format( 

78 len(self.initialization_vector), self.name 

79 ) 

80 ) 

81 

82 

83def _check_nonce_length( 

84 nonce: bytes, name: str, algorithm: CipherAlgorithm 

85) -> None: 

86 if not isinstance(algorithm, BlockCipherAlgorithm): 

87 raise UnsupportedAlgorithm( 

88 f"{name} requires a block cipher algorithm", 

89 _Reasons.UNSUPPORTED_CIPHER, 

90 ) 

91 if len(nonce) * 8 != algorithm.block_size: 

92 raise ValueError( 

93 "Invalid nonce size ({}) for {}.".format(len(nonce), name) 

94 ) 

95 

96 

97def _check_iv_and_key_length( 

98 self: ModeWithInitializationVector, algorithm: CipherAlgorithm 

99) -> None: 

100 if not isinstance(algorithm, BlockCipherAlgorithm): 

101 raise UnsupportedAlgorithm( 

102 f"{self} requires a block cipher algorithm", 

103 _Reasons.UNSUPPORTED_CIPHER, 

104 ) 

105 _check_aes_key_length(self, algorithm) 

106 _check_iv_length(self, algorithm) 

107 

108 

109class CBC(ModeWithInitializationVector): 

110 name = "CBC" 

111 

112 def __init__(self, initialization_vector: bytes): 

113 utils._check_byteslike("initialization_vector", initialization_vector) 

114 self._initialization_vector = initialization_vector 

115 

116 @property 

117 def initialization_vector(self) -> bytes: 

118 return self._initialization_vector 

119 

120 validate_for_algorithm = _check_iv_and_key_length 

121 

122 

123class XTS(ModeWithTweak): 

124 name = "XTS" 

125 

126 def __init__(self, tweak: bytes): 

127 utils._check_byteslike("tweak", tweak) 

128 

129 if len(tweak) != 16: 

130 raise ValueError("tweak must be 128-bits (16 bytes)") 

131 

132 self._tweak = tweak 

133 

134 @property 

135 def tweak(self) -> bytes: 

136 return self._tweak 

137 

138 def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: 

139 if isinstance(algorithm, (algorithms.AES128, algorithms.AES256)): 

140 raise TypeError( 

141 "The AES128 and AES256 classes do not support XTS, please use " 

142 "the standard AES class instead." 

143 ) 

144 

145 if algorithm.key_size not in (256, 512): 

146 raise ValueError( 

147 "The XTS specification requires a 256-bit key for AES-128-XTS" 

148 " and 512-bit key for AES-256-XTS" 

149 ) 

150 

151 

152class ECB(Mode): 

153 name = "ECB" 

154 

155 validate_for_algorithm = _check_aes_key_length 

156 

157 

158class OFB(ModeWithInitializationVector): 

159 name = "OFB" 

160 

161 def __init__(self, initialization_vector: bytes): 

162 utils._check_byteslike("initialization_vector", initialization_vector) 

163 self._initialization_vector = initialization_vector 

164 

165 @property 

166 def initialization_vector(self) -> bytes: 

167 return self._initialization_vector 

168 

169 validate_for_algorithm = _check_iv_and_key_length 

170 

171 

172class CFB(ModeWithInitializationVector): 

173 name = "CFB" 

174 

175 def __init__(self, initialization_vector: bytes): 

176 utils._check_byteslike("initialization_vector", initialization_vector) 

177 self._initialization_vector = initialization_vector 

178 

179 @property 

180 def initialization_vector(self) -> bytes: 

181 return self._initialization_vector 

182 

183 validate_for_algorithm = _check_iv_and_key_length 

184 

185 

186class CFB8(ModeWithInitializationVector): 

187 name = "CFB8" 

188 

189 def __init__(self, initialization_vector: bytes): 

190 utils._check_byteslike("initialization_vector", initialization_vector) 

191 self._initialization_vector = initialization_vector 

192 

193 @property 

194 def initialization_vector(self) -> bytes: 

195 return self._initialization_vector 

196 

197 validate_for_algorithm = _check_iv_and_key_length 

198 

199 

200class CTR(ModeWithNonce): 

201 name = "CTR" 

202 

203 def __init__(self, nonce: bytes): 

204 utils._check_byteslike("nonce", nonce) 

205 self._nonce = nonce 

206 

207 @property 

208 def nonce(self) -> bytes: 

209 return self._nonce 

210 

211 def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: 

212 _check_aes_key_length(self, algorithm) 

213 _check_nonce_length(self.nonce, self.name, algorithm) 

214 

215 

216class GCM(ModeWithInitializationVector, ModeWithAuthenticationTag): 

217 name = "GCM" 

218 _MAX_ENCRYPTED_BYTES = (2**39 - 256) // 8 

219 _MAX_AAD_BYTES = (2**64) // 8 

220 

221 def __init__( 

222 self, 

223 initialization_vector: bytes, 

224 tag: typing.Optional[bytes] = None, 

225 min_tag_length: int = 16, 

226 ): 

227 # OpenSSL 3.0.0 constrains GCM IVs to [64, 1024] bits inclusive 

228 # This is a sane limit anyway so we'll enforce it here. 

229 utils._check_byteslike("initialization_vector", initialization_vector) 

230 if len(initialization_vector) < 8 or len(initialization_vector) > 128: 

231 raise ValueError( 

232 "initialization_vector must be between 8 and 128 bytes (64 " 

233 "and 1024 bits)." 

234 ) 

235 self._initialization_vector = initialization_vector 

236 if tag is not None: 

237 utils._check_bytes("tag", tag) 

238 if min_tag_length < 4: 

239 raise ValueError("min_tag_length must be >= 4") 

240 if len(tag) < min_tag_length: 

241 raise ValueError( 

242 "Authentication tag must be {} bytes or longer.".format( 

243 min_tag_length 

244 ) 

245 ) 

246 self._tag = tag 

247 self._min_tag_length = min_tag_length 

248 

249 @property 

250 def tag(self) -> typing.Optional[bytes]: 

251 return self._tag 

252 

253 @property 

254 def initialization_vector(self) -> bytes: 

255 return self._initialization_vector 

256 

257 def validate_for_algorithm(self, algorithm: CipherAlgorithm) -> None: 

258 _check_aes_key_length(self, algorithm) 

259 if not isinstance(algorithm, BlockCipherAlgorithm): 

260 raise UnsupportedAlgorithm( 

261 "GCM requires a block cipher algorithm", 

262 _Reasons.UNSUPPORTED_CIPHER, 

263 ) 

264 block_size_bytes = algorithm.block_size // 8 

265 if self._tag is not None and len(self._tag) > block_size_bytes: 

266 raise ValueError( 

267 "Authentication tag cannot be more than {} bytes.".format( 

268 block_size_bytes 

269 ) 

270 )