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

187 statements  

« prev     ^ index     » next       coverage.py v7.2.1, created at 2023-03-14 06:36 +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 os 

7import typing 

8 

9from cryptography import exceptions, utils 

10from cryptography.hazmat.backends.openssl import aead 

11from cryptography.hazmat.backends.openssl.backend import backend 

12from cryptography.hazmat.bindings._rust import FixedPool 

13 

14 

15class ChaCha20Poly1305: 

16 _MAX_SIZE = 2**31 - 1 

17 

18 def __init__(self, key: bytes): 

19 if not backend.aead_cipher_supported(self): 

20 raise exceptions.UnsupportedAlgorithm( 

21 "ChaCha20Poly1305 is not supported by this version of OpenSSL", 

22 exceptions._Reasons.UNSUPPORTED_CIPHER, 

23 ) 

24 utils._check_byteslike("key", key) 

25 

26 if len(key) != 32: 

27 raise ValueError("ChaCha20Poly1305 key must be 32 bytes.") 

28 

29 self._key = key 

30 self._pool = FixedPool(self._create_fn) 

31 

32 @classmethod 

33 def generate_key(cls) -> bytes: 

34 return os.urandom(32) 

35 

36 def _create_fn(self): 

37 return aead._aead_create_ctx(backend, self, self._key) 

38 

39 def encrypt( 

40 self, 

41 nonce: bytes, 

42 data: bytes, 

43 associated_data: typing.Optional[bytes], 

44 ) -> bytes: 

45 if associated_data is None: 

46 associated_data = b"" 

47 

48 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: 

49 # This is OverflowError to match what cffi would raise 

50 raise OverflowError( 

51 "Data or associated data too long. Max 2**31 - 1 bytes" 

52 ) 

53 

54 self._check_params(nonce, data, associated_data) 

55 with self._pool.acquire() as ctx: 

56 return aead._encrypt( 

57 backend, self, nonce, data, [associated_data], 16, ctx 

58 ) 

59 

60 def decrypt( 

61 self, 

62 nonce: bytes, 

63 data: bytes, 

64 associated_data: typing.Optional[bytes], 

65 ) -> bytes: 

66 if associated_data is None: 

67 associated_data = b"" 

68 

69 self._check_params(nonce, data, associated_data) 

70 with self._pool.acquire() as ctx: 

71 return aead._decrypt( 

72 backend, self, nonce, data, [associated_data], 16, ctx 

73 ) 

74 

75 def _check_params( 

76 self, 

77 nonce: bytes, 

78 data: bytes, 

79 associated_data: bytes, 

80 ) -> None: 

81 utils._check_byteslike("nonce", nonce) 

82 utils._check_byteslike("data", data) 

83 utils._check_byteslike("associated_data", associated_data) 

84 if len(nonce) != 12: 

85 raise ValueError("Nonce must be 12 bytes") 

86 

87 

88class AESCCM: 

89 _MAX_SIZE = 2**31 - 1 

90 

91 def __init__(self, key: bytes, tag_length: int = 16): 

92 utils._check_byteslike("key", key) 

93 if len(key) not in (16, 24, 32): 

94 raise ValueError("AESCCM key must be 128, 192, or 256 bits.") 

95 

96 self._key = key 

97 if not isinstance(tag_length, int): 

98 raise TypeError("tag_length must be an integer") 

99 

100 if tag_length not in (4, 6, 8, 10, 12, 14, 16): 

101 raise ValueError("Invalid tag_length") 

102 

103 self._tag_length = tag_length 

104 

105 if not backend.aead_cipher_supported(self): 

106 raise exceptions.UnsupportedAlgorithm( 

107 "AESCCM is not supported by this version of OpenSSL", 

108 exceptions._Reasons.UNSUPPORTED_CIPHER, 

109 ) 

110 

111 @classmethod 

112 def generate_key(cls, bit_length: int) -> bytes: 

113 if not isinstance(bit_length, int): 

114 raise TypeError("bit_length must be an integer") 

115 

116 if bit_length not in (128, 192, 256): 

117 raise ValueError("bit_length must be 128, 192, or 256") 

118 

