Line | Count | Source (jump to first uncovered line) |
1 | | // modes.cpp - originally written and placed in the public domain by Wei Dai |
2 | | |
3 | | #include "pch.h" |
4 | | |
5 | | #ifndef CRYPTOPP_IMPORTS |
6 | | |
7 | | #include "modes.h" |
8 | | #include "strciphr.h" |
9 | | #include "misc.h" |
10 | | |
11 | | #if defined(CRYPTOPP_DEBUG) |
12 | | #include "des.h" |
13 | | #endif |
14 | | |
15 | | NAMESPACE_BEGIN(CryptoPP) |
16 | | |
17 | | #if defined(CRYPTOPP_DEBUG) && !defined(CRYPTOPP_DOXYGEN_PROCESSING) |
18 | | void Modes_TestInstantiations() |
19 | | { |
20 | | CFB_Mode<DES>::Encryption m0; |
21 | | CFB_Mode<DES>::Decryption m1; |
22 | | OFB_Mode<DES>::Encryption m2; |
23 | | CTR_Mode<DES>::Encryption m3; |
24 | | ECB_Mode<DES>::Encryption m4; |
25 | | CBC_Mode<DES>::Encryption m5; |
26 | | } |
27 | | #endif |
28 | | |
29 | | void CipherModeBase::ResizeBuffers() |
30 | 2.38k | { |
31 | 2.38k | m_register.New(m_cipher->BlockSize()); |
32 | 2.38k | } |
33 | | |
34 | | void CFB_ModePolicy::Iterate(byte *output, const byte *input, CipherDir dir, size_t iterationCount) |
35 | 246 | { |
36 | 246 | CRYPTOPP_ASSERT(input); CRYPTOPP_ASSERT(output); |
37 | 246 | CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); |
38 | 246 | CRYPTOPP_ASSERT(m_register.size() == BlockSize()); |
39 | 246 | CRYPTOPP_ASSERT(m_temp.size() == BlockSize()); |
40 | 246 | CRYPTOPP_ASSERT(iterationCount > 0); |
41 | | |
42 | 246 | const unsigned int s = BlockSize(); |
43 | 246 | if (dir == ENCRYPTION) |
44 | 200 | { |
45 | 200 | m_cipher->ProcessAndXorBlock(m_register, input, output); |
46 | 200 | if (iterationCount > 1) |
47 | 151 | m_cipher->AdvancedProcessBlocks(output, PtrAdd(input,s), PtrAdd(output,s), (iterationCount-1)*s, 0); |
48 | 200 | std::memcpy(m_register, PtrAdd(output,(iterationCount-1)*s), s); |
49 | 200 | } |
50 | 46 | else |
51 | 46 | { |
52 | | // make copy first in case of in-place decryption |
53 | 46 | std::memcpy(m_temp, PtrAdd(input,(iterationCount-1)*s), s); |
54 | 46 | if (iterationCount > 1) |
55 | 12 | m_cipher->AdvancedProcessBlocks(input, PtrAdd(input,s), PtrAdd(output,s), (iterationCount-1)*s, BlockTransformation::BT_ReverseDirection); |
56 | 46 | m_cipher->ProcessAndXorBlock(m_register, input, output); |
57 | 46 | std::memcpy(m_register, m_temp, s); |
58 | 46 | } |
59 | 246 | } |
60 | | |
61 | | void CFB_ModePolicy::TransformRegister() |
62 | 871 | { |
63 | 871 | CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); |
64 | 871 | CRYPTOPP_ASSERT(m_register.size() == BlockSize()); |
65 | 871 | CRYPTOPP_ASSERT(m_temp.size() == BlockSize()); |
66 | | |
67 | 871 | const ptrdiff_t updateSize = BlockSize()-m_feedbackSize; |
68 | 871 | m_cipher->ProcessBlock(m_register, m_temp); |
69 | 871 | memmove_s(m_register, m_register.size(), PtrAdd(m_register.begin(),m_feedbackSize), updateSize); |
70 | 871 | memcpy_s(PtrAdd(m_register.begin(),updateSize), m_register.size()-updateSize, m_temp, m_feedbackSize); |
71 | 871 | } |
72 | | |
73 | | void CFB_ModePolicy::CipherResynchronize(const byte *iv, size_t length) |
74 | 307 | { |
75 | 307 | CRYPTOPP_ASSERT(length == BlockSize()); |
76 | 307 | CRYPTOPP_ASSERT(m_register.size() == BlockSize()); |
77 | | |
78 | 307 | CopyOrZero(m_register, m_register.size(), iv, length); |
79 | 307 | TransformRegister(); |
80 | 307 | } |
81 | | |
82 | | void CFB_ModePolicy::SetFeedbackSize(unsigned int feedbackSize) |
83 | 307 | { |
84 | 307 | CRYPTOPP_ASSERT(feedbackSize <= BlockSize()); |
85 | 307 | if (feedbackSize > BlockSize()) |
86 | 0 | throw InvalidArgument("CFB_Mode: invalid feedback size"); |
87 | 307 | m_feedbackSize = feedbackSize ? feedbackSize : BlockSize(); |
88 | 307 | } |
89 | | |
90 | | void CFB_ModePolicy::ResizeBuffers() |
91 | 671 | { |
92 | 671 | CipherModeBase::ResizeBuffers(); |
93 | 671 | m_temp.New(BlockSize()); |
94 | 671 | } |
95 | | |
96 | | byte* CFB_ModePolicy::GetRegisterBegin() |
97 | 520 | { |
98 | 520 | CRYPTOPP_ASSERT(!m_register.empty()); |
99 | 520 | CRYPTOPP_ASSERT(BlockSize() >= m_feedbackSize); |
100 | 520 | return PtrAdd(m_register.begin(), BlockSize() - m_feedbackSize); |
101 | 520 | } |
102 | | |
103 | | void OFB_ModePolicy::WriteKeystream(byte *keystreamBuffer, size_t iterationCount) |
104 | 92 | { |
105 | 92 | CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); |
106 | 92 | CRYPTOPP_ASSERT(m_register.size() == BlockSize()); |
107 | 92 | CRYPTOPP_ASSERT(iterationCount > 0); |
108 | | |
109 | 92 | const unsigned int s = BlockSize(); |
110 | 92 | m_cipher->ProcessBlock(m_register, keystreamBuffer); |
111 | 92 | if (iterationCount > 1) |
112 | 56 | m_cipher->AdvancedProcessBlocks(keystreamBuffer, NULLPTR, PtrAdd(keystreamBuffer, s), s*(iterationCount-1), 0); |
113 | 92 | std::memcpy(m_register, PtrAdd(keystreamBuffer, (iterationCount-1)*s), s); |
114 | 92 | } |
115 | | |
116 | | void OFB_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) |
117 | 41 | { |
118 | 41 | CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); |
119 | 41 | CRYPTOPP_ASSERT(m_register.size() == BlockSize()); |
120 | 41 | CRYPTOPP_ASSERT(length == BlockSize()); |
121 | | |
122 | 41 | CopyOrZero(m_register, m_register.size(), iv, length); |
123 | 41 | } |
124 | | |
125 | | void CTR_ModePolicy::SeekToIteration(lword iterationCount) |
126 | 120 | { |
127 | 120 | int carry=0; |
128 | 2.04k | for (int i=BlockSize()-1; i>=0; i--) |
129 | 1.92k | { |
130 | 1.92k | unsigned int sum = m_register[i] + (byte)iterationCount + carry; |
131 | 1.92k | m_counterArray[i] = byte(sum & 0xff); |
132 | 1.92k | carry = sum >> 8; |
133 | 1.92k | iterationCount >>= 8; |
134 | 1.92k | } |
135 | 120 | } |
136 | | |
137 | | void CTR_ModePolicy::IncrementCounterBy256() |
138 | 0 | { |
139 | 0 | IncrementCounterByOne(m_counterArray, BlockSize()-1); |
140 | 0 | } |
141 | | |
142 | | void CTR_ModePolicy::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount) |
143 | 193 | { |
144 | 193 | CRYPTOPP_ASSERT(output); |
145 | | // CRYPTOPP_ASSERT(input); // input is sometimes NULL |
146 | 193 | CRYPTOPP_ASSERT(m_cipher->IsForwardTransformation()); |
147 | 193 | CRYPTOPP_ASSERT(m_counterArray.size() == BlockSize()); |
148 | 193 | CRYPTOPP_UNUSED(operation); |
149 | | |
150 | 193 | const size_t s = BlockSize(); |
151 | | |
152 | 450 | while (iterationCount) |
153 | 257 | { |
154 | 257 | const byte lsb = m_counterArray[s-1]; |
155 | 257 | const size_t blocks = UnsignedMin(iterationCount, 256u-lsb); |
156 | 257 | const size_t outIncrement = output ? blocks*s : 0; |
157 | 257 | const size_t inIncrement = input ? blocks*s : 0; |
158 | | |
159 | 257 | m_cipher->AdvancedProcessBlocks(m_counterArray, input, output, blocks*s, BlockTransformation::BT_InBlockIsCounter|BlockTransformation::BT_AllowParallel); |
160 | 257 | if ((m_counterArray[s-1] = static_cast<byte>(lsb + blocks)) == 0) |
161 | 64 | IncrementCounterBy256(); |
162 | | |
163 | 257 | output = PtrAdd(output, outIncrement); |
164 | 257 | input = PtrAdd(input, inIncrement); |
165 | 257 | iterationCount -= blocks; |
166 | 257 | } |
167 | 193 | } |
168 | | |
169 | | void CTR_ModePolicy::CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length) |
170 | 78 | { |
171 | 78 | CRYPTOPP_UNUSED(keystreamBuffer), CRYPTOPP_UNUSED(length); |
172 | 78 | CRYPTOPP_ASSERT(m_register.size() == BlockSize()); |
173 | 78 | CRYPTOPP_ASSERT(length == BlockSize()); |
174 | | |
175 | 78 | CopyOrZero(m_register, m_register.size(), iv, length); |
176 | 78 | m_counterArray.Assign(m_register.begin(), m_register.size()); |
177 | 78 | } |
178 | | |
179 | | void BlockOrientedCipherModeBase::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs ¶ms) |
180 | 183 | { |
181 | 183 | m_cipher->SetKey(key, length, params); |
182 | 183 | ResizeBuffers(); |
183 | 183 | if (IsResynchronizable()) |
184 | 183 | { |
185 | 183 | size_t ivLength; |
186 | 183 | const byte *iv = GetIVAndThrowIfInvalid(params, ivLength); |
187 | 183 | Resynchronize(iv, (int)ivLength); |
188 | 183 | } |
189 | 183 | } |
190 | | |
191 | | void BlockOrientedCipherModeBase::ResizeBuffers() |
192 | 1.17k | { |
193 | 1.17k | CipherModeBase::ResizeBuffers(); |
194 | 1.17k | m_buffer.New(BlockSize()); |
195 | 1.17k | } |
196 | | |
197 | | void ECB_OneWay::ProcessData(byte *outString, const byte *inString, size_t length) |
198 | 594 | { |
199 | 594 | CRYPTOPP_ASSERT(length%BlockSize()==0); |
200 | 594 | m_cipher->AdvancedProcessBlocks(inString, NULLPTR, outString, length, BlockTransformation::BT_AllowParallel); |
201 | 594 | } |
202 | | |
203 | | void CBC_Encryption::ProcessData(byte *outString, const byte *inString, size_t length) |
204 | 105 | { |
205 | 105 | CRYPTOPP_ASSERT(length%BlockSize()==0); |
206 | 105 | CRYPTOPP_ASSERT(m_register.size() == BlockSize()); |
207 | 105 | if (!length) return; |
208 | | |
209 | 105 | const unsigned int blockSize = BlockSize(); |
210 | 105 | m_cipher->AdvancedProcessBlocks(inString, m_register, outString, blockSize, BlockTransformation::BT_XorInput); |
211 | 105 | if (length > blockSize) |
212 | 11 | m_cipher->AdvancedProcessBlocks(PtrAdd(inString,blockSize), outString, PtrAdd(outString,blockSize), length-blockSize, BlockTransformation::BT_XorInput); |
213 | 105 | std::memcpy(m_register, PtrAdd(outString, length - blockSize), blockSize); |
214 | 105 | } |
215 | | |
216 | | size_t CBC_CTS_Encryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) |
217 | 0 | { |
218 | 0 | CRYPTOPP_UNUSED(outLength); |
219 | 0 | const size_t used = inLength; |
220 | 0 | const unsigned int blockSize = BlockSize(); |
221 | |
|
222 | 0 | if (inLength <= blockSize) |
223 | 0 | { |
224 | 0 | if (!m_stolenIV) |
225 | 0 | throw InvalidArgument("CBC_Encryption: message is too short for ciphertext stealing"); |
226 | | |
227 | | // steal from IV |
228 | 0 | std::memcpy(outString, m_register, inLength); |
229 | 0 | outString = m_stolenIV; |
230 | 0 | } |
231 | 0 | else |
232 | 0 | { |
233 | | // steal from next to last block |
234 | 0 | xorbuf(m_register, inString, blockSize); |
235 | 0 | m_cipher->ProcessBlock(m_register); |
236 | 0 | inString = PtrAdd(inString, blockSize); |
237 | 0 | inLength -= blockSize; |
238 | 0 | std::memcpy(PtrAdd(outString, blockSize), m_register, inLength); |
239 | 0 | } |
240 | | |
241 | | // output last full ciphertext block |
242 | 0 | xorbuf(m_register, inString, inLength); |
243 | 0 | m_cipher->ProcessBlock(m_register); |
244 | 0 | std::memcpy(outString, m_register, blockSize); |
245 | |
|
246 | 0 | return used; |
247 | 0 | } |
248 | | |
249 | | void CBC_Decryption::ResizeBuffers() |
250 | 319 | { |
251 | 319 | BlockOrientedCipherModeBase::ResizeBuffers(); |
252 | 319 | m_temp.New(BlockSize()); |
253 | 319 | } |
254 | | |
255 | | void CBC_Decryption::ProcessData(byte *outString, const byte *inString, size_t length) |
256 | 124 | { |
257 | 124 | CRYPTOPP_ASSERT(length%BlockSize()==0); |
258 | 124 | if (!length) {return;} |
259 | | |
260 | | // save copy now in case of in-place decryption |
261 | 124 | const unsigned int blockSize = BlockSize(); |
262 | 124 | std::memcpy(m_temp, PtrAdd(inString, length-blockSize), blockSize); |
263 | 124 | if (length > blockSize) |
264 | 10 | m_cipher->AdvancedProcessBlocks(PtrAdd(inString,blockSize), inString, PtrAdd(outString,blockSize), length-blockSize, BlockTransformation::BT_ReverseDirection|BlockTransformation::BT_AllowParallel); |
265 | 124 | m_cipher->ProcessAndXorBlock(inString, m_register, outString); |
266 | 124 | m_register.swap(m_temp); |
267 | 124 | } |
268 | | |
269 | | size_t CBC_CTS_Decryption::ProcessLastBlock(byte *outString, size_t outLength, const byte *inString, size_t inLength) |
270 | 0 | { |
271 | 0 | CRYPTOPP_UNUSED(outLength); |
272 | 0 | const byte *pn1, *pn2; |
273 | 0 | const size_t used = inLength; |
274 | 0 | const bool stealIV = inLength <= BlockSize(); |
275 | 0 | const unsigned int blockSize = BlockSize(); |
276 | |
|
277 | 0 | if (stealIV) |
278 | 0 | { |
279 | 0 | pn1 = inString; |
280 | 0 | pn2 = m_register; |
281 | 0 | } |
282 | 0 | else |
283 | 0 | { |
284 | 0 | pn1 = PtrAdd(inString, blockSize); |
285 | 0 | pn2 = inString; |
286 | 0 | inLength -= blockSize; |
287 | 0 | } |
288 | | |
289 | | // decrypt last partial plaintext block |
290 | 0 | std::memcpy(m_temp, pn2, blockSize); |
291 | 0 | m_cipher->ProcessBlock(m_temp); |
292 | 0 | xorbuf(m_temp, pn1, inLength); |
293 | |
|
294 | 0 | if (stealIV) |
295 | 0 | { |
296 | 0 | std::memcpy(outString, m_temp, inLength); |
297 | 0 | } |
298 | 0 | else |
299 | 0 | { |
300 | 0 | std::memcpy(PtrAdd(outString, blockSize), m_temp, inLength); |
301 | | // decrypt next to last plaintext block |
302 | 0 | std::memcpy(m_temp, pn1, inLength); |
303 | 0 | m_cipher->ProcessBlock(m_temp); |
304 | 0 | xorbuf(outString, m_temp, m_register, blockSize); |
305 | 0 | } |
306 | |
|
307 | 0 | return used; |
308 | 0 | } |
309 | | |
310 | | NAMESPACE_END |
311 | | |
312 | | #endif |