Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/Crypto/Cipher/_mode_cbc.py: 69%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

95 statements  

1# SPDX-FileCopyrightText: 2014 Legrandin <helderijs@gmail.com> 

2# SPDX-License-Identifier: BSD-2-Clause 

3 

4""" 

5Ciphertext Block Chaining (CBC) mode. 

6""" 

7 

8from __future__ import annotations 

9 

10from typing import Optional, Union, overload 

11 

12__all__ = ["CbcMode"] 

13from Crypto.Cipher._state_machine import Method 

14from Crypto.Random import get_random_bytes 

15from Crypto.Util._raw_api import ( 

16 SmartPointer, 

17 VoidPointer, 

18 c_size_t, 

19 c_uint8_ptr_len, 

20 c_uint8_ptr_out, 

21 create_output_buffer, 

22 get_raw_buffer, 

23 is_writeable_buffer, 

24 load_pycryptodome_raw_lib, 

25) 

26 

27Buffer = Union[bytes, bytearray, memoryview] 

28 

29raw_cbc_lib = load_pycryptodome_raw_lib( 

30 "Crypto.Cipher._raw_cbc", 

31 """ 

32 int CBC_start_operation(void *cipher, 

33 const uint8_t iv[], 

34 size_t iv_len, 

35 void **pResult); 

36 int CBC_encrypt(void *cbcState, 

37 const uint8_t *in, 

38 uint8_t *out, 

39 size_t data_len); 

40 int CBC_decrypt(void *cbcState, 

41 const uint8_t *in, 

42 uint8_t *out, 

43 size_t data_len); 

44 int CBC_stop_operation(void *state); 

45 """, 

46) 

47 

48 

49class CbcMode: 

50 """*Cipher-Block Chaining (CBC)*. 

51 

52 Each of the ciphertext blocks depends on the current 

53 and all previous plaintext blocks. 

54 

55 An Initialization Vector (*IV*) is required. 

56 

57 See `NIST SP800-38A`_ , Section 6.2 . 

58 

59 .. _`NIST SP800-38A` : http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf 

60 

61 :undocumented: __init__ 

62 """ 

63 

64 def __init__(self, block_cipher: SmartPointer, iv: Buffer) -> None: 

65 """Create a new block cipher, configured in CBC mode. 

66 

67 :Parameters: 

68 block_cipher : C pointer 

69 A smart pointer to the low-level block cipher instance. 

70 

71 iv : bytes/bytearray/memoryview 

72 The initialization vector to use for encryption or decryption. 

73 It is as long as the cipher block. 

74 

75 **The IV must be unpredictable**. Ideally it is picked randomly. 

76 

77 Reusing the *IV* for encryptions performed with the same key 

78 compromises confidentiality. 

79 """ 

80 

81 state = VoidPointer() 

82 iv_ptr, iv_len = c_uint8_ptr_len(iv) 

83 result = raw_cbc_lib.CBC_start_operation( 

84 block_cipher.get(), iv_ptr, c_size_t(iv_len), state.address_of() 

85 ) 

86 if result: 

87 raise ValueError("Error %d while instantiating the CBC mode" % result) 

88 

89 # Ensure that object disposal of this Python object will (eventually) 

90 # free the memory allocated by the raw library for the cipher mode 

91 self._state = SmartPointer(state.get(), raw_cbc_lib.CBC_stop_operation) 

92 

93 # Memory allocated for the underlying block cipher is now owed 

94 # by the cipher mode 

95 block_cipher.release() 

96 

97 self.block_size = len(iv) 

98 """The block size of the underlying cipher, in bytes.""" 

99 

100 self.iv = bytes(iv) 

101 """The Initialization Vector originally used to create the object. 

102 The value does not change.""" 

103 

104 self.IV = self.iv 

105 """Alias for `iv`""" 

106 

107 self._next = [Method.ENCRYPT, Method.DECRYPT] 

108 

109 @overload 

110 def encrypt(self, plaintext: Buffer) -> bytes: ... 

111 

112 @overload 

113 def encrypt(self, plaintext: Buffer, output: Union[bytearray, memoryview]) -> None: ... 

114 

115 def encrypt( 

116 self, plaintext: Buffer, output: Optional[Union[bytearray, memoryview]] = None 

117 ) -> Optional[bytes]: 

118 """Encrypt data with the key and the parameters set at initialization. 

119 

120 A cipher object is stateful: once you have encrypted a message 

121 you cannot encrypt (or decrypt) another message using the same 

122 object. 

123 

124 The data to encrypt can be broken up in two or 

125 more pieces and `encrypt` can be called multiple times. 

126 

127 That is, the statement: 

128 

129 >>> c.encrypt(a) + c.encrypt(b) 

130 

131 is equivalent to: 

132 

133 >>> c.encrypt(a+b) 

134 

135 That also means that you cannot reuse an object for encrypting 

136 or decrypting other data with the same key. 

137 

138 This function does not add any padding to the plaintext. 

139 

140 :Parameters: 

141 plaintext : bytes/bytearray/memoryview 

142 The piece of data to encrypt. 

143 Its lenght must be multiple of the cipher block size. 

144 :Keywords: 

145 output : bytearray/memoryview 

146 The location where the ciphertext must be written to. 

147 If ``None``, the ciphertext is returned. 

148 :Return: 

149 If ``output`` is ``None``, the ciphertext is returned as ``bytes``. 

150 Otherwise, ``None``. 

151 """ 

152 

153 if Method.ENCRYPT not in self._next: 

154 raise TypeError("encrypt() cannot be called after decrypt()") 

155 self._next = [Method.ENCRYPT] 