119 return os.urandom(bit_length // 8) 

120 

121 def encrypt( 

122 self, 

123 nonce: bytes, 

124 data: bytes, 

125 associated_data: typing.Optional[bytes], 

126 ) -> bytes: 

127 if associated_data is None: 

128 associated_data = b"" 

129 

130 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: 

131 # This is OverflowError to match what cffi would raise 

132 raise OverflowError( 

133 "Data or associated data too long. Max 2**31 - 1 bytes" 

134 ) 

135 

136 self._check_params(nonce, data, associated_data) 

137 self._validate_lengths(nonce, len(data)) 

138 return aead._encrypt( 

139 backend, self, nonce, data, [associated_data], self._tag_length 

140 ) 

141 

142 def decrypt( 

143 self, 

144 nonce: bytes, 

145 data: bytes, 

146 associated_data: typing.Optional[bytes], 

147 ) -> bytes: 

148 if associated_data is None: 

149 associated_data = b"" 

150 

151 self._check_params(nonce, data, associated_data) 

152 return aead._decrypt( 

153 backend, self, nonce, data, [associated_data], self._tag_length 

154 ) 

155 

156 def _validate_lengths(self, nonce: bytes, data_len: int) -> None: 

157 # For information about computing this, see 

158 # https://tools.ietf.org/html/rfc3610#section-2.1 

159 l_val = 15 - len(nonce) 

160 if 2 ** (8 * l_val) < data_len: 

161 raise ValueError("Data too long for nonce") 

162 

163 def _check_params( 

164 self, nonce: bytes, data: bytes, associated_data: bytes 

165 ) -> None: 

166 utils._check_byteslike("nonce", nonce) 

167 utils._check_byteslike("data", data) 

168 utils._check_byteslike("associated_data", associated_data) 

169 if not 7 <= len(nonce) <= 13: 

170 raise ValueError("Nonce must be between 7 and 13 bytes") 

171 

172 

173class AESGCM: 

174 _MAX_SIZE = 2**31 - 1 

175 

176 def __init__(self, key: bytes): 

177 utils._check_byteslike("key", key) 

178 if len(key) not in (16, 24, 32): 

179 raise ValueError("AESGCM key must be 128, 192, or 256 bits.") 

180 

181 self._key = key 

182 

183 @classmethod 

184 def generate_key(cls, bit_length: int) -> bytes: 

185 if not isinstance(bit_length, int): 

186 raise TypeError("bit_length must be an integer") 

187 

188 if bit_length not in (128, 192, 256): 

189 raise ValueError("bit_length must be 128, 192, or 256") 

190 

191 return os.urandom(bit_length // 8) 

192 

193 def encrypt( 

194 self, 

195 nonce: bytes, 

196 data: bytes, 

197 associated_data: typing.Optional[bytes], 

198 ) -> bytes: 

199 if associated_data is None: 

200 associated_data = b"" 

201 

202 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: 

203 # This is OverflowError to match what cffi would raise 

204 raise OverflowError( 

205 "Data or associated data too long. Max 2**31 - 1 bytes" 

206 ) 

207 

208 self._check_params(nonce, data, associated_data) 

209 return aead._encrypt(backend, self, nonce, data, [associated_data], 16) 

210 

211 def decrypt( 

212 self, 

213 nonce: bytes, 

214 data: bytes, 

215 associated_data: typing.Optional[bytes], 

216 ) -> bytes: 

217 if associated_data is None: 

218 associated_data = b"" 

219 

220 self._check_params(nonce, data, associated_data) 

221 return aead._decrypt(backend, self, nonce, data, [associated_data], 16) 

222 

223 def _check_params( 

224 self, 

225 nonce: bytes, 

226 data: bytes, 

227 associated_data: bytes, 

228 ) -> None: 

229 utils._check_byteslike("nonce", nonce) 

230 utils._check_byteslike("data", data) 

231 utils._check_byteslike("associated_data", associated_data) 

232 if len(nonce) < 8 or len(nonce) > 128: 

233 raise ValueError("Nonce must be between 8 and 128 bytes") 

234 

235 

236class AESOCB3: 

237 _MAX_SIZE = 2**31 - 1 

238 

239 def __init__(self, key: bytes): 

240 utils._check_byteslike("key", key) 

241 if len(key) not in (16, 24, 32): 

242 raise ValueError("AESOCB3 key must be 128, 192, or 256 bits.") 

243 

244 self._key = key 

245 

246 if not backend.aead_cipher_supported(self): 

247 raise exceptions.UnsupportedAlgorithm( 

248 "OCB3 is not supported by this version of OpenSSL", 

249 exceptions._Reasons.UNSUPPORTED_CIPHER, 

250 ) 

251 

252 @classmethod 

253 def generate_key(cls, bit_length: int) -> bytes: 

254 if not isinstance(bit_length, int): 

255 raise TypeError("bit_length must be an integer") 

256 

257 if bit_length not in (128, 192, 256): 

258 raise ValueError("bit_length must be 128, 192, or 256") 

259 

260 return os.urandom(bit_length // 8) 

261 

262 def encrypt( 

263 self, 

264 nonce: bytes, 

265 data: bytes, 

266 associated_data: typing.Optional[bytes], 

267 ) -> bytes: 

268 if associated_data is None: 

269 associated_data = b"" 

270 

271 if len(data) > self._MAX_SIZE or len(associated_data) > self._MAX_SIZE: 

272 # This is OverflowError to match what cffi would raise 

273 raise OverflowError( 

274 "Data or associated data too long. Max 2**31 - 1 bytes" 

275 ) 

276 

277 self._check_params(nonce, data, associated_data) 

278 return aead._encrypt(backend, self, nonce, data, [associated_data], 16) 

279 

280 def decrypt( 

281 self, 

282 nonce: bytes, 

283 data: bytes, 

284 associated_data: typing.Optional[bytes], 

285 ) -> bytes: 

286 if associated_data is None: 

287 associated_data = b"" 

288 

289 self._check_params(nonce, data, associated_data) 

290 return aead._decrypt(backend, self, nonce, data, [associated_data], 16) 

291 

292 def _check_params( 

293 self, 

294 nonce: bytes, 

295 data: bytes, 

296 associated_data: bytes, 

297 ) -> None: 

298 utils._check_byteslike("nonce", nonce) 

299 utils._check_byteslike("data", data) 

300 utils._check_byteslike("associated_data", associated_data) 

301 if len(nonce) < 12 or len(nonce) > 15: 

302 raise ValueError("Nonce must be between 12 and 15 bytes") 

303 

304 

305class AESSIV: 

306 _MAX_SIZE = 2**31 - 1 

307 

308 def __init__(self, key: bytes): 

309 utils._check_byteslike("key", key) 

310 if len(key) not in (32, 48, 64): 

311 raise ValueError("AESSIV key must be 256, 384, or 512 bits.") 

312 

313 self._key = key 

314 

315 if not backend.aead_cipher_supported(self): 

316 raise exceptions.UnsupportedAlgorithm( 

317 "AES-SIV is not supported by this version of OpenSSL", 

318 exceptions._Reasons.UNSUPPORTED_CIPHER, 

319 ) 

320 

321 @classmethod 

322 def generate_key(cls, bit_length: int) -> bytes: 

323 if not isinstance(bit_length, int): 

324 raise TypeError("bit_length must be an integer") 

325 

326 if bit_length not in (256, 384, 512): 

327 raise ValueError("bit_length must be 256, 384, or 512") 

328 

329 return os.urandom(bit_length // 8) 

330 

331 def encrypt( 

332 self, 

333 data: bytes, 

334 associated_data: typing.Optional[typing.List[bytes]], 

335 ) -> bytes: 

336 if associated_data is None: 

337 associated_data = [] 

338 

339 self._check_params(data, associated_data) 

340 

341 if len(data) > self._MAX_SIZE or any( 

342 len(ad) > self._MAX_SIZE for ad in associated_data 

343 ): 

344 # This is OverflowError to match what cffi would raise 

345 raise OverflowError( 

346 "Data or associated data too long. Max 2**31 - 1 bytes" 

347 ) 

348 

349 return aead._encrypt(backend, self, b"", data, associated_data, 16) 

350 

351 def decrypt( 

352 self, 

353 data: bytes, 

354 associated_data: typing.Optional[typing.List[bytes]], 

355 ) -> bytes: 

356 if associated_data is None: 

357 associated_data = [] 

358 

359 self._check_params(data, associated_data) 

360 

361 return aead._decrypt(backend, self, b"", data, associated_data, 16) 

362 

363 def _check_params( 

364 self, 

365 data: bytes, 

366 associated_data: typing.List[bytes], 

367 ) -> None: 

368 utils._check_byteslike("data", data) 

369 if len(data) == 0: 

370 raise ValueError("data must not be zero length") 

371 

372 if not isinstance(associated_data, list): 

373 raise TypeError( 

374 "associated_data must be a list of bytes-like objects or None" 

375 ) 

376 for x in associated_data: 

377 utils._check_byteslike("associated_data elements", x)