Crypto++  8.0
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  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  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, KeystreamBufferEnd()-m_leftOver, len);
75 
76  length -= len; m_leftOver -= len;
77  inString = PtrAdd(inString, len);
78  outString = PtrAdd(outString, len);
79  }
80 
81  PolicyInterface &policy = this->AccessPolicy();
82  unsigned int bytesPerIteration = policy.GetBytesPerIteration();
83 
84  if (policy.CanOperateKeystream() && length >= bytesPerIteration)
85  {
86  const size_t iterations = length / bytesPerIteration;
87  unsigned int alignment = policy.GetAlignment();
88  KeystreamOperation operation = KeystreamOperation((IsAlignedOn(inString, alignment) * 2) | (int)IsAlignedOn(outString, alignment));
89  policy.OperateKeystream(operation, outString, inString, iterations);
90 
91  inString = PtrAdd(inString, iterations * bytesPerIteration);
92  outString = PtrAdd(outString, iterations * bytesPerIteration);
93  length -= iterations * bytesPerIteration;
94  }
95 
96  size_t bufferByteSize = m_buffer.size();
97  size_t bufferIterations = bufferByteSize / bytesPerIteration;
98 
99  while (length >= bufferByteSize)
100  {
101  policy.WriteKeystream(m_buffer, bufferIterations);
102  xorbuf(outString, inString, KeystreamBufferBegin(), bufferByteSize);
103 
104  length -= bufferByteSize;
105  inString = PtrAdd(inString, bufferByteSize);
106  outString = PtrAdd(outString, bufferByteSize);
107  }
108 
109  if (length > 0)
110  {
111  bufferByteSize = RoundUpToMultipleOf(length, bytesPerIteration);
112  bufferIterations = bufferByteSize / bytesPerIteration;
113 
114  policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bufferByteSize), bufferIterations);
115  xorbuf(outString, inString, PtrSub(KeystreamBufferEnd(), bufferByteSize), length);
116  m_leftOver = bufferByteSize - length;
117  }
118 }
119 
120 template <class S>
121 void AdditiveCipherTemplate<S>::Resynchronize(const byte *iv, int length)
122 {
123  PolicyInterface &policy = this->AccessPolicy();
124  m_leftOver = 0;
125  m_buffer.New(GetBufferByteSize(policy));
126  policy.CipherResynchronize(m_buffer, iv, this->ThrowIfInvalidIVLength(length));
127 }
128 
129 template <class BASE>
131 {
132  PolicyInterface &policy = this->AccessPolicy();
133  word32 bytesPerIteration = policy.GetBytesPerIteration();
134 
135  policy.SeekToIteration(position / bytesPerIteration);
136  position %= bytesPerIteration;
137 
138  if (position > 0)
139  {
140  policy.WriteKeystream(PtrSub(KeystreamBufferEnd(), bytesPerIteration), 1);
141  m_leftOver = bytesPerIteration - static_cast<word32>(position);
142  }
143  else
144  m_leftOver = 0;
145 }
146 
147 template <class BASE>
148 void CFB_CipherTemplate<BASE>::UncheckedSetKey(const byte *key, unsigned int length, const NameValuePairs &params)
149 {
150  PolicyInterface &policy = this->AccessPolicy();
151  policy.CipherSetKey(params, key, length);
152 
153  if (this->IsResynchronizable())
154  {
155  size_t ivLength;
156  const byte *iv = this->GetIVAndThrowIfInvalid(params, ivLength);
157  policy.CipherResynchronize(iv, ivLength);
158  }
159 
160  m_leftOver = policy.GetBytesPerIteration();
161 }
162 
163 template <class BASE>
164 void CFB_CipherTemplate<BASE>::Resynchronize(const byte *iv, int length)
165 {
166  PolicyInterface &policy = this->AccessPolicy();
167  policy.CipherResynchronize(iv, this->ThrowIfInvalidIVLength(length));
168  m_leftOver = policy.GetBytesPerIteration();
169 }
170 
171 template <class BASE>
172 void CFB_CipherTemplate<BASE>::ProcessData(byte *outString, const byte *inString, size_t length)
173 {
174  CRYPTOPP_ASSERT(outString); CRYPTOPP_ASSERT(inString);
175  CRYPTOPP_ASSERT(length % this->MandatoryBlockSize() == 0);
176 
177  PolicyInterface &policy = this->AccessPolicy();
178  word32 bytesPerIteration = policy.GetBytesPerIteration();
179  byte *reg = policy.GetRegisterBegin();
180 
181  if (m_leftOver)
182  {
183  const size_t len = STDMIN(m_leftOver, length);
184  CombineMessageAndShiftRegister(outString, PtrAdd(reg, bytesPerIteration - m_leftOver), inString, len);
185 
186  m_leftOver -= len; length -= len;
187  inString = PtrAdd(inString, len);
188  outString = PtrAdd(outString, len);
189  }
190 
191  // TODO: Figure out what is happening on ARM A-32. x86, Aarch64 and PowerPC are OK.
192  // The issue surfaced for CFB mode when we cut-in Cryptogams AES ARMv7 asm.
193  // Using 'outString' for both input and output leads to incorrect results.
194  //
195  // Benchmarking on Cortex-A7 and Cortex-A9 indicates removing the block
196  // below costs about 9 cpb for CFB mode on ARM.
197  //
198  // Also see https://github.com/weidai11/cryptopp/issues/683.
199  //
200  // UPDATE: It appears the issue is related to alignment checks. When we made
201  // the alignment check result volatile GCC and Clang stopped short-
202  // circuiting the transform, which is what we wanted. I suspect
203  // there's a little more to the issue, but we can enable the block again.
204 
205  const unsigned int alignment = policy.GetAlignment();
206  volatile bool isAligned = IsAlignedOn(outString, alignment);
207  if (policy.CanIterate() && length >= bytesPerIteration && isAligned)
208  {
209  isAligned &= IsAlignedOn(inString, alignment);
210  const CipherDir cipherDir = GetCipherDir(*this);
211  if (isAligned)
212  policy.Iterate(outString, inString, cipherDir, length / bytesPerIteration);
213  else
214  {
215  // GCC and Clang does not like this on ARM. The incorrect result is a string
216  // of 0's instead of ciphertext (or plaintext if decrypting). The 0's trace
217  // back to the allocation for the std::string in datatest.cpp. Elements in the
218  // string are initialized to their default value, which is 0.
219  //
220  // It almost feels as if the compiler does not see the string is transformed
221  // in-place so it short-circuits the transform. However, if we use a stand-alone
222  // reproducer with the same data then the issue is _not_ present.
223  //
224  // When working on this issue we introduced PtrAdd and PtrSub to ensure we were
225  // not running afoul of pointer arithmetic rules of the language. Namely we need
226  // to use ptrdiff_t when subtracting pointers. We believe the relevant code paths
227  // are clean.
228  //
229  // One workaround is a distinct and aligned temporary buffer. It [mostly] works
230  // as expected but requires an extra allocation (casts not shown):
231  //
232  // std::string temp(inString, length);
233  // policy.Iterate(outString, &temp[0], cipherDir, length / bytesPerIteration);
234  //
235  memcpy(outString, inString, length);
236  policy.Iterate(outString, outString, cipherDir, length / bytesPerIteration);
237  }
238  const size_t remainder = length % bytesPerIteration;
239  inString = PtrAdd(inString, length - remainder);
240  outString = PtrAdd(outString, length - remainder);
241  length = remainder;
242  }
243 
244  while (length >= bytesPerIteration)
245  {
246  policy.TransformRegister();
247  CombineMessageAndShiftRegister(outString, reg, inString, bytesPerIteration);
248  length -= bytesPerIteration;
249  inString = PtrAdd(inString, bytesPerIteration);
250  outString = PtrAdd(outString, bytesPerIteration);
251  }
252 
253  if (length > 0)
254  {
255  policy.TransformRegister();
256  CombineMessageAndShiftRegister(outString, reg, inString, length);
257  m_leftOver = bytesPerIteration - length;
258  }
259 }
260 
261 template <class BASE>
262 void CFB_EncryptionTemplate<BASE>::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length)
263 {
264  xorbuf(reg, message, length);
265  memcpy(output, reg, length);
266 }
267 
268 template <class BASE>
269 void CFB_DecryptionTemplate<BASE>::CombineMessageAndShiftRegister(byte *output, byte *reg, const byte *message, size_t length)
270 {
271  for (size_t i=0; i<length; i++)
272  {
273  byte b = message[i];
274  output[i] = reg[i] ^ b;
275  reg[i] = b;
276  }
277 }
278 
279 NAMESPACE_END
280 
281 #endif
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
Definition: strciphr.cpp:121
virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
Operates the keystream.
Definition: strciphr.h:149
CipherDir
Specifies a direction for a cipher to operate.
Definition: cryptlib.h:123
Base class for feedback based stream ciphers with SymmetricCipher interface.
Definition: strciphr.h:563
virtual bool CanOperateKeystream() const
Flag indicating.
Definition: strciphr.h:139
virtual void WriteKeystream(byte *keystream, size_t iterationCount)
Generate the keystream.
Definition: strciphr.h:133
void Seek(lword position)
Seeks to a random position in the stream.
Definition: strciphr.cpp:130
Policy object for additive stream ciphers.
Definition: strciphr.h:104
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition: misc.h:1111
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
Definition: strciphr.cpp:69
Base class for feedback based stream ciphers in the reverse direction with SymmetricCipher interface...
Definition: strciphr.h:653
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
Definition: strciphr.cpp:172
virtual unsigned int GetAlignment() const
Provides data alignment requirements.
Definition: strciphr.h:112
virtual unsigned int GetBytesPerIteration() const =0
Provides number of bytes operated upon during an iteration.
virtual void SeekToIteration(lword iterationCount)
Seeks to a random position in the stream.
Definition: strciphr.h:174
Precompiled header file.
CipherDir GetCipherDir(const T &obj)
Returns the direction the cipher is being operated.
Definition: misc.h:1172
Base class for feedback based stream ciphers in the forward direction with SymmetricCipher interface...
Definition: strciphr.h:644
void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: strciphr.cpp:34
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:535
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:69
Classes for implementing stream ciphers.
PTR PtrSub(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:356
PTR PtrAdd(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:343
void xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Definition: misc.cpp:32
virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
Resynchronize the cipher.
Definition: strciphr.h:163
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1053
KeystreamOperation
Keystream operation flags.
Definition: strciphr.h:88
Crypto++ library namespace.
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
Definition: strciphr.cpp:164
Base class for additive stream ciphers with SymmetricCipher interface.
Definition: strciphr.h:299
Interface for retrieving values given their names.
Definition: cryptlib.h:293