Crypto++ 8.9
Free C++ class library of cryptographic schemes
misc.cpp
1// misc.cpp - originally written and placed in the public domain by Wei Dai
2
3#include "pch.h"
4#include "config.h"
5
6#if CRYPTOPP_MSC_VERSION
7# pragma warning(disable: 4189)
8# if (CRYPTOPP_MSC_VERSION >= 1400)
9# pragma warning(disable: 6237)
10# endif
11#endif
12
13#ifndef CRYPTOPP_IMPORTS
14
15#include "misc.h"
16#include "trap.h"
17#include "words.h"
18#include "stdcpp.h"
19#include "integer.h"
20#include "secblock.h"
21
22// Hack for OpenBSD and GCC 4.2.1. I believe they are stuck at 4.2.1 due to GPLv3.
23#if defined(__OpenBSD__)
24# if defined (CRYPTOPP_GCC_VERSION) && (CRYPTOPP_GCC_VERSION < 43000)
25# undef CRYPTOPP_DISABLE_ASM
26# define CRYPTOPP_DISABLE_ASM 1
27# endif
28#endif
29
30#ifndef CRYPTOPP_DISABLE_ASM
31# if defined(__SSE2__)
32# include <emmintrin.h>
33# endif
34# if defined(__AVX__)
35# include <immintrin.h>
36# endif
37
38# if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64)
39# if (CRYPTOPP_ARM_NEON_HEADER) || (CRYPTOPP_ARM_ASIMD_AVAILABLE)
40# include <arm_neon.h>
41# endif
42# endif
43#endif // CRYPTOPP_DISABLE_ASM
44
45NAMESPACE_BEGIN(CryptoPP)
46
47byte* BytePtr(SecByteBlock& str)
48{
49 // Caller wants a writeable pointer
50 CRYPTOPP_ASSERT(str.empty() == false);
51
52 if (str.empty())
53 return NULLPTR;
54 return reinterpret_cast<byte*>(str.data());
55}
56
57const byte* ConstBytePtr(const SecByteBlock& str)
58{
59 if (str.empty())
60 return NULLPTR;
61 return reinterpret_cast<const byte*>(str.data());
62}
63
64size_t BytePtrSize(const SecByteBlock& str)
65{
66 return str.size();
67}
68
69// xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020
70void xorbuf(byte *buf, const byte *mask, size_t count)
71{
72 CRYPTOPP_ASSERT(buf != NULLPTR);
73 CRYPTOPP_ASSERT(mask != NULLPTR);
74 CRYPTOPP_ASSERT(count > 0);
75
76#ifndef CRYPTOPP_DISABLE_ASM
77# if defined(__AVX__)
78 while (count >= 32)
79 {
80 __m256i b = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(buf));
81 __m256i m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mask));
82 _mm256_storeu_si256(reinterpret_cast<__m256i*>(buf), _mm256_castps_si256(
83 _mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m))));
84 buf += 32; mask += 32; count -= 32;
85 }
86 // https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties
87 _mm256_zeroupper();
88# endif
89# if defined(__SSE2__)
90 while (count >= 16)
91 {
92 __m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(buf));
93 __m128i m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(mask));
94 _mm_storeu_si128(reinterpret_cast<__m128i*>(buf), _mm_castps_si128(
95 _mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m))));
96 buf += 16; mask += 16; count -= 16;
97 }
98# endif
99# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
100 while (count >= 16)
101 {
102 vst1q_u8(buf, veorq_u8(vld1q_u8(buf), vld1q_u8(mask)));
103 buf += 16; mask += 16; count -= 16;
104 }
105# endif
106#endif // CRYPTOPP_DISABLE_ASM
107
108#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
109 // word64 and stride of 8 slows things down on x86_64.
110 // word64 and stride of 8 makes no difference on ARM.
111 // word64 and stride of 16 benefits PowerPC.
112 while (count >= 16)
113 {
114 word64 r[2], b[2], m[2];
115 std::memcpy(&b, buf, 16); std::memcpy(&m, mask, 16);
116
117 r[0] = b[0] ^ m[0];
118 r[1] = b[1] ^ m[1];
119 std::memcpy(buf, &r, 16);
120
121 buf += 16; mask += 16; count -= 16;
122 }
123#endif
124
125 // One of the arch specific xor's may have cleared the request
126 if (count == 0) return;
127
128 while (count >= 4)
129 {
130 word32 r, b, m;
131 std::memcpy(&b, buf, 4); std::memcpy(&m, mask, 4);
132
133 r = b ^ m;
134 std::memcpy(buf, &r, 4);
135
136 buf += 4; mask += 4; count -= 4;
137 }
138
139 for (size_t i=0; i<count; i++)
140 buf[i] ^= mask[i];
141}
142
143// xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020
144void xorbuf(byte *output, const byte *input, const byte *mask, size_t count)
145{
146 CRYPTOPP_ASSERT(output != NULLPTR);
147 CRYPTOPP_ASSERT(input != NULLPTR);
148 CRYPTOPP_ASSERT(count > 0);
149
150#ifndef CRYPTOPP_DISABLE_ASM
151# if defined(__AVX__)
152 while (count >= 32)
153 {
154 __m256i b = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(input));
155 __m256i m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(mask));
156 _mm256_storeu_si256(reinterpret_cast<__m256i*>(output), _mm256_castps_si256(
157 _mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m))));
158 output += 32; input += 32; mask += 32; count -= 32;
159 }
160 // https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties
161 _mm256_zeroupper();
162# endif
163# if defined(__SSE2__)
164 while (count >= 16)
165 {
166 __m128i b = _mm_loadu_si128(reinterpret_cast<const __m128i*>(input));
167 __m128i m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(mask));
168 _mm_storeu_si128(reinterpret_cast<__m128i*>(output), _mm_castps_si128(
169 _mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m))));
170 output += 16; input += 16; mask += 16; count -= 16;
171 }
172# endif
173# if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64)
174 while (count >= 16)
175 {
176 vst1q_u8(output, veorq_u8(vld1q_u8(input), vld1q_u8(mask)));
177 output += 16; input += 16; mask += 16; count -= 16;
178 }
179# endif
180#endif // CRYPTOPP_DISABLE_ASM
181
182#if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64
183 // word64 and stride of 8 slows things down on x86_64.
184 // word64 and stride of 8 makes no difference on ARM.
185 // word64 and stride of 16 benefits PowerPC.
186 while (count >= 16)
187 {
188 word64 b[2], m[2], r[2];
189 std::memcpy(&b, input, 16); std::memcpy(&m, mask, 16);
190
191 r[0] = b[0] ^ m[0];
192 r[1] = b[1] ^ m[1];
193 std::memcpy(output, &r, 16);
194
195 output += 16; input += 16; mask += 16; count -= 16;
196 }
197#endif
198
199 // One of the arch specific xor's may have cleared the request
200 if (count == 0) return;
201
202 while (count >= 4)
203 {
204 word32 b, m, r;
205 std::memcpy(&b, input, 4); std::memcpy(&m, mask, 4);
206
207 r = b ^ m;
208 std::memcpy(output, &r, 4);
209
210 output += 4; input += 4; mask += 4; count -= 4;
211 }
212
213 for (size_t i=0; i<count; i++)
214 output[i] = input[i] ^ mask[i];
215}
216
217// VerifyBufsEqual simplified at https://github.com/weidai11/cryptopp/issues/1020
218bool VerifyBufsEqual(const byte *buf, const byte *mask, size_t count)
219{
220 CRYPTOPP_ASSERT(buf != NULLPTR);
221 CRYPTOPP_ASSERT(mask != NULLPTR);
222 // CRYPTOPP_ASSERT(count > 0);
223
224#if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_ARM64 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_BOOL_MIPS64 || CRYPTOPP_BOOL_SPARC64
225 word64 acc64 = 0;
226 while (count >= 8)
227 {
228 word64 b, m;
229 std::memcpy(&b, buf, 8); std::memcpy(&m, mask, 8);
230 acc64 |= b ^ m;
231
232 buf += 8; mask += 8; count -= 8;
233 }
234
235 word32 acc8 = (acc64 >> 32) | (acc64 & 0xffffffff);
236 acc8 = static_cast<byte>(acc8) | static_cast<byte>(acc8 >> 8) |
237 static_cast<byte>(acc8 >> 16) | static_cast<byte>(acc8 >> 24);
238#else
239 word32 acc32 = 0;
240 while (count >= 4)
241 {
242 word32 b, m;
243 std::memcpy(&b, buf, 4); std::memcpy(&m, mask, 4);
244 acc32 |= b ^ m;
245
246 buf += 4; mask += 4; count -= 4;
247 }
248
249 word32 acc8 = acc32;
250 acc8 = static_cast<byte>(acc8) | static_cast<byte>(acc8 >> 8) |
251 static_cast<byte>(acc8 >> 16) | static_cast<byte>(acc8 >> 24);
252#endif
253
254 for (size_t i=0; i<count; i++)
255 acc8 |= buf[i] ^ mask[i];
256
257 // word32 results in this tail code on x86:
258 // 33a: 85 c0 test %eax, %eax
259 // 33c: 0f 94 c0 sete %al
260 // 33f: c3 ret
261 return acc8 == 0;
262}
263
264std::string StringNarrow(const wchar_t *str, bool throwOnError)
265{
266 CRYPTOPP_ASSERT(str);
267 std::string result;
268
269 // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
270#if (CRYPTOPP_MSC_VERSION >= 1400)
271 size_t len=0, size=0;
272 errno_t err = 0;
273
274 //const wchar_t* ptr = str;
275 //while (*ptr++) len++;
276 len = wcslen(str)+1;
277
278 err = wcstombs_s(&size, NULLPTR, 0, str, len*sizeof(wchar_t));
279 CRYPTOPP_ASSERT(err == 0);
280 if (err != 0)
281 {
282 if (throwOnError)
283 throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err));
284 else
285 return std::string();
286 }
287
288 result.resize(size);
289 err = wcstombs_s(&size, &result[0], size, str, len*sizeof(wchar_t));
290 CRYPTOPP_ASSERT(err == 0);
291 if (err != 0)
292 {
293 if (throwOnError)
294 throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err));
295 else
296 return std::string();
297 }
298
299 // The safe routine's size includes the NULL.
300 if (!result.empty() && result[size - 1] == '\0')
301 result.erase(size - 1);
302#else
303 size_t size = wcstombs(NULLPTR, str, 0);
304 CRYPTOPP_ASSERT(size != (size_t)-1);
305 if (size == (size_t)-1)
306 {
307 if (throwOnError)
308 throw InvalidArgument("StringNarrow: wcstombs() failed");
309 else
310 return std::string();
311 }
312
313 result.resize(size);
314 size = wcstombs(&result[0], str, size);
315 CRYPTOPP_ASSERT(size != (size_t)-1);
316 if (size == (size_t)-1)
317 {
318 if (throwOnError)
319 throw InvalidArgument("StringNarrow: wcstombs() failed");
320 else
321 return std::string();
322 }
323#endif
324
325 return result;
326}
327
328std::wstring StringWiden(const char *str, bool throwOnError)
329{
330 CRYPTOPP_ASSERT(str);
331 std::wstring result;
332
333 // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55
334#if (CRYPTOPP_MSC_VERSION >= 1400)
335 size_t len=0, size=0;
336 errno_t err = 0;
337
338 //const char* ptr = str;
339 //while (*ptr++) len++;
340 len = std::strlen(str)+1;
341
342 err = mbstowcs_s(&size, NULLPTR, 0, str, len);
343 CRYPTOPP_ASSERT(err == 0);
344 if (err != 0)
345 {
346 if (throwOnError)
347 throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err));
348 else
349 return std::wstring();
350 }
351
352 result.resize(size);
353 err = mbstowcs_s(&size, &result[0], size, str, len);
354 CRYPTOPP_ASSERT(err == 0);
355 if (err != 0)
356 {
357 if (throwOnError)
358 throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err));
359 else
360 return std::wstring();
361 }
362
363 // The safe routine's size includes the NULL.
364 if (!result.empty() && result[size - 1] == '\0')
365 result.erase(size - 1);
366#else
367 size_t size = mbstowcs(NULLPTR, str, 0);
368 CRYPTOPP_ASSERT(size != (size_t)-1);
369 if (size == (size_t)-1)
370 {
371 if (throwOnError)
372 throw InvalidArgument("StringWiden: mbstowcs() failed");
373 else
374 return std::wstring();
375 }
376
377 result.resize(size);
378 size = mbstowcs(&result[0], str, size);
379 CRYPTOPP_ASSERT(size != (size_t)-1);
380 if (size == (size_t)-1)
381 {
382 if (throwOnError)
383 throw InvalidArgument("StringWiden: mbstowcs() failed");
384 else
385 return std::wstring();
386 }
387#endif
388
389 return result;
390}
391
392NAMESPACE_END
393
394#endif
An invalid argument was detected.
Definition cryptlib.h:208
A::pointer data()
Provides a pointer to the first element in the memory block.
Definition secblock.h:857
bool empty() const
Determines if the SecBlock is empty.
Definition secblock.h:871
size_type size() const
Provides the count of elements in the SecBlock.
Definition secblock.h:867
SecBlock typedef.
Definition secblock.h:1226
Library configuration file.
unsigned int word32
32-bit unsigned datatype
Definition config_int.h:72
unsigned long long word64
64-bit unsigned datatype
Definition config_int.h:101
Multiple precision integer with arithmetic operations.
Utility functions for the Crypto++ library.
size_t BytePtrSize(const std::string &str)
Size of a string.
Definition misc.h:481
std::string IntToString(T value, unsigned int base=10)
Converts a value to a string.
Definition misc.h:929
const byte * ConstBytePtr(const std::string &str)
Const pointer to the first element of a string.
Definition misc.h:463
std::string StringNarrow(const wchar_t *str, bool throwOnError=true)
Converts a wide character C-string to a multibyte string.
std::wstring StringWiden(const char *str, bool throwOnError=true)
Converts a multibyte C-string to a wide character string.
byte * BytePtr(std::string &str)
Pointer to the first element of a string.
Definition misc.h:441
CRYPTOPP_DLL bool VerifyBufsEqual(const byte *buf1, const byte *buf2, size_t count)
Performs a near constant-time comparison of two equally sized buffers.
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 and functions for secure memory allocations.
Common C++ header files.
Debugging and diagnostic assertions.
#define CRYPTOPP_ASSERT(exp)
Debugging and diagnostic assertion.
Definition trap.h:68
Support functions for word operations.