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

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

71 statements  

1# 

2# Cipher/mode_ecb.py : ECB mode 

3# 

4# =================================================================== 

5# The contents of this file are dedicated to the public domain. To 

6# the extent that dedication to the public domain is not available, 

7# everyone is granted a worldwide, perpetual, royalty-free, 

8# non-exclusive license to exercise all rights associated with the 

9# contents of this file for any purpose whatsoever. 

10# No rights are reserved. 

11# 

12# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 

13# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 

14# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 

15# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 

16# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 

17# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 

18# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 

19# SOFTWARE. 

20# =================================================================== 

21 

22""" 

23Electronic Code Book (ECB) mode. 

24""" 

25 

26from __future__ import annotations 

27 

28from typing import Any, Optional, Union, overload 

29 

30__all__ = ["EcbMode"] 

31 

32from Crypto.Util._raw_api import ( 

33 SmartPointer, 

34 VoidPointer, 

35 c_size_t, 

36 c_uint8_ptr_len, 

37 c_uint8_ptr_out, 

38 create_output_buffer, 

39 get_raw_buffer, 

40 is_writeable_buffer, 

41 load_pycryptodome_raw_lib, 

42) 

43 

44Buffer = Union[bytes, bytearray, memoryview] 

45 

46raw_ecb_lib = load_pycryptodome_raw_lib( 

47 "Crypto.Cipher._raw_ecb", 

48 """ 

49 int ECB_start_operation(void *cipher, 

50 void **pResult); 

51 int ECB_encrypt(void *ecbState, 

52 const uint8_t *in, 

53 uint8_t *out, 

54 size_t data_len); 

55 int ECB_decrypt(void *ecbState, 

56 const uint8_t *in, 

57 uint8_t *out, 

58 size_t data_len); 

59 int ECB_stop_operation(void *state); 

60 """, 

61) 

62 

63 

64class EcbMode: 

65 """*Electronic Code Book (ECB)*. 

66 

67 This is the simplest encryption mode. Each of the plaintext blocks 

68 is directly encrypted into a ciphertext block, independently of 

69 any other block. 

70 

71 This mode is dangerous because it exposes frequency of symbols 

72 in your plaintext. Other modes (e.g. *CBC*) should be used instead. 

73 

74 See `NIST SP800-38A`_ , Section 6.1. 

75 

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

77 

78 :undocumented: __init__ 

79 """ 

80 

81 def __init__(self, block_cipher: Any) -> None: 

82 """Create a new block cipher, configured in ECB mode. 

83 

84 :Parameters: 

85 block_cipher : C pointer 

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

87 """ 

88 self.block_size = block_cipher.block_size 

89 

90 state = VoidPointer() 

91 result = raw_ecb_lib.ECB_start_operation(block_cipher.get(), state.address_of()) 

92 if result: 

93 raise ValueError("Error %d while instantiating the ECB mode" % result) 

94 

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

96 # free the memory allocated by the raw library for the cipher 

97 # mode 

98 self._state = SmartPointer(state.get(), raw_ecb_lib.ECB_stop_operation) 

99 

100 # Memory allocated for the underlying block cipher is now owned 

101 # by the cipher mode 

102 block_cipher.release() 

103 

104 @overload 

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

106 

107 @overload 

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

109 

110 def encrypt( 

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

112 ) -> Optional[bytes]: 

113 """Encrypt data with the key set at initialization. 

114 

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

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

117 

118 That is, the statement: 

119 

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

121 

122 is equivalent to: 

123 

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

125 

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

127 

128 :Parameters: 

129 plaintext : bytes/bytearray/memoryview 

130 The piece of data to encrypt. 

131 The length must be multiple of the cipher block length. 

132 :Keywords: 

133 output : bytearray/memoryview 

134 The location where the ciphertext must be written to. 

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

136 :Return: 

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

138 Otherwise, ``None``. 

139 """ 

140 

141 if output is None: 

142 ciphertext = create_output_buffer(len(plaintext)) 

143 else: 

144 ciphertext = output 

145 

146 if not is_writeable_buffer(output): 

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

148 

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

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

151 

152 with c_uint8_ptr_out(ciphertext) as ciphertext_ptr: 

153 plaintext_ptr, plaintext_len = c_uint8_ptr_len(plaintext) 

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

155 if len(ciphertext_ptr) != plaintext_len: 

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

157 result = raw_ecb_lib.ECB_encrypt( 

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

159 ) 

160 if result: 

161 if result == 3: 

162 raise ValueError("Data must be aligned to block boundary in ECB mode") 

163 raise ValueError("Error %d while encrypting in ECB mode" % result) 

164 

165 if output is None: 

166 return get_raw_buffer(ciphertext) 

167 else: 

168 return None 

169 

170 @overload 

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

172 

173 @overload 

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

175 

176 def decrypt( 

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

178 ) -> Optional[bytes]: 

179 """Decrypt data with the key set at initialization. 

180 

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

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

183 

184 That is, the statement: 

185 

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

187 

188 is equivalent to: 

189 

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

191 

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

193 

194 :Parameters: 

195 ciphertext : bytes/bytearray/memoryview 

196 The piece of data to decrypt. 

197 The length must be multiple of the cipher block length. 

198 :Keywords: 

199 output : bytearray/memoryview 

200 The location where the plaintext must be written to. 

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

202 :Return: 

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

204 Otherwise, ``None``. 

205 """ 

206 

207 if output is None: 

208 plaintext = create_output_buffer(len(ciphertext)) 

209 else: 

210 plaintext = output 

211 

212 if not is_writeable_buffer(output): 

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

214 

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

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

217 

218 with c_uint8_ptr_out(plaintext) as plaintext_ptr: 

219 ciphertext_ptr, ciphertext_len = c_uint8_ptr_len(ciphertext) 

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

221 if len(plaintext_ptr) != ciphertext_len: 

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

223 result = raw_ecb_lib.ECB_decrypt( 

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

225 ) 

226 if result: 

227 if result == 3: 

228 raise ValueError("Data must be aligned to block boundary in ECB mode") 

229 raise ValueError("Error %d while decrypting in ECB mode" % result) 

230 

231 if output is None: 

232 return get_raw_buffer(plaintext) 

233 else: 

234 return None 

235 

236 

237def _create_ecb_cipher(factory, **kwargs): 

238 """Instantiate a cipher object that performs ECB encryption/decryption. 

239 

240 :Parameters: 

241 factory : module 

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

243 

244 All keywords are passed to the underlying block cipher. 

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

246 to be present""" 

247 

248 cipher_state = factory._create_base_cipher(kwargs) 

249 cipher_state.block_size = factory.block_size 

250 if kwargs: 

251 raise TypeError("Unknown parameters for ECB: %s" % str(kwargs)) 

252 return EcbMode(cipher_state)