Crypto++  8.8
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 
45 NAMESPACE_BEGIN(CryptoPP)
46 
47 byte* 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 
57 const byte* ConstBytePtr(const SecByteBlock& str)
58 {
59  if (str.empty())
60  return NULLPTR;
61  return reinterpret_cast<const byte*>(str.data());
62 }
63 
64 size_t BytePtrSize(const SecByteBlock& str)
65 {
66  return str.size();
67 }
68 
69 // xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020
70 void 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
144 void 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
218 bool 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 
264 std::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 
328 std::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 
392 NAMESPACE_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<byte> 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
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
const byte * ConstBytePtr(const std::string &str)
Const pointer to the first element of a string.
Definition: misc.h:463
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.