156 

157 if output is None: 

158 ciphertext = create_output_buffer(len(plaintext)) 

159 else: 

160 ciphertext = output 

161 

162 if not is_writeable_buffer(output): 

163 raise TypeError("output must be a bytearray or a writeable memoryview") 

164 

165 if len(plaintext) != len(output): 

166 raise ValueError("output must have the same length as the input (%d bytes)" % len(plaintext)) 

167 

168 with c_uint8_ptr_out(ciphertext) as ciphertext_ptr: 

169 plaintext_ptr, plaintext_len = c_uint8_ptr_len(plaintext) 

170 # Check the lengths of the buffers that C code gets 

171 if len(ciphertext_ptr) != plaintext_len: 

172 raise ValueError("output must have the same length as the input (%d bytes)" % plaintext_len) 

173 result = raw_cbc_lib.CBC_encrypt( 

174 self._state.get(), plaintext_ptr, ciphertext_ptr, c_size_t(plaintext_len) 

175 ) 

176 if result: 

177 if result == 3: 

178 raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) 

179 raise ValueError("Error %d while encrypting in CBC mode" % result) 

180 

181 if output is None: 

182 return get_raw_buffer(ciphertext) 

183 else: 

184 return None 

185 

186 @overload 

187 def decrypt(self, ciphertext: Buffer) -> bytes: ... 

188 

189 @overload 

190 def decrypt(self, ciphertext: Buffer, output: Union[bytearray, memoryview]) -> None: ... 

191 

192 def decrypt( 

193 self, ciphertext: Buffer, output: Optional[Union[bytearray, memoryview]] = None 

194 ) -> Optional[bytes]: 

195 """Decrypt data with the key and the parameters set at initialization. 

196 

197 A cipher object is stateful: once you have decrypted a message 

198 you cannot decrypt (or encrypt) another message with the same 

199 object. 

200 

201 The data to decrypt can be broken up in two or 

202 more pieces and `decrypt` can be called multiple times. 

203 

204 That is, the statement: 

205 

206 >>> c.decrypt(a) + c.decrypt(b) 

207 

208 is equivalent to: 

209 

210 >>> c.decrypt(a+b) 

211 

212 This function does not remove any padding from the plaintext. 

213 

214 :Parameters: 

215 ciphertext : bytes/bytearray/memoryview 

216 The piece of data to decrypt. 

217 Its length must be multiple of the cipher block size. 

218 :Keywords: 

219 output : bytearray/memoryview 

220 The location where the plaintext must be written to. 

221 If ``None``, the plaintext is returned. 

222 :Return: 

223 If ``output`` is ``None``, the plaintext is returned as ``bytes``. 

224 Otherwise, ``None``. 

225 """ 

226 

227 if Method.DECRYPT not in self._next: 

228 raise TypeError("decrypt() cannot be called after encrypt()") 

229 self._next = [Method.DECRYPT] 

230 

231 if output is None: 

232 plaintext = create_output_buffer(len(ciphertext)) 

233 else: 

234 plaintext = output 

235 

236 if not is_writeable_buffer(output): 

237 raise TypeError("output must be a bytearray or a writeable memoryview") 

238 

239 if len(ciphertext) != len(output): 

240 raise ValueError("output must have the same length as the input (%d bytes)" % len(plaintext)) 

241 

242 with c_uint8_ptr_out(plaintext) as plaintext_ptr: 

243 ciphertext_ptr, ciphertext_len = c_uint8_ptr_len(ciphertext) 

244 # Check the lengths of the buffers that C code gets 

245 if len(plaintext_ptr) != ciphertext_len: 

246 raise ValueError("output must have the same length as the input (%d bytes)" % ciphertext_len) 

247 result = raw_cbc_lib.CBC_decrypt( 

248 self._state.get(), ciphertext_ptr, plaintext_ptr, c_size_t(ciphertext_len) 

249 ) 

250 if result: 

251 if result == 3: 

252 raise ValueError("Data must be padded to %d byte boundary in CBC mode" % self.block_size) 

253 raise ValueError("Error %d while decrypting in CBC mode" % result) 

254 

255 if output is None: 

256 return get_raw_buffer(plaintext) 

257 else: 

258 return None 

259 

260 

261def _create_cbc_cipher(factory, **kwargs): 

262 """Instantiate a cipher object that performs CBC encryption/decryption. 

263 

264 :Parameters: 

265 factory : module 

266 The underlying block cipher, a module from ``Crypto.Cipher``. 

267 

268 :Keywords: 

269 iv : bytes/bytearray/memoryview 

270 The IV to use for CBC. 

271 

272 IV : bytes/bytearray/memoryview 

273 Alias for ``iv``. 

274 

275 Any other keyword will be passed to the underlying block cipher. 

276 See the relevant documentation for details (at least ``key`` will need 

277 to be present). 

278 """ 

279 

280 cipher_state = factory._create_base_cipher(kwargs) 

281 iv = kwargs.pop("IV", None) 

282 IV = kwargs.pop("iv", None) 

283 

284 if (iv, IV) == (None, None): 

285 iv = get_random_bytes(factory.block_size) 

286 if iv is not None: 

287 if IV is not None: 

288 raise TypeError("You must either use 'iv' or 'IV', not both") 

289 else: 

290 iv = IV 

291 

292 if len(iv) != factory.block_size: 

293 raise ValueError("Incorrect IV length (it must be %d bytes long)" % factory.block_size) 

294 

295 if kwargs: 

296 raise TypeError("Unknown parameters for CBC: %s" % str(kwargs)) 

297 

298 return CbcMode(cipher_state, iv)