Crypto++ 8.2 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>
137 void AdditiveCipherTemplate<BASE>::Seek(lword position)
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
AdditiveCipherTemplate::Resynchronize
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
Definition: strciphr.cpp:128
AdditiveCipherAbstractPolicy::CipherSetKey
virtual void CipherSetKey(const NameValuePairs &params, const byte *key, size_t length)=0
Key the cipher.
AdditiveCipherAbstractPolicy::OperateKeystream
virtual void OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
Operates the keystream.
Definition: strciphr.h:149
CipherDir
CipherDir
Specifies a direction for a cipher to operate.
Definition: cryptlib.h:123
CFB_CipherTemplate
Base class for feedback based stream ciphers with SymmetricCipher interface.
Definition: strciphr.h:563
AdditiveCipherAbstractPolicy::CanOperateKeystream
virtual bool CanOperateKeystream() const
Flag indicating.
Definition: strciphr.h:139
AdditiveCipherAbstractPolicy::WriteKeystream
virtual void WriteKeystream(byte *keystream, size_t iterationCount)
Generate the keystream.
Definition: strciphr.h:133
AdditiveCipherTemplate::Seek
void Seek(lword position)
Seeks to a random position in the stream.
Definition: strciphr.cpp:137
AdditiveCipherAbstractPolicy
Policy object for additive stream ciphers.
Definition: strciphr.h:104
IsAlignedOn
bool IsAlignedOn(const void *ptr, unsigned int alignment)
Determines whether ptr is aligned to a minimum value.
Definition: misc.h:1207
AdditiveCipherTemplate::ProcessData
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
Definition: strciphr.cpp:69
CFB_DecryptionTemplate
Base class for feedback based stream ciphers in the reverse direction with SymmetricCipher interface...
Definition: strciphr.h:653
CFB_CipherTemplate::ProcessData
void ProcessData(byte *outString, const byte *inString, size_t length)
Apply keystream to data.
Definition: strciphr.cpp:179
AdditiveCipherAbstractPolicy::GetAlignment
virtual unsigned int GetAlignment() const
Provides data alignment requirements.
Definition: strciphr.h:112
AdditiveCipherAbstractPolicy::GetBytesPerIteration
virtual unsigned int GetBytesPerIteration() const =0
Provides number of bytes operated upon during an iteration.
AdditiveCipherAbstractPolicy::SeekToIteration
virtual void SeekToIteration(lword iterationCount)
Seeks to a random position in the stream.
Definition: strciphr.h:174
pch.h
Precompiled header file.
GetCipherDir
CipherDir GetCipherDir(const T &obj)
Returns the direction the cipher is being operated.
Definition: misc.h:1268
CFB_EncryptionTemplate
Base class for feedback based stream ciphers in the forward direction with SymmetricCipher interface...
Definition: strciphr.h:644
AdditiveCipherTemplate::GenerateBlock
void GenerateBlock(byte *output, size_t size)
Generate random array of bytes.
Definition: strciphr.cpp:34
STDMIN
const T & STDMIN(const T &a, const T &b)
Replacement function for std::min.
Definition: misc.h:635
CRYPTOPP_ASSERT
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition: trap.h:68
strciphr.h
Classes for implementing stream ciphers.
PtrSub
PTR PtrSub(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:397
PtrAdd
PTR PtrAdd(PTR pointer, OFF offset)
Create a pointer with an offset.
Definition: misc.h:384
AdditiveCipherAbstractPolicy::CipherResynchronize
virtual void CipherResynchronize(byte *keystreamBuffer, const byte *iv, size_t length)
Resynchronize the cipher.
Definition: strciphr.h:163
xorbuf
CRYPTOPP_DLL void CRYPTOPP_API xorbuf(byte *buf, const byte *mask, size_t count)
Performs an XOR of a buffer with a mask.
Definition: misc.cpp:46
RoundUpToMultipleOf
T1 RoundUpToMultipleOf(const T1 &n, const T2 &m)
Rounds a value up to a multiple of a second value.
Definition: misc.h:1154
KeystreamOperation
KeystreamOperation
Keystream operation flags.
Definition: strciphr.h:88
CryptoPP
Crypto++ library namespace.
CFB_CipherTemplate::Resynchronize
void Resynchronize(const byte *iv, int length=-1)
Resynchronize the cipher.
Definition: strciphr.cpp:171
AdditiveCipherTemplate
Base class for additive stream ciphers with SymmetricCipher interface.
Definition: strciphr.h:299
NameValuePairs
Interface for retrieving values given their names.
Definition: cryptlib.h:321