00001
00002
00003
00004 #include "pch.h"
00005 #include "config.h"
00006 #include "cryptlib.h"
00007 #include "secblock.h"
00008 #include "rdrand.h"
00009 #include "cpu.h"
00010
00011 #if CRYPTOPP_MSC_VERSION
00012 # pragma warning(disable: 4100)
00013 #endif
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040 #if 0
00041 #define NASM_RDRAND_ASM_AVAILABLE 1
00042 #define NASM_RDSEED_ASM_AVAILABLE 1
00043 #endif
00044
00045
00046
00047
00048
00049
00050
00051
00052 #ifndef CRYPTOPP_CPUID_AVAILABLE
00053 # if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
00054 # define CRYPTOPP_CPUID_AVAILABLE
00055 # endif
00056 #endif
00057
00058 #if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDRAND_ASM)
00059 # define CRYPTOPP_BOOL_RDRAND_ASM 1
00060 #else
00061 # define CRYPTOPP_BOOL_RDRAND_ASM 0
00062 #endif
00063 #if defined(CRYPTOPP_CPUID_AVAILABLE) && !defined(CRYPTOPP_BOOL_RDSEED_ASM)
00064 # define CRYPTOPP_BOOL_RDSEED_ASM 1
00065 #else
00066 # define CRYPTOPP_BOOL_RDSEED_ASM 0
00067 #endif
00068
00069 #if defined(CRYPTOPP_CPUID_AVAILABLE)
00070 # define MSC_INTRIN_COMPILER ((CRYPTOPP_MSC_VERSION >= 1700) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
00071 # define GCC_INTRIN_COMPILER ((CRYPTOPP_GCC_VERSION >= 40600) || (CRYPTOPP_CLANG_VERSION >= 30200) || (_INTEL_COMPILER >= 1210))
00072 #else
00073 # define MSC_INTRIN_COMPILER 0
00074 # define GCC_INTRIN_COMPILER 0
00075 #endif
00076
00077
00078
00079
00080 #if defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_MSC_VERSION >= 1200)
00081 # if CRYPTOPP_BOOL_RDRAND_ASM
00082 # define MASM_RDRAND_ASM_AVAILABLE 1
00083 # elif MSC_INTRIN_COMPILER
00084 # define ALL_RDRAND_INTRIN_AVAILABLE 1
00085 # endif
00086 # if CRYPTOPP_BOOL_RDSEED_ASM
00087 # define MASM_RDSEED_ASM_AVAILABLE 1
00088 # elif MSC_INTRIN_COMPILER
00089 # define ALL_RDSEED_INTRIN_AVAILABLE 1
00090 # endif
00091 #elif defined(CRYPTOPP_CPUID_AVAILABLE) && (CRYPTOPP_GCC_VERSION >= 30200)
00092 # if GCC_INTRIN_COMPILER && defined(__RDRND__)
00093 # define ALL_RDRAND_INTRIN_AVAILABLE 1
00094 # elif CRYPTOPP_BOOL_RDRAND_ASM
00095 # define GCC_RDRAND_ASM_AVAILABLE 1
00096 # endif
00097 # if GCC_INTRIN_COMPILER && defined(__RDSEED__)
00098 # define ALL_RDSEED_INTRIN_AVAILABLE 1
00099 # elif CRYPTOPP_BOOL_RDSEED_ASM
00100 # define GCC_RDSEED_ASM_AVAILABLE 1
00101 # endif
00102 #endif
00103
00104
00105 #if 0
00106 # if MASM_RDRAND_ASM_AVAILABLE
00107 # pragma message ("MASM_RDRAND_ASM_AVAILABLE is 1")
00108 # elif NASM_RDRAND_ASM_AVAILABLE
00109 # pragma message ("NASM_RDRAND_ASM_AVAILABLE is 1")
00110 # elif GCC_RDRAND_ASM_AVAILABLE
00111 # pragma message ("GCC_RDRAND_ASM_AVAILABLE is 1")
00112 # elif ALL_RDRAND_INTRIN_AVAILABLE
00113 # pragma message ("ALL_RDRAND_INTRIN_AVAILABLE is 1")
00114 # else
00115 # pragma message ("RDRAND is not available")
00116 # endif
00117 # if MASM_RDSEED_ASM_AVAILABLE
00118 # pragma message ("MASM_RDSEED_ASM_AVAILABLE is 1")
00119 # elif NASM_RDSEED_ASM_AVAILABLE
00120 # pragma message ("NASM_RDSEED_ASM_AVAILABLE is 1")
00121 # elif GCC_RDSEED_ASM_AVAILABLE
00122 # pragma message ("GCC_RDSEED_ASM_AVAILABLE is 1")
00123 # elif ALL_RDSEED_INTRIN_AVAILABLE
00124 # pragma message ("ALL_RDSEED_INTRIN_AVAILABLE is 1")
00125 # else
00126 # pragma message ("RDSEED is not available")
00127 # endif
00128 #endif
00129
00130
00131
00132
00133 #if (ALL_RDRAND_INTRIN_AVAILABLE || ALL_RDSEED_INTRIN_AVAILABLE)
00134 # include <immintrin.h>
00135 # if defined(__has_include)
00136 # if __has_include(<x86intrin.h>)
00137 # include <x86intrin.h>
00138 # endif
00139 # endif
00140 #endif
00141
00142 #if MASM_RDRAND_ASM_AVAILABLE
00143 # ifdef _M_X64
00144 extern "C" int CRYPTOPP_FASTCALL MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
00145
00146 # else
00147 extern "C" int MASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
00148
00149 # endif
00150 #endif
00151
00152 #if MASM_RDSEED_ASM_AVAILABLE
00153 # ifdef _M_X64
00154 extern "C" int CRYPTOPP_FASTCALL MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
00155
00156 # else
00157 extern "C" int MASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
00158
00159 # endif
00160 #endif
00161
00162 #if NASM_RDRAND_ASM_AVAILABLE
00163 extern "C" int NASM_RRA_GenerateBlock(byte*, size_t, unsigned int);
00164 #endif
00165
00166 #if NASM_RDSEED_ASM_AVAILABLE
00167 extern "C" int NASM_RSA_GenerateBlock(byte*, size_t, unsigned int);
00168 #endif
00169
00170
00171
00172
00173 NAMESPACE_BEGIN(CryptoPP)
00174
00175 #if ALL_RDRAND_INTRIN_AVAILABLE
00176 static int ALL_RRI_GenerateBlock(byte *output, size_t size, unsigned int safety)
00177 {
00178 assert((output && size) || !(output || size));
00179 #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
00180 word64 val;
00181 #else
00182 word32 val;
00183 #endif
00184
00185 while (size >= sizeof(val))
00186 {
00187 #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
00188 if (_rdrand64_step((word64*)output))
00189 #else
00190 if (_rdrand32_step((word32*)output))
00191 #endif
00192 {
00193 output += sizeof(val);
00194 size -= sizeof(val);
00195 }
00196 else
00197 {
00198 if (!safety--)
00199 return 0;
00200 }
00201 }
00202
00203 if (size)
00204 {
00205 #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
00206 if (_rdrand64_step(&val))
00207 #else
00208 if (_rdrand32_step(&val))
00209 #endif
00210 {
00211 memcpy(output, &val, size);
00212 size = 0;
00213 }
00214 else
00215 {
00216 if (!safety--)
00217 return 0;
00218 }
00219 }
00220
00221 #if CRYPTOPP_BOOL_X64 || CRYTPOPP_BOOL_X32
00222 *((volatile word64*)&val) = 0;
00223 #else
00224 *((volatile word32*)&val) = 0;
00225 #endif
00226
00227 return int(size == 0);
00228 }
00229 #endif // ALL_RDRAND_INTRINSIC_AVAILABLE
00230
00231 #if GCC_RDRAND_ASM_AVAILABLE
00232 static int GCC_RRA_GenerateBlock(byte *output, size_t size, unsigned int safety)
00233 {
00234 assert((output && size) || !(output || size));
00235 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00236 word64 val;
00237 #else
00238 word32 val;
00239 #endif
00240 char rc;
00241 while (size)
00242 {
00243 __asm__ volatile(
00244 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00245 ".byte 0x48, 0x0f, 0xc7, 0xf0;\n"
00246 #else
00247 ".byte 0x0f, 0xc7, 0xf0;\n"
00248 #endif
00249 "setc %1; "
00250 : "=a" (val), "=qm" (rc)
00251 :
00252 : "cc"
00253 );
00254
00255 if (rc)
00256 {
00257 if (size >= sizeof(val))
00258 {
00259 #if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
00260 *((word64*)output) = val;
00261 #elif defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X86)
00262 *((word32*)output) = val;
00263 #else
00264 memcpy(output, &val, sizeof(val));
00265 #endif
00266 output += sizeof(val);
00267 size -= sizeof(val);
00268 }
00269 else
00270 {
00271 memcpy(output, &val, size);
00272 size = 0;
00273 }
00274 }
00275 else
00276 {
00277 if (!safety--)
00278 break;
00279 }
00280 }
00281
00282 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00283 *((volatile word64*)&val) = 0;
00284 #else
00285 *((volatile word32*)&val) = 0;
00286 #endif
00287
00288 return int(size == 0);
00289 }
00290
00291 #endif // GCC_RDRAND_ASM_AVAILABLE
00292
00293 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
00294 void RDRAND::GenerateBlock(byte *output, size_t size)
00295 {
00296 CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
00297 assert((output && size) || !(output || size));
00298
00299 if(!HasRDRAND())
00300 throw NotImplemented("RDRAND: rdrand is not available on this platform");
00301
00302 int rc; CRYPTOPP_UNUSED(rc);
00303 #if MASM_RDRAND_ASM_AVAILABLE
00304 rc = MASM_RRA_GenerateBlock(output, size, m_retries);
00305 if (!rc) { throw RDRAND_Err("MASM_RRA_GenerateBlock"); }
00306 #elif NASM_RDRAND_ASM_AVAILABLE
00307 rc = NASM_RRA_GenerateBlock(output, size, m_retries);
00308 if (!rc) { throw RDRAND_Err("NASM_RRA_GenerateBlock"); }
00309 #elif ALL_RDRAND_INTRIN_AVAILABLE
00310 rc = ALL_RRI_GenerateBlock(output, size, m_retries);
00311 if (!rc) { throw RDRAND_Err("ALL_RRI_GenerateBlock"); }
00312 #elif GCC_RDRAND_ASM_AVAILABLE
00313 rc = GCC_RRA_GenerateBlock(output, size, m_retries);
00314 if (!rc) { throw RDRAND_Err("GCC_RRA_GenerateBlock"); }
00315 #else
00316
00317 throw NotImplemented("RDRAND: failed to find a suitable implementation???");
00318 #endif // CRYPTOPP_CPUID_AVAILABLE
00319 }
00320
00321 void RDRAND::DiscardBytes(size_t n)
00322 {
00323
00324
00325 assert(HasRDRAND());
00326 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00327 FixedSizeSecBlock<word64, 16> discard;
00328 n = RoundUpToMultipleOf(n, sizeof(word64));
00329 #else
00330 FixedSizeSecBlock<word32, 16> discard;
00331 n = RoundUpToMultipleOf(n, sizeof(word32));
00332 #endif
00333
00334 size_t count = STDMIN(n, discard.SizeInBytes());
00335 while (count)
00336 {
00337 GenerateBlock(discard.BytePtr(), count);
00338 n -= count;
00339 count = STDMIN(n, discard.SizeInBytes());
00340 }
00341 }
00342 #endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
00343
00344
00345
00346
00347 #if ALL_RDSEED_INTRIN_AVAILABLE
00348 static int ALL_RSI_GenerateBlock(byte *output, size_t size, unsigned int safety)
00349 {
00350 assert((output && size) || !(output || size));
00351 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00352 word64 val;
00353 #else
00354 word32 val;
00355 #endif
00356
00357 while (size >= sizeof(val))
00358 {
00359 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00360 if (_rdseed64_step((word64*)output))
00361 #else
00362 if (_rdseed32_step((word32*)output))
00363 #endif
00364 {
00365 output += sizeof(val);
00366 size -= sizeof(val);
00367 }
00368 else
00369 {
00370 if (!safety--)
00371 return 0;
00372 }
00373 }
00374
00375 if (size)
00376 {
00377 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00378 if (_rdseed64_step(&val))
00379 #else
00380 if (_rdseed32_step(&val))
00381 #endif
00382 {
00383 memcpy(output, &val, size);
00384 size = 0;
00385 }
00386 else
00387 {
00388 if (!safety--)
00389 return 0;
00390 }
00391 }
00392
00393 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00394 *((volatile word64*)&val) = 0;
00395 #else
00396 *((volatile word32*)&val) = 0;
00397 #endif
00398
00399 return int(size == 0);
00400 }
00401 #endif // ALL_RDSEED_INTRIN_AVAILABLE
00402
00403 #if GCC_RDSEED_ASM_AVAILABLE
00404 static int GCC_RSA_GenerateBlock(byte *output, size_t size, unsigned int safety)
00405 {
00406 assert((output && size) || !(output || size));
00407 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00408 word64 val;
00409 #else
00410 word32 val;
00411 #endif
00412 char rc;
00413 while (size)
00414 {
00415 __asm__ volatile(
00416 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00417 ".byte 0x48, 0x0f, 0xc7, 0xf8;\n"
00418 #else
00419 ".byte 0x0f, 0xc7, 0xf8;\n"
00420 #endif
00421 "setc %1; "
00422 : "=a" (val), "=qm" (rc)
00423 :
00424 : "cc"
00425 );
00426
00427 if (rc)
00428 {
00429 if (size >= sizeof(val))
00430 {
00431 #if defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32)
00432 *((word64*)output) = val;
00433 #elif defined(CRYPTOPP_ALLOW_UNALIGNED_DATA_ACCESS) && (CRYPTOPP_BOOL_X86)
00434 *((word32*)output) = val;
00435 #else
00436 memcpy(output, &val, sizeof(val));
00437 #endif
00438 output += sizeof(val);
00439 size -= sizeof(val);
00440 }
00441 else
00442 {
00443 memcpy(output, &val, size);
00444 size = 0;
00445 }
00446 }
00447 else
00448 {
00449 if (!safety--)
00450 break;
00451 }
00452 }
00453
00454 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00455 *((volatile word64*)&val) = 0;
00456 #else
00457 *((volatile word32*)&val) = 0;
00458 #endif
00459
00460 return int(size == 0);
00461 }
00462 #endif // GCC_RDSEED_ASM_AVAILABLE
00463
00464 #if (CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64)
00465 void RDSEED::GenerateBlock(byte *output, size_t size)
00466 {
00467 CRYPTOPP_UNUSED(output), CRYPTOPP_UNUSED(size);
00468 assert((output && size) || !(output || size));
00469
00470 if(!HasRDSEED())
00471 throw NotImplemented("RDSEED: rdseed is not available on this platform");
00472
00473 int rc; CRYPTOPP_UNUSED(rc);
00474 #if MASM_RDSEED_ASM_AVAILABLE
00475 rc = MASM_RSA_GenerateBlock(output, size, m_retries);
00476 if (!rc) { throw RDSEED_Err("MASM_RSA_GenerateBlock"); }
00477 #elif NASM_RDSEED_ASM_AVAILABLE
00478 rc = NASM_RSA_GenerateBlock(output, size, m_retries);
00479 if (!rc) { throw RDRAND_Err("NASM_RSA_GenerateBlock"); }
00480 #elif ALL_RDSEED_INTRIN_AVAILABLE
00481 rc = ALL_RSI_GenerateBlock(output, size, m_retries);
00482 if (!rc) { throw RDSEED_Err("ALL_RSI_GenerateBlock"); }
00483 #elif GCC_RDSEED_ASM_AVAILABLE
00484 rc = GCC_RSA_GenerateBlock(output, size, m_retries);
00485 if (!rc) { throw RDSEED_Err("GCC_RSA_GenerateBlock"); }
00486 #else
00487
00488 throw NotImplemented("RDSEED: failed to find a suitable implementation???");
00489 #endif
00490 }
00491
00492 void RDSEED::DiscardBytes(size_t n)
00493 {
00494
00495
00496 assert(HasRDSEED());
00497 #if CRYPTOPP_BOOL_X64 || CRYPTOPP_BOOL_X32
00498 FixedSizeSecBlock<word64, 16> discard;
00499 n = RoundUpToMultipleOf(n, sizeof(word64));
00500 #else
00501 FixedSizeSecBlock<word32, 16> discard;
00502 n = RoundUpToMultipleOf(n, sizeof(word32));
00503 #endif
00504
00505 size_t count = STDMIN(n, discard.SizeInBytes());
00506 while (count)
00507 {
00508 GenerateBlock(discard.BytePtr(), count);
00509 n -= count;
00510 count = STDMIN(n, discard.SizeInBytes());
00511 }
00512 }
00513 #endif // CRYPTOPP_BOOL_X86 || CRYPTOPP_BOOL_X32 || CRYPTOPP_BOOL_X64
00514
00515 NAMESPACE_END