// misc.cpp - originally written and placed in the public domain by Wei Dai #include "pch.h" #include "config.h" #if CRYPTOPP_MSC_VERSION # pragma warning(disable: 4189) # if (CRYPTOPP_MSC_VERSION >= 1400) # pragma warning(disable: 6237) # endif #endif #ifndef CRYPTOPP_IMPORTS #include "misc.h" #include "trap.h" #include "words.h" #include "stdcpp.h" #include "integer.h" #include "secblock.h" // Hack for OpenBSD and GCC 4.2.1. I believe they are stuck at 4.2.1 due to GPLv3. #if defined(__OpenBSD__) # if defined (CRYPTOPP_GCC_VERSION) && (CRYPTOPP_GCC_VERSION < 43000) # undef CRYPTOPP_DISABLE_ASM # define CRYPTOPP_DISABLE_ASM 1 # endif #endif #ifndef CRYPTOPP_DISABLE_ASM # if defined(__SSE2__) # include # endif # if defined(__AVX__) # include # endif # if defined(__aarch32__) || defined(__aarch64__) || defined(_M_ARM64) # if (CRYPTOPP_ARM_NEON_HEADER) || (CRYPTOPP_ARM_ASIMD_AVAILABLE) # include # endif # endif #endif // CRYPTOPP_DISABLE_ASM NAMESPACE_BEGIN(CryptoPP) byte* BytePtr(SecByteBlock& str) { // Caller wants a writeable pointer CRYPTOPP_ASSERT(str.empty() == false); if (str.empty()) return NULLPTR; return reinterpret_cast(str.data()); } const byte* ConstBytePtr(const SecByteBlock& str) { if (str.empty()) return NULLPTR; return reinterpret_cast(str.data()); } size_t BytePtrSize(const SecByteBlock& str) { return str.size(); } // xorbuf simplified at https://github.com/weidai11/cryptopp/issues/1020 void xorbuf(byte *buf, const byte *mask, size_t count) { CRYPTOPP_ASSERT(buf != NULLPTR); CRYPTOPP_ASSERT(mask != NULLPTR); CRYPTOPP_ASSERT(count > 0); #ifndef CRYPTOPP_DISABLE_ASM # if defined(__AVX__) while (count >= 32) { __m256i b = _mm256_loadu_si256(reinterpret_cast(buf)); __m256i m = _mm256_loadu_si256(reinterpret_cast(mask)); _mm256_storeu_si256(reinterpret_cast<__m256i*>(buf), _mm256_castps_si256( _mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m)))); buf += 32; mask += 32; count -= 32; } // https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties _mm256_zeroupper(); # endif # if defined(__SSE2__) while (count >= 16) { __m128i b = _mm_loadu_si128(reinterpret_cast(buf)); __m128i m = _mm_loadu_si128(reinterpret_cast(mask)); _mm_storeu_si128(reinterpret_cast<__m128i*>(buf), _mm_castps_si128( _mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m)))); buf += 16; mask += 16; count -= 16; } # endif # if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64) while (count >= 16) { vst1q_u8(buf, veorq_u8(vld1q_u8(buf), vld1q_u8(mask))); buf += 16; mask += 16; count -= 16; } # endif #endif // CRYPTOPP_DISABLE_ASM #if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 // word64 and stride of 8 slows things down on x86_64. // word64 and stride of 8 makes no difference on ARM. // word64 and stride of 16 benefits PowerPC. while (count >= 16) { word64 r[2], b[2], m[2]; std::memcpy(&b, buf, 16); std::memcpy(&m, mask, 16); r[0] = b[0] ^ m[0]; r[1] = b[1] ^ m[1]; std::memcpy(buf, &r, 16); buf += 16; mask += 16; count -= 16; } #endif // One of the arch specific xor's may have cleared the request if (count == 0) return; while (count >= 4) { word32 r, b, m; std::memcpy(&b, buf, 4); std::memcpy(&m, mask, 4); r = b ^ m; std::memcpy(buf, &r, 4); buf += 4; mask += 4; count -= 4; } for (size_t i=0; i 0); #ifndef CRYPTOPP_DISABLE_ASM # if defined(__AVX__) while (count >= 32) { __m256i b = _mm256_loadu_si256(reinterpret_cast(input)); __m256i m = _mm256_loadu_si256(reinterpret_cast(mask)); _mm256_storeu_si256(reinterpret_cast<__m256i*>(output), _mm256_castps_si256( _mm256_xor_ps(_mm256_castsi256_ps(b), _mm256_castsi256_ps(m)))); output += 32; input += 32; mask += 32; count -= 32; } // https://software.intel.com/en-us/articles/avoiding-avx-sse-transition-penalties _mm256_zeroupper(); # endif # if defined(__SSE2__) while (count >= 16) { __m128i b = _mm_loadu_si128(reinterpret_cast(input)); __m128i m = _mm_loadu_si128(reinterpret_cast(mask)); _mm_storeu_si128(reinterpret_cast<__m128i*>(output), _mm_castps_si128( _mm_xor_ps(_mm_castsi128_ps(b), _mm_castsi128_ps(m)))); output += 16; input += 16; mask += 16; count -= 16; } # endif # if defined(__aarch64__) || defined(__aarch32__) || defined(_M_ARM64) while (count >= 16) { vst1q_u8(output, veorq_u8(vld1q_u8(input), vld1q_u8(mask))); output += 16; input += 16; mask += 16; count -= 16; } # endif #endif // CRYPTOPP_DISABLE_ASM #if CRYPTOPP_BOOL_PPC32 || CRYPTOPP_BOOL_PPC64 // word64 and stride of 8 slows things down on x86_64. // word64 and stride of 8 makes no difference on ARM. // word64 and stride of 16 benefits PowerPC. while (count >= 16) { word64 b[2], m[2], r[2]; std::memcpy(&b, input, 16); std::memcpy(&m, mask, 16); r[0] = b[0] ^ m[0]; r[1] = b[1] ^ m[1]; std::memcpy(output, &r, 16); output += 16; input += 16; mask += 16; count -= 16; } #endif // One of the arch specific xor's may have cleared the request if (count == 0) return; while (count >= 4) { word32 b, m, r; std::memcpy(&b, input, 4); std::memcpy(&m, mask, 4); r = b ^ m; std::memcpy(output, &r, 4); output += 4; input += 4; mask += 4; count -= 4; } for (size_t i=0; i 0); #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_ARM64 || CRYPTOPP_BOOL_PPC64 || CRYPTOPP_BOOL_MIPS64 || CRYPTOPP_BOOL_SPARC64 word64 acc64 = 0; while (count >= 8) { word64 b, m; std::memcpy(&b, buf, 8); std::memcpy(&m, mask, 8); acc64 |= b ^ m; buf += 8; mask += 8; count -= 8; } word32 acc8 = (acc64 >> 32) | (acc64 & 0xffffffff); acc8 = static_cast(acc8) | static_cast(acc8 >> 8) | static_cast(acc8 >> 16) | static_cast(acc8 >> 24); #else word32 acc32 = 0; while (count >= 4) { word32 b, m; std::memcpy(&b, buf, 4); std::memcpy(&m, mask, 4); acc32 |= b ^ m; buf += 4; mask += 4; count -= 4; } word32 acc8 = acc32; acc8 = static_cast(acc8) | static_cast(acc8 >> 8) | static_cast(acc8 >> 16) | static_cast(acc8 >> 24); #endif for (size_t i=0; i= 1400) size_t len=0, size=0; errno_t err = 0; //const wchar_t* ptr = str; //while (*ptr++) len++; len = wcslen(str)+1; err = wcstombs_s(&size, NULLPTR, 0, str, len*sizeof(wchar_t)); CRYPTOPP_ASSERT(err == 0); if (err != 0) { if (throwOnError) throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err)); else return std::string(); } result.resize(size); err = wcstombs_s(&size, &result[0], size, str, len*sizeof(wchar_t)); CRYPTOPP_ASSERT(err == 0); if (err != 0) { if (throwOnError) throw InvalidArgument("StringNarrow: wcstombs_s() failed with error " + IntToString(err)); else return std::string(); } // The safe routine's size includes the NULL. if (!result.empty() && result[size - 1] == '\0') result.erase(size - 1); #else size_t size = wcstombs(NULLPTR, str, 0); CRYPTOPP_ASSERT(size != (size_t)-1); if (size == (size_t)-1) { if (throwOnError) throw InvalidArgument("StringNarrow: wcstombs() failed"); else return std::string(); } result.resize(size); size = wcstombs(&result[0], str, size); CRYPTOPP_ASSERT(size != (size_t)-1); if (size == (size_t)-1) { if (throwOnError) throw InvalidArgument("StringNarrow: wcstombs() failed"); else return std::string(); } #endif return result; } std::wstring StringWiden(const char *str, bool throwOnError) { CRYPTOPP_ASSERT(str); std::wstring result; // Safer functions on Windows for C&A, https://github.com/weidai11/cryptopp/issues/55 #if (CRYPTOPP_MSC_VERSION >= 1400) size_t len=0, size=0; errno_t err = 0; //const char* ptr = str; //while (*ptr++) len++; len = std::strlen(str)+1; err = mbstowcs_s(&size, NULLPTR, 0, str, len); CRYPTOPP_ASSERT(err == 0); if (err != 0) { if (throwOnError) throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err)); else return std::wstring(); } result.resize(size); err = mbstowcs_s(&size, &result[0], size, str, len); CRYPTOPP_ASSERT(err == 0); if (err != 0) { if (throwOnError) throw InvalidArgument("StringWiden: wcstombs_s() failed with error " + IntToString(err)); else return std::wstring(); } // The safe routine's size includes the NULL. if (!result.empty() && result[size - 1] == '\0') result.erase(size - 1); #else size_t size = mbstowcs(NULLPTR, str, 0); CRYPTOPP_ASSERT(size != (size_t)-1); if (size == (size_t)-1) { if (throwOnError) throw InvalidArgument("StringWiden: mbstowcs() failed"); else return std::wstring(); } result.resize(size); size = mbstowcs(&result[0], str, size); CRYPTOPP_ASSERT(size != (size_t)-1); if (size == (size_t)-1) { if (throwOnError) throw InvalidArgument("StringWiden: mbstowcs() failed"); else return std::wstring(); } #endif return result; } NAMESPACE_END #endif