mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
more refactoring
This commit is contained in:
parent
c3b5c45fea
commit
5275a34b0b
5 changed files with 301 additions and 38 deletions
|
@ -3,7 +3,6 @@ project(zt_go_native)
|
|||
|
||||
set(src
|
||||
GoGlue.cpp
|
||||
CoreTests.cpp
|
||||
)
|
||||
|
||||
set(headers
|
||||
|
|
18
node/AES.hpp
18
node/AES.hpp
|
@ -64,22 +64,24 @@ public:
|
|||
*
|
||||
* @param key 256-bit key
|
||||
*/
|
||||
explicit ZT_ALWAYS_INLINE AES(const uint8_t key[32]) noexcept { this->init(key); }
|
||||
explicit ZT_ALWAYS_INLINE AES(const void *const key) noexcept { this->init(key); }
|
||||
|
||||
ZT_ALWAYS_INLINE ~AES() { Utils::burn(&_k,sizeof(_k)); }
|
||||
|
||||
/**
|
||||
* Set (or re-set) this AES256 cipher's key
|
||||
*
|
||||
* @param key 256-bit / 32-byte key
|
||||
*/
|
||||
ZT_ALWAYS_INLINE void init(const uint8_t key[32]) noexcept
|
||||
ZT_ALWAYS_INLINE void init(const void *key) noexcept
|
||||
{
|
||||
#ifdef ZT_AES_AESNI
|
||||
if (likely(Utils::CPUID.aes)) {
|
||||
_init_aesni(key);
|
||||
_init_aesni(reinterpret_cast<const uint8_t *>(key));
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
_initSW(key);
|
||||
_initSW(reinterpret_cast<const uint8_t *>(key));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -88,7 +90,7 @@ public:
|
|||
* @param in Input block
|
||||
* @param out Output block (can be same as input)
|
||||
*/
|
||||
ZT_ALWAYS_INLINE void encrypt(const uint8_t in[16],uint8_t out[16]) const noexcept
|
||||
ZT_ALWAYS_INLINE void encrypt(const void *const in,void *const out) const noexcept
|
||||
{
|
||||
#ifdef ZT_AES_AESNI
|
||||
if (likely(Utils::CPUID.aes)) {
|
||||
|
@ -96,7 +98,7 @@ public:
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
_encryptSW(in,out);
|
||||
_encryptSW(reinterpret_cast<const uint8_t *>(in),reinterpret_cast<uint8_t *>(out));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,7 +107,7 @@ public:
|
|||
* @param in Input block
|
||||
* @param out Output block (can be same as input)
|
||||
*/
|
||||
ZT_ALWAYS_INLINE void decrypt(const uint8_t in[16],uint8_t out[16]) const noexcept
|
||||
ZT_ALWAYS_INLINE void decrypt(const void *const in,void *const out) const noexcept
|
||||
{
|
||||
#ifdef ZT_AES_AESNI
|
||||
if (likely(Utils::CPUID.aes)) {
|
||||
|
@ -113,7 +115,7 @@ public:
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
_decryptSW(in,out);
|
||||
_decryptSW(reinterpret_cast<const uint8_t *>(in),reinterpret_cast<uint8_t *>(out));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
259
node/Tests.cpp
259
node/Tests.cpp
|
@ -37,9 +37,9 @@
|
|||
#include "LZ4.hpp"
|
||||
#include "Hashtable.hpp"
|
||||
#include "FCV.hpp"
|
||||
#include "SHA512.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <set>
|
||||
|
@ -98,7 +98,7 @@ struct C25519TestVector
|
|||
uint8_t priv1[64];
|
||||
uint8_t pub2[64];
|
||||
uint8_t priv2[64];
|
||||
uint8_t agreement[64];
|
||||
uint8_t agreementSha512[64];
|
||||
uint8_t agreementSignedBy1[96];
|
||||
uint8_t agreementSignedBy2[96];
|
||||
};
|
||||
|
@ -144,6 +144,13 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] =
|
|||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ZT_ENDIAN_S "little"
|
||||
#else
|
||||
#define ZT_ENDIAN_S "big"
|
||||
#endif
|
||||
|
||||
// This is basically a unit test for compiler packed structure behavior.
|
||||
ZT_PACKED_STRUCT(struct StructPackingTestSample {
|
||||
uint8_t foo;
|
||||
uint16_t bar;
|
||||
|
@ -155,13 +162,41 @@ ZT_PACKED_STRUCT(struct StructPackingTestSample {
|
|||
uint8_t lol;
|
||||
});
|
||||
|
||||
#define ZT_T_ASSERT(e) if (!(e)) { ZT_T_PRINTF("FAILED (simple assert: " #e ")" ZT_EOL_S); return "simple assert: " #e; }
|
||||
// Increments and decrements a counter based on object create/destroy
|
||||
class LifeCycleTracker
|
||||
{
|
||||
public:
|
||||
ZT_ALWAYS_INLINE LifeCycleTracker() :
|
||||
cnt(nullptr)
|
||||
{
|
||||
}
|
||||
ZT_ALWAYS_INLINE LifeCycleTracker(const LifeCycleTracker <c) :
|
||||
cnt(ltc.cnt)
|
||||
{
|
||||
if (*cnt) ++*cnt;
|
||||
}
|
||||
explicit ZT_ALWAYS_INLINE LifeCycleTracker(long &c) :
|
||||
cnt(&c)
|
||||
{
|
||||
++c;
|
||||
}
|
||||
ZT_ALWAYS_INLINE ~LifeCycleTracker()
|
||||
{
|
||||
if (cnt) --*cnt;
|
||||
}
|
||||
ZT_ALWAYS_INLINE LifeCycleTracker &operator=(const LifeCycleTracker <c)
|
||||
{
|
||||
if (<c != this) {
|
||||
if (*cnt) --*cnt;
|
||||
cnt = ltc.cnt;
|
||||
if (*cnt) ++*cnt;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
long *cnt;
|
||||
};
|
||||
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
#define ZT_ENDIAN_S "little"
|
||||
#else
|
||||
#define ZT_ENDIAN_S "big"
|
||||
#endif
|
||||
#define ZT_T_ASSERT(e) if (!(e)) { ZT_T_PRINTF("FAILED (simple assert: " #e ")" ZT_EOL_S); return "simple assert: " #e; }
|
||||
|
||||
extern "C" const char *ZTT_general()
|
||||
{
|
||||
|
@ -206,6 +241,9 @@ extern "C" const char *ZTT_general()
|
|||
ZT_T_ASSERT(sizeof(Protocol::Header) == ZT_PROTO_MIN_PACKET_LENGTH);
|
||||
ZT_T_ASSERT(sizeof(Protocol::FragmentHeader) == ZT_PROTO_MIN_FRAGMENT_LENGTH);
|
||||
ZT_T_ASSERT(sizeof(sockaddr_storage) == sizeof(InetAddress));
|
||||
ZT_T_ASSERT(sizeof(sockaddr_in) <= sizeof(InetAddress));
|
||||
ZT_T_ASSERT(sizeof(sockaddr_in6) <= sizeof(InetAddress));
|
||||
ZT_T_ASSERT(sizeof(sockaddr) <= sizeof(InetAddress));
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
|
@ -270,6 +308,92 @@ extern "C" const char *ZTT_general()
|
|||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[general] Testing FCV (fixed capacity vector)... ");
|
||||
long cnt = 0;
|
||||
FCV<LifeCycleTracker,1024> test,test2;
|
||||
for(unsigned int i=0;i<512;++i)
|
||||
test.push_back(LifeCycleTracker(cnt));
|
||||
if (cnt != 512) {
|
||||
ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (1))" ZT_EOL_S,cnt);
|
||||
return "FCV object life cycle test failed (1)";
|
||||
}
|
||||
test2 = test;
|
||||
if (cnt != 1024) {
|
||||
ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (2))" ZT_EOL_S,cnt);
|
||||
return "FCV object life cycle test failed (2)";
|
||||
}
|
||||
test.clear();
|
||||
if (cnt != 512) {
|
||||
ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (3))" ZT_EOL_S,cnt);
|
||||
return "FCV object life cycle test failed (3)";
|
||||
}
|
||||
for(unsigned int i=0;i<512;++i)
|
||||
test.push_back(LifeCycleTracker(cnt));
|
||||
if (cnt != 1024) {
|
||||
ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (4))" ZT_EOL_S,cnt);
|
||||
return "FCV object life cycle test failed (4)";
|
||||
}
|
||||
test.clear();
|
||||
test2.clear();
|
||||
if (cnt != 0) {
|
||||
ZT_T_PRINTF("FAILED (expected 0 objects, got %lu (5))" ZT_EOL_S,cnt);
|
||||
return "FCV object life cycle test failed (5)";
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[general] Testing Hashtable... ");
|
||||
|
||||
long cnt = 0;
|
||||
Hashtable< unsigned int,LifeCycleTracker > test,test2;
|
||||
for(unsigned int i=0;i<512;++i)
|
||||
test[i] = LifeCycleTracker(cnt);
|
||||
if (cnt != 512) {
|
||||
ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (1))" ZT_EOL_S,cnt);
|
||||
return "Hashtable test failed (1)";
|
||||
}
|
||||
test2 = test;
|
||||
if (cnt != 1024) {
|
||||
ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (2))" ZT_EOL_S,cnt);
|
||||
return "Hashtable test failed (2)";
|
||||
}
|
||||
test.clear();
|
||||
if (cnt != 512) {
|
||||
ZT_T_PRINTF("FAILED (expected 512 objects, got %lu (3))" ZT_EOL_S,cnt);
|
||||
return "Hashtable test failed (3)";
|
||||
}
|
||||
for(unsigned int i=0;i<512;++i)
|
||||
test[i] = LifeCycleTracker(cnt);
|
||||
if (cnt != 1024) {
|
||||
ZT_T_PRINTF("FAILED (expected 1024 objects, got %lu (4))" ZT_EOL_S,cnt);
|
||||
return "Hashtable test failed (4)";
|
||||
}
|
||||
test.clear();
|
||||
test2.clear();
|
||||
if (cnt != 0) {
|
||||
ZT_T_PRINTF("FAILED (expected 0 objects, got %lu (5))" ZT_EOL_S,cnt);
|
||||
return "Hashtable test failed (5)";
|
||||
}
|
||||
|
||||
Hashtable< unsigned int,unsigned int > test3;
|
||||
for(unsigned int i=0;i<1111;++i)
|
||||
test3[i] = i;
|
||||
if (test3.size() != 1111) {
|
||||
ZT_T_PRINTF("FAILED (size() incorrect)" ZT_EOL_S);
|
||||
return "Hashtable test failed (size() incorrect)";
|
||||
}
|
||||
for(unsigned int i=0;i<1111;++i) {
|
||||
if (test3[i] != i) {
|
||||
ZT_T_PRINTF("FAILED (lookup test)" ZT_EOL_S);
|
||||
return "Hashtable test failed (lookup)";
|
||||
}
|
||||
}
|
||||
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: %s" ZT_EOL_S,e.what());
|
||||
return e.what();
|
||||
|
@ -277,12 +401,129 @@ extern "C" const char *ZTT_general()
|
|||
ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: unknown exception" ZT_EOL_S);
|
||||
return "an unknown exception occurred";
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" const char *ZTT_crypto()
|
||||
{
|
||||
try {
|
||||
{
|
||||
ZT_T_PRINTF("[crypto] Testing SHA384 and SHA512... ");
|
||||
uint8_t h[64];
|
||||
SHA512(h,SHA512_TV0_INPUT,strlen(SHA512_TV0_INPUT));
|
||||
if (memcmp(h,SHA512_TV0_DIGEST,64) != 0) {
|
||||
ZT_T_PRINTF("FAILED (SHA512)" ZT_EOL_S);
|
||||
return "SHA512 test vector failed";
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
SHA384(h,SHA512_TV0_INPUT,strlen(SHA512_TV0_INPUT));
|
||||
if (memcmp(h,SHA512_TV0_SHA384_DIGEST,48) != 0) {
|
||||
ZT_T_PRINTF("FAILED (SHA384)" ZT_EOL_S);
|
||||
return "SHA384 test vector failed";
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t agree0[32],agree1[32],kh[64],sig[96];
|
||||
ZT_T_PRINTF("[crypto] Testing C25519/Ed25519... ");
|
||||
for(int t=0;t<ZT_NUM_C25519_TEST_VECTORS;++t) {
|
||||
C25519::agree(C25519_TEST_VECTORS[t].priv1,C25519_TEST_VECTORS[t].pub2,agree0);
|
||||
C25519::agree(C25519_TEST_VECTORS[t].priv2,C25519_TEST_VECTORS[t].pub1,agree1);
|
||||
if (memcmp(agree0,agree1,32) != 0) {
|
||||
ZT_T_PRINTF("FAILED (keys do not agree, vector %d)" ZT_EOL_S,t);
|
||||
return "Curve25519 key agreement test failed (a/b does not agree with b/a)";
|
||||
}
|
||||
SHA512(kh,agree0,32);
|
||||
if (memcmp(kh,C25519_TEST_VECTORS[t].agreementSha512,64) != 0) {
|
||||
ZT_T_PRINTF("FAILED (hash of agreement does not match test vector %d)" ZT_EOL_S,t);
|
||||
return "Curve25519 key agreement test failed (does not match expected value)";
|
||||
}
|
||||
C25519::sign(C25519_TEST_VECTORS[t].priv1,C25519_TEST_VECTORS[t].pub1,kh,64,sig);
|
||||
if (memcmp(sig,C25519_TEST_VECTORS[t].agreementSignedBy1,96) != 0) {
|
||||
ZT_T_PRINTF("FAILED (signature of agreement by key 1 does not match test vector %d)" ZT_EOL_S,t);
|
||||
return "Curve25519 signature test failed (signature by key 1 does not match expected value)";
|
||||
}
|
||||
C25519::sign(C25519_TEST_VECTORS[t].priv2,C25519_TEST_VECTORS[t].pub2,kh,64,sig);
|
||||
if (memcmp(sig,C25519_TEST_VECTORS[t].agreementSignedBy1,96) != 0) {
|
||||
ZT_T_PRINTF("FAILED (signature of agreement by key 2 does not match test vector %d)" ZT_EOL_S,t);
|
||||
return "Curve25519 signature test failed (signature by key 2 does not match expected value)";
|
||||
}
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t key[48];
|
||||
ZT_T_PRINTF("[crypto] Testing ECC384 (NIST P-384)... ");
|
||||
ECC384ECDH(ECC384_TV0_PUBLIC,ECC384_TV0_PRIVATE,key);
|
||||
if (memcmp(key,ECC384_TV0_DH_SELF_AGREE,48) != 0) {
|
||||
ZT_T_PRINTF("FAILED (test vector 0, self-agree)" ZT_EOL_S);
|
||||
return "ECC384 test vector 0 self-agree failed";
|
||||
}
|
||||
if (!ECC384ECDSAVerify(ECC384_TV0_PUBLIC,ECC384_TV0_PUBLIC,ECC384_TV0_SIG)) {
|
||||
ZT_T_PRINTF("FAILED (test vector 0, signature check)" ZT_EOL_S);
|
||||
return "ECC384 test vector 0 signature check failed";
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t ks[64];
|
||||
ZT_T_PRINTF("[crypto] Testing Salsa20... ");
|
||||
Salsa20 s20;
|
||||
s20.init(SALSA20_TV0_KEY,SALSA20_TV0_IV);
|
||||
memset(ks,0,sizeof(ks));
|
||||
s20.crypt20(ks,ks,sizeof(ks));
|
||||
if (memcmp(ks,SALSA20_TV0_KS,64) != 0) {
|
||||
ZT_T_PRINTF("FAILED (Salsa20 test vector)" ZT_EOL_S);
|
||||
return "Salsa20 test vector failed";
|
||||
}
|
||||
s20.init(SALSA12_TV0_KEY,SALSA12_TV0_IV);
|
||||
memset(ks,0,sizeof(ks));
|
||||
s20.crypt12(ks,ks,sizeof(ks));
|
||||
if (memcmp(ks,SALSA12_TV0_KS,64) != 0) {
|
||||
ZT_T_PRINTF("FAILED (Salsa12 test vector)" ZT_EOL_S);
|
||||
return "Salsa12 test vector failed";
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t tag[16];
|
||||
ZT_T_PRINTF("[crypto] Testing Poly1305... ");
|
||||
poly1305(tag,POLY1305_TV0_INPUT,sizeof(POLY1305_TV0_INPUT),POLY1305_TV0_KEY);
|
||||
if (memcmp(tag,POLY1305_TV0_TAG,16) != 0) {
|
||||
ZT_T_PRINTF("FAILED (test vector 0)");
|
||||
return "poly1305 test vector 0 failed";
|
||||
}
|
||||
poly1305(tag,POLY1305_TV1_INPUT,sizeof(POLY1305_TV1_INPUT),POLY1305_TV1_KEY);
|
||||
if (memcmp(tag,POLY1305_TV1_TAG,16) != 0) {
|
||||
ZT_T_PRINTF("FAILED (test vector 1)");
|
||||
return "poly1305 test vector 1 failed";
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t out[16];
|
||||
ZT_T_PRINTF("[crypto] Testing AES (hardware acceleration: %s)... ",AES::accelerated() ? "enabled" : "disabled");
|
||||
AES aes(AES_TEST_VECTOR_0_KEY);
|
||||
aes.encrypt(AES_TEST_VECTOR_0_IN,out);
|
||||
if (memcmp(AES_TEST_VECTOR_0_OUT,out,16) != 0) {
|
||||
}
|
||||
aes.decrypt(out,out);
|
||||
if (memcmp(AES_TEST_VECTOR_0_IN,out,16) != 0) {
|
||||
}
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
} catch (std::exception &e) {
|
||||
ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: %s" ZT_EOL_S,e.what());
|
||||
return e.what();
|
||||
} catch ( ... ) {
|
||||
ZT_T_PRINTF(ZT_EOL_S "[crypto] Unexpected exception: unknown exception" ZT_EOL_S);
|
||||
return "an unknown exception occurred";
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -259,18 +259,28 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
|||
{
|
||||
static Mutex globalLock;
|
||||
static bool initialized = false;
|
||||
static uint64_t randomState[8];
|
||||
static uint64_t randomBuf[8192];
|
||||
static unsigned int randomPtr = 65536;
|
||||
static uint64_t randomState[16]; // secret state
|
||||
static uint64_t randomBuf[8192]; // next batch of random bytes
|
||||
static unsigned long randomPtr = sizeof(randomBuf); // refresh on first iteration
|
||||
|
||||
// This secure random function gets entropy from the system random source (e.g. /dev/urandom),
|
||||
// CPU random instructions if present, and other sources and uses them to initialize a SHA/AES
|
||||
// based CSPRNG with a large state. System random sources are not used directly to mitigate
|
||||
// against cases where the system random source is broken in some way, which does happen from
|
||||
// time to time.
|
||||
|
||||
Mutex::Lock gl(globalLock);
|
||||
|
||||
for(unsigned int i=0;i<bytes;++i) {
|
||||
if (randomPtr >= 65536) {
|
||||
if (randomPtr >= sizeof(randomBuf)) {
|
||||
randomPtr = 0;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
|
||||
// Fill both randomState and randomBuf from system random source. Failure here
|
||||
// is fatal to the running application and indicates a serious system problem.
|
||||
// This is some of the only OS-specific code in the core.
|
||||
#ifdef __WINDOWS__
|
||||
HCRYPTPROV cryptProvider = NULL;
|
||||
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
|
||||
|
@ -292,12 +302,12 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
|||
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to open /dev/urandom\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((int)::read(devURandomFd,randomState,sizeof(randomState)) != (int)sizeof(randomState)) {
|
||||
if ((long)::read(devURandomFd,randomState,sizeof(randomState)) != (long)sizeof(randomState)) {
|
||||
::close(devURandomFd);
|
||||
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
|
||||
if ((long)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (long)sizeof(randomBuf)) {
|
||||
::close(devURandomFd);
|
||||
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||
exit(1);
|
||||
|
@ -305,29 +315,40 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
|||
close(devURandomFd);
|
||||
#endif
|
||||
|
||||
// Mix in additional entropy just in case the standard random source is wonky somehow
|
||||
// Mix in additional entropy from time, the address of 'buf', rdrand if present, etc.
|
||||
randomState[0] ^= (uint64_t)time(nullptr);
|
||||
randomState[1] ^= (uint64_t)((uintptr_t)buf);
|
||||
#ifdef __UNIX_LIKE__
|
||||
randomState[2] ^= (uint64_t)getpid();
|
||||
randomState[3] ^= (uint64_t)getppid();
|
||||
#endif
|
||||
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
|
||||
if (CPUID.rdrand) {
|
||||
uint64_t tmp = 0;
|
||||
_rdrand64_step((unsigned long long *)&tmp);
|
||||
randomState[2] ^= tmp;
|
||||
_rdrand64_step((unsigned long long *)&tmp);
|
||||
randomState[3] ^= tmp;
|
||||
for(int i=0;i<16;++i) {
|
||||
_rdrand64_step((unsigned long long *)&tmp);
|
||||
randomState[i] ^= tmp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
++randomState[0];
|
||||
SHA512(randomState,randomState,sizeof(randomState));
|
||||
AES aes(reinterpret_cast<const uint8_t *>(randomState));
|
||||
// Generate a new randomBuf:
|
||||
//
|
||||
// (1) Generate next randomState by perturbing, hashing, and replacing the first 384 bits with the hash.
|
||||
// (2) Initialize AES using the first 256 bits of the new randomState as its key.
|
||||
// (3) Initialize a 128-bit counter field using the following 128 bits of randomState.
|
||||
// (4) Encrypt randomBuf with AES-CTR (machine-endian counter since spec conformance doesn't matter).
|
||||
|
||||
++randomState[15];
|
||||
SHA384(randomState,randomState,sizeof(randomState));
|
||||
AES aes(randomState);
|
||||
uint64_t ctr[2],tmp[2];
|
||||
ctr[0] = randomState[6];
|
||||
ctr[1] = randomState[7];
|
||||
ctr[0] = randomState[4];
|
||||
ctr[1] = randomState[5]; // AES key + CTR/nonce = part replaced each time by SHA384
|
||||
for(int k=0;k<8192;) {
|
||||
++ctr[0];
|
||||
aes.encrypt(reinterpret_cast<const uint8_t *>(ctr),reinterpret_cast<uint8_t *>(tmp));
|
||||
aes.encrypt(ctr,tmp);
|
||||
randomBuf[k] ^= tmp[0];
|
||||
randomBuf[k+1] ^= tmp[1];
|
||||
k += 2;
|
||||
|
@ -421,7 +442,6 @@ int b32d(const char *encoded,uint8_t *result,int bufSize) noexcept
|
|||
return count;
|
||||
}
|
||||
|
||||
#define ROL64(x,k) (((x) << (k)) | ((x) >> (64 - (k))))
|
||||
uint64_t random() noexcept
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/Xorshift#xoshiro256**
|
||||
|
@ -434,14 +454,15 @@ uint64_t random() noexcept
|
|||
uint64_t s1 = s_s1;
|
||||
uint64_t s2 = s_s2;
|
||||
uint64_t s3 = s_s3;
|
||||
const uint64_t result = ROL64(s1 * 5,7U) * 9;
|
||||
const uint64_t s1x5 = s1 * 5;
|
||||
const uint64_t result = ((s1x5 << 7U)|(s1x5 >> 57U)) * 9;
|
||||
const uint64_t t = s1 << 17U;
|
||||
s2 ^= s0;
|
||||
s3 ^= s1;
|
||||
s1 ^= s2;
|
||||
s0 ^= s3;
|
||||
s2 ^= t;
|
||||
s3 = ROL64(s3,45U);
|
||||
s3 = ((s3 << 45U)|(s3 >> 19U));
|
||||
s_s0 = s0;
|
||||
s_s1 = s1;
|
||||
s_s2 = s2;
|
||||
|
|
Loading…
Add table
Reference in a new issue