mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 13:03:45 +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
|
set(src
|
||||||
GoGlue.cpp
|
GoGlue.cpp
|
||||||
CoreTests.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(headers
|
set(headers
|
||||||
|
|
18
node/AES.hpp
18
node/AES.hpp
|
@ -64,22 +64,24 @@ public:
|
||||||
*
|
*
|
||||||
* @param key 256-bit key
|
* @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)); }
|
ZT_ALWAYS_INLINE ~AES() { Utils::burn(&_k,sizeof(_k)); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set (or re-set) this AES256 cipher's key
|
* 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
|
#ifdef ZT_AES_AESNI
|
||||||
if (likely(Utils::CPUID.aes)) {
|
if (likely(Utils::CPUID.aes)) {
|
||||||
_init_aesni(key);
|
_init_aesni(reinterpret_cast<const uint8_t *>(key));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_initSW(key);
|
_initSW(reinterpret_cast<const uint8_t *>(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,7 +90,7 @@ public:
|
||||||
* @param in Input block
|
* @param in Input block
|
||||||
* @param out Output block (can be same as input)
|
* @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
|
#ifdef ZT_AES_AESNI
|
||||||
if (likely(Utils::CPUID.aes)) {
|
if (likely(Utils::CPUID.aes)) {
|
||||||
|
@ -96,7 +98,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#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 in Input block
|
||||||
* @param out Output block (can be same as input)
|
* @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
|
#ifdef ZT_AES_AESNI
|
||||||
if (likely(Utils::CPUID.aes)) {
|
if (likely(Utils::CPUID.aes)) {
|
||||||
|
@ -113,7 +115,7 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#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 "LZ4.hpp"
|
||||||
#include "Hashtable.hpp"
|
#include "Hashtable.hpp"
|
||||||
#include "FCV.hpp"
|
#include "FCV.hpp"
|
||||||
|
#include "SHA512.hpp"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -98,7 +98,7 @@ struct C25519TestVector
|
||||||
uint8_t priv1[64];
|
uint8_t priv1[64];
|
||||||
uint8_t pub2[64];
|
uint8_t pub2[64];
|
||||||
uint8_t priv2[64];
|
uint8_t priv2[64];
|
||||||
uint8_t agreement[64];
|
uint8_t agreementSha512[64];
|
||||||
uint8_t agreementSignedBy1[96];
|
uint8_t agreementSignedBy1[96];
|
||||||
uint8_t agreementSignedBy2[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 {
|
ZT_PACKED_STRUCT(struct StructPackingTestSample {
|
||||||
uint8_t foo;
|
uint8_t foo;
|
||||||
uint16_t bar;
|
uint16_t bar;
|
||||||
|
@ -155,13 +162,41 @@ ZT_PACKED_STRUCT(struct StructPackingTestSample {
|
||||||
uint8_t lol;
|
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_T_ASSERT(e) if (!(e)) { ZT_T_PRINTF("FAILED (simple assert: " #e ")" ZT_EOL_S); return "simple assert: " #e; }
|
||||||
#define ZT_ENDIAN_S "little"
|
|
||||||
#else
|
|
||||||
#define ZT_ENDIAN_S "big"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern "C" const char *ZTT_general()
|
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::Header) == ZT_PROTO_MIN_PACKET_LENGTH);
|
||||||
ZT_T_ASSERT(sizeof(Protocol::FragmentHeader) == ZT_PROTO_MIN_FRAGMENT_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_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);
|
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("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) {
|
} catch (std::exception &e) {
|
||||||
ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: %s" ZT_EOL_S,e.what());
|
ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: %s" ZT_EOL_S,e.what());
|
||||||
return 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);
|
ZT_T_PRINTF(ZT_EOL_S "[general] Unexpected exception: unknown exception" ZT_EOL_S);
|
||||||
return "an unknown exception occurred";
|
return "an unknown exception occurred";
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" const char *ZTT_crypto()
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -259,18 +259,28 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
||||||
{
|
{
|
||||||
static Mutex globalLock;
|
static Mutex globalLock;
|
||||||
static bool initialized = false;
|
static bool initialized = false;
|
||||||
static uint64_t randomState[8];
|
static uint64_t randomState[16]; // secret state
|
||||||
static uint64_t randomBuf[8192];
|
static uint64_t randomBuf[8192]; // next batch of random bytes
|
||||||
static unsigned int randomPtr = 65536;
|
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);
|
Mutex::Lock gl(globalLock);
|
||||||
|
|
||||||
for(unsigned int i=0;i<bytes;++i) {
|
for(unsigned int i=0;i<bytes;++i) {
|
||||||
if (randomPtr >= 65536) {
|
if (randomPtr >= sizeof(randomBuf)) {
|
||||||
randomPtr = 0;
|
randomPtr = 0;
|
||||||
|
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
initialized = true;
|
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__
|
#ifdef __WINDOWS__
|
||||||
HCRYPTPROV cryptProvider = NULL;
|
HCRYPTPROV cryptProvider = NULL;
|
||||||
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
|
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");
|
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to open /dev/urandom\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if ((int)::read(devURandomFd,randomState,sizeof(randomState)) != (int)sizeof(randomState)) {
|
if ((long)::read(devURandomFd,randomState,sizeof(randomState)) != (long)sizeof(randomState)) {
|
||||||
::close(devURandomFd);
|
::close(devURandomFd);
|
||||||
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if ((int)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (int)sizeof(randomBuf)) {
|
if ((long)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (long)sizeof(randomBuf)) {
|
||||||
::close(devURandomFd);
|
::close(devURandomFd);
|
||||||
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -305,29 +315,40 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
||||||
close(devURandomFd);
|
close(devURandomFd);
|
||||||
#endif
|
#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[0] ^= (uint64_t)time(nullptr);
|
||||||
randomState[1] ^= (uint64_t)((uintptr_t)buf);
|
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 (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
|
||||||
if (CPUID.rdrand) {
|
if (CPUID.rdrand) {
|
||||||
uint64_t tmp = 0;
|
uint64_t tmp = 0;
|
||||||
|
for(int i=0;i<16;++i) {
|
||||||
_rdrand64_step((unsigned long long *)&tmp);
|
_rdrand64_step((unsigned long long *)&tmp);
|
||||||
randomState[2] ^= tmp;
|
randomState[i] ^= tmp;
|
||||||
_rdrand64_step((unsigned long long *)&tmp);
|
}
|
||||||
randomState[3] ^= tmp;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
++randomState[0];
|
// Generate a new randomBuf:
|
||||||
SHA512(randomState,randomState,sizeof(randomState));
|
//
|
||||||
AES aes(reinterpret_cast<const uint8_t *>(randomState));
|
// (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];
|
uint64_t ctr[2],tmp[2];
|
||||||
ctr[0] = randomState[6];
|
ctr[0] = randomState[4];
|
||||||
ctr[1] = randomState[7];
|
ctr[1] = randomState[5]; // AES key + CTR/nonce = part replaced each time by SHA384
|
||||||
for(int k=0;k<8192;) {
|
for(int k=0;k<8192;) {
|
||||||
++ctr[0];
|
++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] ^= tmp[0];
|
||||||
randomBuf[k+1] ^= tmp[1];
|
randomBuf[k+1] ^= tmp[1];
|
||||||
k += 2;
|
k += 2;
|
||||||
|
@ -421,7 +442,6 @@ int b32d(const char *encoded,uint8_t *result,int bufSize) noexcept
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ROL64(x,k) (((x) << (k)) | ((x) >> (64 - (k))))
|
|
||||||
uint64_t random() noexcept
|
uint64_t random() noexcept
|
||||||
{
|
{
|
||||||
// https://en.wikipedia.org/wiki/Xorshift#xoshiro256**
|
// https://en.wikipedia.org/wiki/Xorshift#xoshiro256**
|
||||||
|
@ -434,14 +454,15 @@ uint64_t random() noexcept
|
||||||
uint64_t s1 = s_s1;
|
uint64_t s1 = s_s1;
|
||||||
uint64_t s2 = s_s2;
|
uint64_t s2 = s_s2;
|
||||||
uint64_t s3 = s_s3;
|
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;
|
const uint64_t t = s1 << 17U;
|
||||||
s2 ^= s0;
|
s2 ^= s0;
|
||||||
s3 ^= s1;
|
s3 ^= s1;
|
||||||
s1 ^= s2;
|
s1 ^= s2;
|
||||||
s0 ^= s3;
|
s0 ^= s3;
|
||||||
s2 ^= t;
|
s2 ^= t;
|
||||||
s3 = ROL64(s3,45U);
|
s3 = ((s3 << 45U)|(s3 >> 19U));
|
||||||
s_s0 = s0;
|
s_s0 = s0;
|
||||||
s_s1 = s1;
|
s_s1 = s1;
|
||||||
s_s2 = s2;
|
s_s2 = s2;
|
||||||
|
|
Loading…
Add table
Reference in a new issue