Crypto++  8.5
Free C++ class library of cryptographic schemes
strciphr.cpp
1 // strciphr.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 "strciphr.h"
8 
9 // Squash MS LNK4221 and libtool warnings
10 #ifndef CRYPTOPP_MANUALLY_INSTANTIATE_TEMPLATES
11 extern const char STRCIPHER_FNAME[] = __FILE__;
12 #endif
13 
14 NAMESPACE_BEGIN(CryptoPP)
15 
16 template <class S>
17 void AdditiveCipherTemplate<S>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
18 {
19  PolicyInterface &policy = this->AccessPolicy();
20  policy.CipherSetKey(params, key, length);
21  m_leftOver = 0;
22  unsigned int bufferByteSize = policy.CanOperateKeystream() ? GetBufferByteSize(policy) : RoundUpToMultipleOf(1024U, GetBufferByteSize(policy));
23  m_buffer.New(bufferByteSize);
24 
25  if (this->IsResynchronizable())
26  {
27  size_t ivLength;
28  const byte *iv = this->GetIVAndThrowIfInvalid(params, ivLength);
29  policy.CipherResynchronize(m_buffer, iv, ivLength);
30  }
31 }
32 
33 template <class S>
34 void AdditiveCipherTemplate<S>::GenerateBlock(byte *outString, size_t length)
35 {
36  if (m_leftOver > 0)
37  {
38  const size_t len = STDMIN(m_leftOver, length);
39  std::memcpy(outString, PtrSub(KeystreamBufferEnd(), m_leftOver), len);
40 
41  length -= len; m_leftOver -= len;
42  outString = PtrAdd(outString, len);
43  if (!length) {return;}
44  }
45 
46  PolicyInterface &policy = this->AccessPolicy();
47  unsigned int bytesPerIteration = policy.GetBytesPerIteration();
48 
49  if (length >= bytesPerIteration)
50  {
51  const size_t iterations = length / bytesPerIteration;
52  policy.WriteKeystream(outString, iterations);
53  length -= iterations * bytesPerIteration;
54  outString = PtrAdd(outString, iterations * bytesPerIteration);
55  }
56 
57  if (length > 0)
58  {
59  size_t bufferByteSize = RoundUpToMultipleOf(length, bytesPerIteration);
60  size_t bufferIterations = bufferByteSize / bytesPerIteration;
61 
62  policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bufferByteSize), bufferIterations);
63  std::memcpy(outString, PtrSub(KeystreamBufferEnd(), bufferByteSize), length);
64  m_leftOver = bufferByteSize - length;
65  }
66 }
67 
68 template <class S>
69 void AdditiveCipherTemplate<S>::ProcessData(byte *outString, const byte *inString, size_t length)
70 {
71  if (m_leftOver > 0)
72  {
73  const size_t len = STDMIN(m_leftOver, length);
74  xorbuf(outString, inString, PtrSub(KeystreamBufferEnd(), m_leftOver), len);
75 
76  length -= len; m_leftOver -= len;
77  inString = PtrAdd(inString, len);
78  outString = PtrAdd(outString, len);
79 
80  if (!length) {return;}
81  }
82 
83  PolicyInterface &policy = this->AccessPolicy();
84  unsigned int bytesPerIteration = policy.GetBytesPerIteration();
85 
86  if (policy.CanOperateKeystream() && length >= bytesPerIteration)
87  {
88  const size_t iterations = length / bytesPerIteration;
89  unsigned int alignment = policy.GetAlignment();
90  volatile int inAligned = IsAlignedOn(inString, alignment) << 1;
91  volatile int outAligned = IsAlignedOn(outString, alignment) << 0;
92 
93  KeystreamOperation operation = KeystreamOperation(inAligned | outAligned);
94  policy.OperateKeystream(operation, outString, inString, iterations);
95 
96  inString = PtrAdd(inString, iterations * bytesPerIteration);
97  outString = PtrAdd(outString, iterations * bytesPerIteration);
98  length -= iterations * bytesPerIteration;
99 
100  if (!length) {return;}
101  }
102 
103  size_t bufferByteSize = m_buffer.size();
104  size_t bufferIterations = bufferByteSize / bytesPerIteration;
105 
106  while (length >= bufferByteSize)
107  {
108  policy.WriteKeystream(m_buffer, bufferIterations);
109  xorbuf(outString, inString, KeystreamBufferBegin(), bufferByteSize);
110 
111  length -= bufferByteSize;
112  inString = PtrAdd(inString, bufferByteSize);
113  outString = PtrAdd(outString, bufferByteSize);
114  }
115 
116  if (length > 0)
117  {
118  bufferByteSize = RoundUpToMultipleOf(length, bytesPerIteration);
119  bufferIterations = bufferByteSize / bytesPerIteration;
120 
121  policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bufferByteSize), bufferIterations);
122  xorbuf(outString, inString, PtrSub(KeystreamBufferEnd(), bufferByteSize), length);
123  m_leftOver = bufferByteSize - length;
124  }
125 }
126 
127 template <class S>
128 void AdditiveCipherTemplate<S>::Resynchronize(const byte *iv, int length)
129 {
130  PolicyInterface &policy = this->AccessPolicy();
131  m_leftOver = 0;
132  m_buffer.New(GetBufferByteSize(policy));
133  policy.CipherResynchronize(m_buffer, iv, this->ThrowIfInvalidIVLength(length));
134 }
135 
136 template <class BASE>
138 {
139  PolicyInterface &policy = this->AccessPolicy();
140  word32 bytesPerIteration = policy.GetBytesPerIteration();
141 
142  policy.SeekToIteration(position / bytesPerIteration);
143  position %= bytesPerIteration;
144 
145  if (position > 0)
146  {
147  policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bytesPerIteration), 1);
148  m_leftOver = bytesPerIteration - static_cast<word32>(position);
149  }
150  else
151  m_leftOver = 0;
152 }
153 
154 template <class BASE>
155 void CFB_CipherTemplate<BASE>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
156 {
157  PolicyInterface &policy = this->AccessPolicy();
158  policy.CipherSetKey(params, key, length);
159 
160  if (this->IsResynchronizable())
161  {
162  size_t ivLength;
163  const byte *iv = this->GetIVAndThrowIfInvalid(params, ivLength);
164  policy.CipherResynchronize(iv, ivLength);
165  }
166 
167  m_leftOver = policy.GetBytesPerIteration();
168 }
169 
170 template <class BASE>
171 void CFB_CipherTemplate<BASE>::Resynchronize(const byte *iv, int length)
172 {
173  PolicyInterface &policy = this->AccessPolicy();
174  policy.CipherResynchronize(iv, this->ThrowIfInvalidIVLength(length));
175  m_leftOver = policy.GetBytesPerIteration();
176 }
177 
178 template <class BASE>
179 void CFB_CipherTemplate<BASE>::ProcessData(byte *outString, const byte *inString, size_t length)
180 {
181  CRYPTOPP_ASSERT(outString); CRYPTOPP_ASSERT(inString);
182  CRYPTOPP_ASSERT(length % this->MandatoryBlockSize() == 0);
183 
184  PolicyInterface &policy = this->AccessPolicy();
185  word32 bytesPerIteration = policy.GetBytesPerIteration();
186  byte *reg = policy.GetRegisterBegin();
187 
188  if (m_leftOver)
189  {
190  const size_t len = STDMIN(m_leftOver, length);
191  CombineMessageAndShiftRegister(outString, PtrAdd(reg, bytesPerIteration - m_leftOver), inString, len);
192 
193  m_leftOver -= len; length -= len;
194  inString = PtrAdd(inString, len);
195  outString = PtrAdd(outString, len);
196  }
197 
198  if (!length) {return;}
199 
200  // TODO: Figure out what is happening on ARM A-32. x86, Aarch64 and PowerPC are OK.
201  // The issue surfaced for CFB mode when we cut-in Cryptogams AES ARMv7 asm.
202  // Using 'outString' for both input and output leads to incorrect results.
203  //
204  // Benchmarking on Cortex-A7 and Cortex-A9 indicates removing the block
205  // below costs about 9 cpb for CFB mode on ARM.
206  //
207  // Also see https://github.com/weidai11/cryptopp/issues/683.
208 
209  const unsigned int alignment = policy.GetAlignment();
210  volatile bool inAligned = IsAlignedOn(inString, alignment);
211  volatile bool outAligned = IsAlignedOn(outString, alignment);
212 
213  if (policy.CanIterate() && length >= bytesPerIteration && outAligned)
214  {
215  CipherDir cipherDir = GetCipherDir(*this);
216  if (inAligned)
217  policy.Iterate(outString, inString, cipherDir, length / bytesPerIteration);
218  else
219  {
220  // GCC and Clang do not like this on ARM. The incorrect result is a string
221  // of 0's instead of ciphertext (or plaintext if decrypting). The 0's trace
222  // back to the allocation for the std::string in datatest.cpp. Elements in the
223  // string are initialized to their default value, which is 0.
224  //
225  // It almost feels as if the compiler does not see the string is transformed
226  // in-place so it short-circuits the transform. However, if we use a stand-alone
227  // reproducer with the same data then the issue is _not_ present.
228  //
229  // When working on this issue we introduced PtrAdd and PtrSub to ensure we were
230  // not running afoul of pointer arithmetic rules of the language. Namely we need
231  // to use ptrdiff_t when subtracting pointers. We believe the relevant code paths
232  // are clean.
233  //
234  // One workaround is a distinct and aligned temporary buffer. It [mostly] works
235  // as expected but requires an extra allocation (casts not shown):
236  //
237  // std::string temp(inString, length);
238  // policy.Iterate(outString, &temp[0], cipherDir, length / bytesPerIteration);
239 
240  std::memcpy(outString, inString, length);
241  policy.Iterate(outString, outString, cipherDir, length / bytesPerIteration);
242  }
243  const size_t remainder = length % bytesPerIteration;
244  inString = PtrAdd(inString, length - remainder);
245  outString = PtrAdd(outString, length - remainder);
246  length = remainder;
247  }
248 
249  while (length >= bytesPerIteration)
250  {
251  policy.TransformRegister();
252  CombineMessageAndShiftRegister(outString, reg, inString, bytesPerIteration);
253  length -= bytesPerIteration;
254  inString = PtrAdd(inString, bytesPerIteration);
255  outString = PtrAdd(outString, bytesPerIteration);
256  }
257 
258  if (length > 0)
259  {
260  policy.TransformRegister();
261  CombineMessageAndShiftRegister(outString, reg, inString, length);
262  m_leftOver = bytesPerIteration - length;
263  }
264 }
265 
266 template <class BASE>
267 void CFB_EncryptionTemplate<BASE>::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length)
268 {
269  xorbuf(reg, message, length);
270  std::memcpy(output, reg, length);
271 }
272 
273 template <class BASE>
274 void CFB_DecryptionTemplate<BASE>::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length)
275 {
276  for (size_t i=0; i<length; i++)
277  {
278  byte b = message[i];
279  output[i] = reg[i] ^ b;
280  reg[i] = b;
281  }
282 }
283 
284 NAMESPACE_END
285 
286 #endif
Base class for additive stream ciphers with SymmetricCipher interface.
Definition: strciphr.h:300
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
void Seek(lword position)
Seeks to a random position in the stream.
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
Base class for feedback based stream ciphers with SymmetricCipher interface.
Definition: strciphr.h:564
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
Base class for feedback based stream ciphers in the reverse direction with SymmetricCipher interface.
Definition: strciphr.h:654
Base class for feedback based stream ciphers in the forward direction with SymmetricCipher interface.
Definition: strciphr.h:645
Interface for retrieving values given their names.
Definition: cryptlib.h:322
unsigned int word32
32-bit unsigned datatype
Definition: config_int.h:62
word64 lword
Large word type.
Definition: config_int.h:158
CipherDir
Specifies a direction for a cipher to operate.
Definition: cryptlib.h:123
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1154
PTR PtrSub(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:397
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition: misc.h:1206
PTR PtrAdd(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:384
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:635
CipherDir GetCipherDir(const T &obj)
Returns the direction the cipher is being operated.
Definition: misc.h:1267
CRYPTOPP_DLL void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Crypto++ library namespace.
Precompiled header file.
Classes for implementing stream ciphers.
KeystreamOperation
Keystream operation flags.
Definition: strciphr.h:88
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68