Crypto++ 8.2
Free C&
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
11extern const char STRCIPHER_FNAME[] = __FILE__;
12#endif
13
14NAMESPACE_BEGIN(CryptoPP)
15
16template <class S>
17void 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
33template <class S>
34void 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
68template <class S>
69void 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
120template <class S>
121void 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
129template <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
147template <class BASE>
148void 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
163template <class BASE>
164void 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
171template <class BASE>
172void 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
261template <class BASE>
262void 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
268template <class BASE>
269void 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
279NAMESPACE_END
280
281#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.
Definition: strciphr.cpp:69
void Seek(lword position)
Seeks to a random position in the stream.
Definition: strciphr.cpp:130
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
Definition: strciphr.cpp:121
void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: strciphr.cpp:34
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.
Definition: strciphr.cpp:164
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
Definition: strciphr.cpp:172
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:294
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:1085
PTR PtrSub(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:356
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:567
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition: misc.h:1143
PTR PtrAdd(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:343
CipherDir GetCipherDir(const T &obj)
Returns the direction the cipher is being operated.
Definition: misc.h:1204
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:69