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

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

75 statements  

1# =================================================================== 

2# 

3# Copyright (c) 2014, Legrandin <helderijs@gmail.com> 

4# All rights reserved. 

5# 

6# Redistribution and use in source and binary forms, with or without 

7# modification, are permitted provided that the following conditions 

8# are met: 

9# 

10# 1. Redistributions of source code must retain the above copyright 

11# notice, this list of conditions and the following disclaimer. 

12# 2. Redistributions in binary form must reproduce the above copyright 

13# notice, this list of conditions and the following disclaimer in 

14# the documentation and/or other materials provided with the 

15# distribution. 

16# 

17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 

18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 

19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 

20# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 

21# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 

22# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 

23# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 

24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 

25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 

26# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 

27# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 

28# POSSIBILITY OF SUCH DAMAGE. 

29# =================================================================== 

30 

31""" 

32Ciphertext Block Chaining (CBC) mode. 

33""" 

34 

35__all__ = ['CbcMode'] 

36 

37from Crypto.Util.py3compat import _copy_bytes 

38from Crypto.Util._raw_api import (load_pycryptodome_raw_lib, VoidPointer, 

39 create_string_buffer, get_raw_buffer, 

40 SmartPointer, c_size_t, c_uint8_ptr, 

41 is_writeable_buffer) 

42 

43from Crypto.Random import get_random_bytes 

44 

45raw_cbc_lib = load_pycryptodome_raw_lib("Crypto.Cipher._raw_cbc", """ 

46 int CBC_start_operation(void *cipher, 

47 const uint8_t iv[], 

48 size_t iv_len, 

49 void **pResult); 

50 int CBC_encrypt(void *cbcState, 

51 const uint8_t *in, 

52 uint8_t *out, 

53 size_t data_len); 

54 int CBC_decrypt(void *cbcState, 

55 const uint8_t *in, 

56 uint8_t *out, 

57 size_t data_len); 

58 int CBC_stop_operation(void *state); 

59 """ 

60 ) 

61 

62 

63class CbcMode(object): 

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

65 

66 Each of the ciphertext blocks depends on the current 

67 and all previous plaintext blocks. 

68 

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

70 

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

72 

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

74 

75 :undocumented: __init__ 

76 """ 

77 

78 def __init__(self, block_cipher, iv): 

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

80 

81 :Parameters: 

82 block_cipher : C pointer 

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

84 

85 iv : bytes/bytearray/memoryview 

86 The initialization vector to use for encryption or decryption. 

87 It is as long as the cipher block. 

88 

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

90 

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

92 compromises confidentiality. 

93 """ 

94 

95 self._state = VoidPointer() 

96 result = raw_cbc_lib.CBC_start_operation(block_cipher.get(), 

97 c_uint8_ptr(iv), 

98 c_size_t(len(iv)), 

99 self._state.address_of()) 

100 if result: 

101 raise ValueError("Error %d while instantiating the CBC mode" 

102 % result) 

103 

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

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

106 self._state = SmartPointer(self._state.get(), 

107 raw_cbc_lib.CBC_stop_operation) 

108 

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

110 # by the cipher mode 

111 block_cipher.release() 

112 

113 self.block_size = len(iv) 

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

115 

116 self.iv = _copy_bytes(None, None, iv) 

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

118 The value does not change.""" 

119 

120 self.IV = self.iv 

121 """Alias for `iv`""" 

122 

123 self._next = ["encrypt", "decrypt"] 

124 

125 def encrypt(self, plaintext, output=None): 

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

127 

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

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

130 object. 

131 

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

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

134 

135 That is, the statement: 

136 

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

138 

139 is equivalent to: 

140 

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

142 

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

144 or decrypting other data with the same key. 

145 

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

147 

148 :Parameters: 

149 plaintext : bytes/bytearray/memoryview 

150 The piece of data to encrypt. 

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

152 :Keywords: 

153 output : bytearray/memoryview 

154 The location where the ciphertext must be written to. 

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

156 :Return: 

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

158 Otherwise, ``None``. 

159 """ 

160 

161 if "encrypt" not in self._next: 

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

163 self._next = ["encrypt"] 

164 

165 if output is None: 

166 ciphertext = create_string_buffer(len(plaintext)) 

167 else: 

168 ciphertext = output 

169 

170 if not is_writeable_buffer(output): 

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

172 

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

174 raise ValueError("output must have the same length as the input" 

175 " (%d bytes)" % len(plaintext)) 

176 

177 result = raw_cbc_lib.CBC_encrypt(self._state.get(), 

178 c_uint8_ptr(plaintext), 

179 c_uint8_ptr(ciphertext), 

180 c_size_t(len(plaintext))) 

181 if result: 

182 if result == 3: 

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

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

185 

186 if output is None: 

187 return get_raw_buffer(ciphertext) 

188 else: 

189 return None 

190 

191 def decrypt(self, ciphertext, output=None): 

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

193 

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

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

196 object. 

197 

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

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

200 

201 That is, the statement: 

202 

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

204 

205 is equivalent to: 

206 

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

208 

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

210 

211 :Parameters: 

212 ciphertext : bytes/bytearray/memoryview 

213 The piece of data to decrypt. 

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

215 :Keywords: 

216 output : bytearray/memoryview 

217 The location where the plaintext must be written to. 

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

219 :Return: 

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

221 Otherwise, ``None``. 

222 """ 

223 

224 if "decrypt" not in self._next: 

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

226 self._next = ["decrypt"] 

227 

228 if output is None: 

229 plaintext = create_string_buffer(len(ciphertext)) 

230 else: 

231 plaintext = output 

232 

233 if not is_writeable_buffer(output): 

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

235 

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

237 raise ValueError("output must have the same length as the input" 

238 " (%d bytes)" % len(plaintext)) 

239 

240 result = raw_cbc_lib.CBC_decrypt(self._state.get(), 

241 c_uint8_ptr(ciphertext), 

242 c_uint8_ptr(plaintext), 

243 c_size_t(len(ciphertext))) 

244 if result: 

245 if result == 3: 

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

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

248 

249 if output is None: 

250 return get_raw_buffer(plaintext) 

251 else: 

252 return None 

253 

254 

255def _create_cbc_cipher(factory, **kwargs): 

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

257 

258 :Parameters: 

259 factory : module 

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

261 

262 :Keywords: 

263 iv : bytes/bytearray/memoryview 

264 The IV to use for CBC. 

265 

266 IV : bytes/bytearray/memoryview 

267 Alias for ``iv``. 

268 

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

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

271 to be present). 

272 """ 

273 

274 cipher_state = factory._create_base_cipher(kwargs) 

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

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

277 

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

279 iv = get_random_bytes(factory.block_size) 

280 if iv is not None: 

281 if IV is not None: 

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

283 else: 

284 iv = IV 

285 

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

287 raise ValueError("Incorrect IV length (it must be %d bytes long)" % 

288 factory.block_size) 

289 

290 if kwargs: 

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

292 

293 return CbcMode(cipher_state, iv)