Coverage Report

Created: 2024-11-21 07:03

/src/cryptopp/modes.cpp
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 &params)
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