New Buffer implementation (not used yet) and cleanup

This commit is contained in:
Adam Ierymenko 2020-01-10 15:28:27 -08:00
parent 2fbeaaf148
commit 83eacdfada
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
9 changed files with 684 additions and 112 deletions

View file

@ -14,10 +14,6 @@
#include "Constants.hpp"
#include "AES.hpp"
// This file contains the software implementations of AES and GHASH. They're
// only used if your CPU lacks hardware acceleration as the hardware
// accelerated code is 10-20X as fast in most cases.
#ifdef __WINDOWS__
#include <intrin.h>
#endif
@ -48,28 +44,6 @@ static inline void writeuint32_t(void *out,const uint32_t v)
#define writeuint32_t(o,v) (*((uint32_t *)(o)) = Utils::hton(v))
#endif
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
static bool _zt_aesni_supported()
{
#ifdef __WINDOWS__
int regs[4];
__cpuid(regs,1);
return ( (((regs[2] >> 25) & 1) != 0) && (((regs[2] >> 19) & 1) != 0) && (((regs[2] >> 1) & 1) != 0) ); // AES-NI, SSE4.1, PCLMUL
#else
uint32_t eax,ebx,ecx,edx;
__asm__ __volatile__ (
"cpuid"
: "=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)
: "a"(1),"c"(0)
);
return ( ((ecx & (1 << 25)) != 0) && ((ecx & (1 << 19)) != 0) && ((ecx & (1 << 1)) != 0) ); // AES-NI, SSE4.1, PCLMUL
#endif
}
const bool AES::HW_ACCEL = _zt_aesni_supported();
#else
const bool AES::HW_ACCEL = false;
#endif
const uint32_t AES::Te0[256] = { 0xc66363a5,0xf87c7c84,0xee777799,0xf67b7b8d,0xfff2f20d,0xd66b6bbd,0xde6f6fb1,0x91c5c554,0x60303050,0x02010103,0xce6767a9,0x562b2b7d,0xe7fefe19,0xb5d7d762,0x4dababe6,0xec76769a,0x8fcaca45,0x1f82829d,0x89c9c940,0xfa7d7d87,0xeffafa15,0xb25959eb,0x8e4747c9,0xfbf0f00b,0x41adadec,0xb3d4d467,0x5fa2a2fd,0x45afafea,0x239c9cbf,0x53a4a4f7,0xe4727296,0x9bc0c05b,0x75b7b7c2,0xe1fdfd1c,0x3d9393ae,0x4c26266a,0x6c36365a,0x7e3f3f41,0xf5f7f702,0x83cccc4f,0x6834345c,0x51a5a5f4,0xd1e5e534,0xf9f1f108,0xe2717193,0xabd8d873,0x62313153,0x2a15153f,0x0804040c,0x95c7c752,0x46232365,0x9dc3c35e,0x30181828,0x379696a1,0x0a05050f,0x2f9a9ab5,0x0e070709,0x24121236,0x1b80809b,0xdfe2e23d,0xcdebeb26,0x4e272769,0x7fb2b2cd,0xea75759f,0x1209091b,0x1d83839e,0x582c2c74,0x341a1a2e,0x361b1b2d,0xdc6e6eb2,0xb45a5aee,0x5ba0a0fb,0xa45252f6,0x763b3b4d,0xb7d6d661,0x7db3b3ce,0x5229297b,0xdde3e33e,0x5e2f2f71,0x13848497,0xa65353f5,0xb9d1d168,0x00000000,0xc1eded2c,0x40202060,0xe3fcfc1f,0x79b1b1c8,0xb65b5bed,0xd46a6abe,0x8dcbcb46,0x67bebed9,0x7239394b,0x944a4ade,0x984c4cd4,0xb05858e8,0x85cfcf4a,0xbbd0d06b,0xc5efef2a,0x4faaaae5,0xedfbfb16,0x864343c5,0x9a4d4dd7,0x66333355,0x11858594,0x8a4545cf,0xe9f9f910,0x04020206,0xfe7f7f81,0xa05050f0,0x783c3c44,0x259f9fba,0x4ba8a8e3,0xa25151f3,0x5da3a3fe,0x804040c0,0x058f8f8a,0x3f9292ad,0x219d9dbc,0x70383848,0xf1f5f504,0x63bcbcdf,0x77b6b6c1,0xafdada75,0x42212163,0x20101030,0xe5ffff1a,0xfdf3f30e,0xbfd2d26d,0x81cdcd4c,0x180c0c14,0x26131335,0xc3ecec2f,0xbe5f5fe1,0x359797a2,0x884444cc,0x2e171739,0x93c4c457,0x55a7a7f2,0xfc7e7e82,0x7a3d3d47,0xc86464ac,0xba5d5de7,0x3219192b,0xe6737395,0xc06060a0,0x19818198,0x9e4f4fd1,0xa3dcdc7f,0x44222266,0x542a2a7e,0x3b9090ab,0x0b888883,0x8c4646ca,0xc7eeee29,0x6bb8b8d3,0x2814143c,0xa7dede79,0xbc5e5ee2,0x160b0b1d,0xaddbdb76,0xdbe0e03b,0x64323256,0x743a3a4e,0x140a0a1e,0x924949db,0x0c06060a,0x4824246c,0xb85c5ce4,0x9fc2c25d,0xbdd3d36e,0x43acacef,0xc46262a6,0x399191a8,0x319595a4,0xd3e4e437,0xf279798b,0xd5e7e732,0x8bc8c843,0x6e373759,0xda6d6db7,0x018d8d8c,0xb1d5d564,0x9c4e4ed2,0x49a9a9e0,0xd86c6cb4,0xac5656fa,0xf3f4f407,0xcfeaea25,0xca6565af,0xf47a7a8e,0x47aeaee9,0x10080818,0x6fbabad5,0xf0787888,0x4a25256f,0x5c2e2e72,0x381c1c24,0x57a6a6f1,0x73b4b4c7,0x97c6c651,0xcbe8e823,0xa1dddd7c,0xe874749c,0x3e1f1f21,0x964b4bdd,0x61bdbddc,0x0d8b8b86,0x0f8a8a85,0xe0707090,0x7c3e3e42,0x71b5b5c4,0xcc6666aa,0x904848d8,0x06030305,0xf7f6f601,0x1c0e0e12,0xc26161a3,0x6a35355f,0xae5757f9,0x69b9b9d0,0x17868691,0x99c1c158,0x3a1d1d27,0x279e9eb9,0xd9e1e138,0xebf8f813,0x2b9898b3,0x22111133,0xd26969bb,0xa9d9d970,0x078e8e89,0x339494a7,0x2d9b9bb6,0x3c1e1e22,0x15878792,0xc9e9e920,0x87cece49,0xaa5555ff,0x50282878,0xa5dfdf7a,0x038c8c8f,0x59a1a1f8,0x09898980,0x1a0d0d17,0x65bfbfda,0xd7e6e631,0x844242c6,0xd06868b8,0x824141c3,0x299999b0,0x5a2d2d77,0x1e0f0f11,0x7bb0b0cb,0xa85454fc,0x6dbbbbd6,0x2c16163a };
const uint32_t AES::Te1[256] = { 0xa5c66363,0x84f87c7c,0x99ee7777,0x8df67b7b,0x0dfff2f2,0xbdd66b6b,0xb1de6f6f,0x5491c5c5,0x50603030,0x03020101,0xa9ce6767,0x7d562b2b,0x19e7fefe,0x62b5d7d7,0xe64dabab,0x9aec7676,0x458fcaca,0x9d1f8282,0x4089c9c9,0x87fa7d7d,0x15effafa,0xebb25959,0xc98e4747,0x0bfbf0f0,0xec41adad,0x67b3d4d4,0xfd5fa2a2,0xea45afaf,0xbf239c9c,0xf753a4a4,0x96e47272,0x5b9bc0c0,0xc275b7b7,0x1ce1fdfd,0xae3d9393,0x6a4c2626,0x5a6c3636,0x417e3f3f,0x02f5f7f7,0x4f83cccc,0x5c683434,0xf451a5a5,0x34d1e5e5,0x08f9f1f1,0x93e27171,0x73abd8d8,0x53623131,0x3f2a1515,0x0c080404,0x5295c7c7,0x65462323,0x5e9dc3c3,0x28301818,0xa1379696,0x0f0a0505,0xb52f9a9a,0x090e0707,0x36241212,0x9b1b8080,0x3ddfe2e2,0x26cdebeb,0x694e2727,0xcd7fb2b2,0x9fea7575,0x1b120909,0x9e1d8383,0x74582c2c,0x2e341a1a,0x2d361b1b,0xb2dc6e6e,0xeeb45a5a,0xfb5ba0a0,0xf6a45252,0x4d763b3b,0x61b7d6d6,0xce7db3b3,0x7b522929,0x3edde3e3,0x715e2f2f,0x97138484,0xf5a65353,0x68b9d1d1,0x00000000,0x2cc1eded,0x60402020,0x1fe3fcfc,0xc879b1b1,0xedb65b5b,0xbed46a6a,0x468dcbcb,0xd967bebe,0x4b723939,0xde944a4a,0xd4984c4c,0xe8b05858,0x4a85cfcf,0x6bbbd0d0,0x2ac5efef,0xe54faaaa,0x16edfbfb,0xc5864343,0xd79a4d4d,0x55663333,0x94118585,0xcf8a4545,0x10e9f9f9,0x06040202,0x81fe7f7f,0xf0a05050,0x44783c3c,0xba259f9f,0xe34ba8a8,0xf3a25151,0xfe5da3a3,0xc0804040,0x8a058f8f,0xad3f9292,0xbc219d9d,0x48703838,0x04f1f5f5,0xdf63bcbc,0xc177b6b6,0x75afdada,0x63422121,0x30201010,0x1ae5ffff,0x0efdf3f3,0x6dbfd2d2,0x4c81cdcd,0x14180c0c,0x35261313,0x2fc3ecec,0xe1be5f5f,0xa2359797,0xcc884444,0x392e1717,0x5793c4c4,0xf255a7a7,0x82fc7e7e,0x477a3d3d,0xacc86464,0xe7ba5d5d,0x2b321919,0x95e67373,0xa0c06060,0x98198181,0xd19e4f4f,0x7fa3dcdc,0x66442222,0x7e542a2a,0xab3b9090,0x830b8888,0xca8c4646,0x29c7eeee,0xd36bb8b8,0x3c281414,0x79a7dede,0xe2bc5e5e,0x1d160b0b,0x76addbdb,0x3bdbe0e0,0x56643232,0x4e743a3a,0x1e140a0a,0xdb924949,0x0a0c0606,0x6c482424,0xe4b85c5c,0x5d9fc2c2,0x6ebdd3d3,0xef43acac,0xa6c46262,0xa8399191,0xa4319595,0x37d3e4e4,0x8bf27979,0x32d5e7e7,0x438bc8c8,0x596e3737,0xb7da6d6d,0x8c018d8d,0x64b1d5d5,0xd29c4e4e,0xe049a9a9,0xb4d86c6c,0xfaac5656,0x07f3f4f4,0x25cfeaea,0xafca6565,0x8ef47a7a,0xe947aeae,0x18100808,0xd56fbaba,0x88f07878,0x6f4a2525,0x725c2e2e,0x24381c1c,0xf157a6a6,0xc773b4b4,0x5197c6c6,0x23cbe8e8,0x7ca1dddd,0x9ce87474,0x213e1f1f,0xdd964b4b,0xdc61bdbd,0x860d8b8b,0x850f8a8a,0x90e07070,0x427c3e3e,0xc471b5b5,0xaacc6666,0xd8904848,0x05060303,0x01f7f6f6,0x121c0e0e,0xa3c26161,0x5f6a3535,0xf9ae5757,0xd069b9b9,0x91178686,0x5899c1c1,0x273a1d1d,0xb9279e9e,0x38d9e1e1,0x13ebf8f8,0xb32b9898,0x33221111,0xbbd26969,0x70a9d9d9,0x89078e8e,0xa7339494,0xb62d9b9b,0x223c1e1e,0x92158787,0x20c9e9e9,0x4987cece,0xffaa5555,0x78502828,0x7aa5dfdf,0x8f038c8c,0xf859a1a1,0x80098989,0x171a0d0d,0xda65bfbf,0x31d7e6e6,0xc6844242,0xb8d06868,0xc3824141,0xb0299999,0x775a2d2d,0x111e0f0f,0xcb7bb0b0,0xfca85454,0xd66dbbbb,0x3a2c1616 };
const uint32_t AES::Te2[256] = { 0x63a5c663,0x7c84f87c,0x7799ee77,0x7b8df67b,0xf20dfff2,0x6bbdd66b,0x6fb1de6f,0xc55491c5,0x30506030,0x01030201,0x67a9ce67,0x2b7d562b,0xfe19e7fe,0xd762b5d7,0xabe64dab,0x769aec76,0xca458fca,0x829d1f82,0xc94089c9,0x7d87fa7d,0xfa15effa,0x59ebb259,0x47c98e47,0xf00bfbf0,0xadec41ad,0xd467b3d4,0xa2fd5fa2,0xafea45af,0x9cbf239c,0xa4f753a4,0x7296e472,0xc05b9bc0,0xb7c275b7,0xfd1ce1fd,0x93ae3d93,0x266a4c26,0x365a6c36,0x3f417e3f,0xf702f5f7,0xcc4f83cc,0x345c6834,0xa5f451a5,0xe534d1e5,0xf108f9f1,0x7193e271,0xd873abd8,0x31536231,0x153f2a15,0x040c0804,0xc75295c7,0x23654623,0xc35e9dc3,0x18283018,0x96a13796,0x050f0a05,0x9ab52f9a,0x07090e07,0x12362412,0x809b1b80,0xe23ddfe2,0xeb26cdeb,0x27694e27,0xb2cd7fb2,0x759fea75,0x091b1209,0x839e1d83,0x2c74582c,0x1a2e341a,0x1b2d361b,0x6eb2dc6e,0x5aeeb45a,0xa0fb5ba0,0x52f6a452,0x3b4d763b,0xd661b7d6,0xb3ce7db3,0x297b5229,0xe33edde3,0x2f715e2f,0x84971384,0x53f5a653,0xd168b9d1,0x00000000,0xed2cc1ed,0x20604020,0xfc1fe3fc,0xb1c879b1,0x5bedb65b,0x6abed46a,0xcb468dcb,0xbed967be,0x394b7239,0x4ade944a,0x4cd4984c,0x58e8b058,0xcf4a85cf,0xd06bbbd0,0xef2ac5ef,0xaae54faa,0xfb16edfb,0x43c58643,0x4dd79a4d,0x33556633,0x85941185,0x45cf8a45,0xf910e9f9,0x02060402,0x7f81fe7f,0x50f0a050,0x3c44783c,0x9fba259f,0xa8e34ba8,0x51f3a251,0xa3fe5da3,0x40c08040,0x8f8a058f,0x92ad3f92,0x9dbc219d,0x38487038,0xf504f1f5,0xbcdf63bc,0xb6c177b6,0xda75afda,0x21634221,0x10302010,0xff1ae5ff,0xf30efdf3,0xd26dbfd2,0xcd4c81cd,0x0c14180c,0x13352613,0xec2fc3ec,0x5fe1be5f,0x97a23597,0x44cc8844,0x17392e17,0xc45793c4,0xa7f255a7,0x7e82fc7e,0x3d477a3d,0x64acc864,0x5de7ba5d,0x192b3219,0x7395e673,0x60a0c060,0x81981981,0x4fd19e4f,0xdc7fa3dc,0x22664422,0x2a7e542a,0x90ab3b90,0x88830b88,0x46ca8c46,0xee29c7ee,0xb8d36bb8,0x143c2814,0xde79a7de,0x5ee2bc5e,0x0b1d160b,0xdb76addb,0xe03bdbe0,0x32566432,0x3a4e743a,0x0a1e140a,0x49db9249,0x060a0c06,0x246c4824,0x5ce4b85c,0xc25d9fc2,0xd36ebdd3,0xacef43ac,0x62a6c462,0x91a83991,0x95a43195,0xe437d3e4,0x798bf279,0xe732d5e7,0xc8438bc8,0x37596e37,0x6db7da6d,0x8d8c018d,0xd564b1d5,0x4ed29c4e,0xa9e049a9,0x6cb4d86c,0x56faac56,0xf407f3f4,0xea25cfea,0x65afca65,0x7a8ef47a,0xaee947ae,0x08181008,0xbad56fba,0x7888f078,0x256f4a25,0x2e725c2e,0x1c24381c,0xa6f157a6,0xb4c773b4,0xc65197c6,0xe823cbe8,0xdd7ca1dd,0x749ce874,0x1f213e1f,0x4bdd964b,0xbddc61bd,0x8b860d8b,0x8a850f8a,0x7090e070,0x3e427c3e,0xb5c471b5,0x66aacc66,0x48d89048,0x03050603,0xf601f7f6,0x0e121c0e,0x61a3c261,0x355f6a35,0x57f9ae57,0xb9d069b9,0x86911786,0xc15899c1,0x1d273a1d,0x9eb9279e,0xe138d9e1,0xf813ebf8,0x98b32b98,0x11332211,0x69bbd269,0xd970a9d9,0x8e89078e,0x94a73394,0x9bb62d9b,0x1e223c1e,0x87921587,0xe920c9e9,0xce4987ce,0x55ffaa55,0x28785028,0xdf7aa5df,0x8c8f038c,0xa1f859a1,0x89800989,0x0d171a0d,0xbfda65bf,0xe631d7e6,0x42c68442,0x68b8d068,0x41c38241,0x99b02999,0x2d775a2d,0x0f111e0f,0xb0cb7bb0,0x54fca854,0xbbd66dbb,0x163a2c16 };
@ -175,6 +149,39 @@ void AES::_encryptSW(const uint8_t in[16],uint8_t out[16]) const
writeuint32_t(out + 12,(Te2[(t3 >> 24)] & 0xff000000) ^ (Te3[(t0 >> 16) & 0xff] & 0x00ff0000) ^ (Te0[(t1 >> 8) & 0xff] & 0x0000ff00) ^ (Te1[(t2) & 0xff] & 0x000000ff) ^ rk[59]);
}
void AES::_ctrSW(const uint8_t iv[16],const void *in,unsigned int len,void *out) const
{
uint64_t ctr[2],cenc[2];
memcpy(ctr,iv,16);
uint64_t bctr = Utils::ntoh(ctr[1]);
const uint8_t *i = (const uint8_t *)in;
uint8_t *o = (uint8_t *)out;
while (len >= 16) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
ctr[1] = Utils::hton(++bctr);
#ifdef ZT_NO_TYPE_PUNNING
for(unsigned int k=0;k<16;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
#else
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[0];
o += 8;
i += 8;
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[1];
o += 8;
i += 8;
#endif
len -= 16;
}
if (len) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
for(unsigned int k=0;k<len;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
}
}
#if (defined(__GNUC__) || defined(__clang)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64) || defined(__aarch64__))
#if defined(__SIZEOF_INT128__)
@ -337,9 +344,8 @@ void AES::_gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_
for(unsigned int i=0;i<8;++i) ((uint8_t *)&y1)[i] ^= *(in++);
#else
y0 ^= *((const uint64_t *)in);
in += 8;
y1 ^= *((const uint64_t *)in);
in += 8;
y1 ^= *((const uint64_t *)(in + 8));
in += 16;
#endif
s_gfmul(h0,h1,y0,y1);
len -= 16;

View file

@ -21,45 +21,36 @@
#include <cstdint>
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <xmmintrin.h>
#include <wmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#define ZT_AES_AESNI 1
#endif // x64
#endif
namespace ZeroTier {
/**
* AES-256 and pals
* AES-256 and pals including GMAC, CTR, etc.
*/
class AES
{
public:
/**
* This will be true if your platform's type of AES acceleration is supported on this machine
*/
static const bool HW_ACCEL;
inline AES() {}
inline AES(const uint8_t key[32]) { this->init(key); }
inline ~AES() { Utils::burn(&_k,sizeof(_k)); }
ZT_ALWAYS_INLINE AES() {}
ZT_ALWAYS_INLINE AES(const uint8_t key[32]) { this->init(key); }
ZT_ALWAYS_INLINE ~AES() { Utils::burn(&_k,sizeof(_k)); }
/**
* Set (or re-set) this AES256 cipher's key
*/
inline void init(const uint8_t key[32])
ZT_ALWAYS_INLINE void init(const uint8_t key[32])
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
if (likely(Utils::CPUID.aes)) {
_init_aesni(key);
return;
}
#endif
_initSW(key);
}
@ -69,15 +60,14 @@ public:
* @param in Input block
* @param out Output block (can be same as input)
*/
inline void encrypt(const uint8_t in[16],uint8_t out[16]) const
ZT_ALWAYS_INLINE void encrypt(const uint8_t in[16],uint8_t out[16]) const
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
if (likely(Utils::CPUID.aes)) {
_encrypt_aesni(in,out);
return;
}
#endif
_encryptSW(in,out);
}
@ -89,15 +79,14 @@ public:
* @param len Length of input
* @param out 128-bit authorization tag from GMAC
*/
inline void gmac(const uint8_t iv[12],const void *in,const unsigned int len,uint8_t out[16]) const
ZT_ALWAYS_INLINE void gmac(const uint8_t iv[12],const void *in,const unsigned int len,uint8_t out[16]) const
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
if (likely(Utils::CPUID.aes)) {
_gmac_aesni(iv,(const uint8_t *)in,len,out);
return;
}
#endif
_gmacSW(iv,(const uint8_t *)in,len,out);
}
@ -113,44 +102,15 @@ public:
* @param len Length of input
* @param out Output plaintext or ciphertext
*/
inline void ctr(const uint8_t iv[16],const void *in,unsigned int len,void *out) const
ZT_ALWAYS_INLINE void ctr(const uint8_t iv[16],const void *in,unsigned int len,void *out) const
{
#ifdef ZT_AES_AESNI
if (likely(HW_ACCEL)) {
if (likely(Utils::CPUID.aes)) {
_ctr_aesni(_k.ni.k,iv,(const uint8_t *)in,len,(uint8_t *)out);
return;
}
#endif
uint64_t ctr[2],cenc[2];
memcpy(ctr,iv,16);
uint64_t bctr = Utils::ntoh(ctr[1]);
const uint8_t *i = (const uint8_t *)in;
uint8_t *o = (uint8_t *)out;
while (len >= 16) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
ctr[1] = Utils::hton(++bctr);
#ifdef ZT_NO_TYPE_PUNNING
for(unsigned int k=0;k<16;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
#else
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[0];
o += 8;
i += 8;
*((uint64_t *)o) = *((const uint64_t *)i) ^ cenc[1];
o += 8;
i += 8;
#endif
len -= 16;
}
if (len) {
_encryptSW((const uint8_t *)ctr,(uint8_t *)cenc);
for(unsigned int k=0;k<len;++k)
*(o++) = *(i++) ^ ((uint8_t *)cenc)[k];
}
_ctrSW(iv,in,len,out);
}
/**
@ -326,6 +286,7 @@ private:
void _initSW(const uint8_t key[32]);
void _encryptSW(const uint8_t in[16],uint8_t out[16]) const;
void _ctrSW(const uint8_t iv[16],const void *in,unsigned int len,void *out) const;
void _gmacSW(const uint8_t iv[12],const uint8_t *in,unsigned int len,uint8_t out[16]) const;
/**************************************************************************/
@ -432,7 +393,7 @@ private:
#endif /*********************************************************************/
#ifdef ZT_AES_AESNI /********************************************************/
static inline __m128i _init256_1_aesni(__m128i a,__m128i b)
static ZT_ALWAYS_INLINE __m128i _init256_1_aesni(__m128i a,__m128i b)
{
__m128i x,y;
b = _mm_shuffle_epi32(b,0xff);
@ -445,7 +406,7 @@ private:
x = _mm_xor_si128(x,b);
return x;
}
static inline __m128i _init256_2_aesni(__m128i a,__m128i b)
static ZT_ALWAYS_INLINE __m128i _init256_2_aesni(__m128i a,__m128i b)
{
__m128i x,y,z;
y = _mm_aeskeygenassist_si128(a,0x00);
@ -459,7 +420,7 @@ private:
x = _mm_xor_si128(x,z);
return x;
}
inline void _init_aesni(const uint8_t key[32])
ZT_ALWAYS_INLINE void _init_aesni(const uint8_t key[32])
{
__m128i t1,t2;
_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i *)key);
@ -505,7 +466,7 @@ private:
_k.ni.hhhh = _mm_shuffle_epi8(hhhh,shuf);
}
inline void _encrypt_aesni(const void *in,void *out) const
ZT_ALWAYS_INLINE void _encrypt_aesni(const void *in,void *out) const
{
__m128i tmp;
tmp = _mm_loadu_si128((const __m128i *)in);
@ -526,7 +487,7 @@ private:
_mm_storeu_si128((__m128i *)out,_mm_aesenclast_si128(tmp,_k.ni.k[14]));
}
static inline __m128i _mult_block_aesni(__m128i shuf,__m128i h,__m128i y)
ZT_ALWAYS_INLINE inline __m128i _mult_block_aesni(__m128i shuf,__m128i h,__m128i y)
{
y = _mm_shuffle_epi8(y,shuf);
__m128i t1 = _mm_clmulepi64_si128(h,y,0x00);
@ -568,7 +529,7 @@ private:
}
static inline __m128i _ghash_aesni(__m128i shuf,__m128i h,__m128i y,__m128i x) { return _mult_block_aesni(shuf,h,_mm_xor_si128(y,x)); }
inline void _gmac_aesni(const uint8_t iv[12],const uint8_t *in,const unsigned int len,uint8_t out[16]) const
ZT_ALWAYS_INLINE void _gmac_aesni(const uint8_t iv[12],const uint8_t *in,const unsigned int len,uint8_t out[16]) const
{
const __m128i *const ab = (const __m128i *)in;
const unsigned int blocks = len / 16;
@ -687,7 +648,7 @@ private:
#define ZT_AES_CTR_AESNI_ROUND(kk) c0 = _mm_aesenc_si128(c0,kk); c1 = _mm_aesenc_si128(c1,kk); c2 = _mm_aesenc_si128(c2,kk); c3 = _mm_aesenc_si128(c3,kk);
static inline void _ctr_aesni(const __m128i key[14],const uint8_t iv[16],const uint8_t *in,unsigned int len,uint8_t *out)
static ZT_ALWAYS_INLINE void _ctr_aesni(const __m128i key[14],const uint8_t iv[16],const uint8_t *in,unsigned int len,uint8_t *out)
{
/* Because our CTR supports full 128-bit nonces, we must do a full 128-bit (big-endian)
* increment to be compatible with canonical NIST-certified CTR implementations. That's

View file

@ -113,11 +113,6 @@ public:
*/
ZT_ALWAYS_INLINE char *toString(char buf[11]) const { return Utils::hex10(_a,buf); }
/**
* @return True if this address is not zero
*/
ZT_ALWAYS_INLINE operator bool() const { return (_a != 0); }
/**
* Check if this address is reserved
*
@ -127,7 +122,7 @@ public:
*
* @return True if address is reserved and may not be used
*/
ZT_ALWAYS_INLINE bool isReserved() const { return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); }
ZT_ALWAYS_INLINE bool isReserved() const { return ((!_a)||((_a >> 32U) == ZT_ADDRESS_RESERVED_PREFIX)); }
/**
* @param i Value from 0 to 4 (inclusive)
@ -135,6 +130,7 @@ public:
*/
ZT_ALWAYS_INLINE uint8_t operator[](unsigned int i) const { return (uint8_t)(_a >> (32 - (i * 8))); }
explicit ZT_ALWAYS_INLINE operator bool() const { return (_a != 0); }
explicit ZT_ALWAYS_INLINE operator unsigned int() const { return (unsigned int)_a; }
explicit ZT_ALWAYS_INLINE operator unsigned long() const { return (unsigned long)_a; }
explicit ZT_ALWAYS_INLINE operator unsigned long long() const { return (unsigned long long)_a; }

View file

@ -24,25 +24,30 @@ namespace ZeroTier {
/**
* Simple atomic counter supporting increment and decrement
*
* This is used as the reference counter in reference counted objects that
* work with SharedPtr<>.
*/
class AtomicCounter
{
public:
ZT_ALWAYS_INLINE AtomicCounter() { _v = 0; }
ZT_ALWAYS_INLINE AtomicCounter() : _v(0) {}
ZT_ALWAYS_INLINE int load() const
{
#ifdef __GNUC__
return __sync_or_and_fetch(const_cast<int *>(&_v),0);
return _v;
#else
return _v.load();
#endif
}
ZT_ALWAYS_INLINE void zero() { _v = 0; }
ZT_ALWAYS_INLINE int operator++()
{
#ifdef __GNUC__
return __sync_add_and_fetch(&_v,1);
return __sync_add_and_fetch((int *)&_v,1);
#else
return ++_v;
#endif
@ -51,7 +56,7 @@ public:
ZT_ALWAYS_INLINE int operator--()
{
#ifdef __GNUC__
return __sync_sub_and_fetch(&_v,1);
return __sync_sub_and_fetch((int *)&_v,1);
#else
return --_v;
#endif
@ -62,7 +67,7 @@ private:
ZT_ALWAYS_INLINE const AtomicCounter &operator=(const AtomicCounter &) { return *this; }
#ifdef __GNUC__
int _v;
volatile int _v;
#else
std::atomic_int _v;
#endif

116
node/Buf.cpp Normal file
View file

@ -0,0 +1,116 @@
/*
* Copyright (c)2019 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2023-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#include "Buf.hpp"
#ifndef __GNUC__
#include <atomic>
#endif
namespace ZeroTier {
#ifdef __GNUC__
static uintptr_t s_pool = 0;
#else
static std::atomic<uintptr_t> s_pool(0);
#endif
void Buf::operator delete(void *ptr,std::size_t sz)
{
if (ptr) {
uintptr_t bb;
const uintptr_t locked = ~((uintptr_t)0);
for (;;) {
#ifdef __GNUC__
bb = __sync_fetch_and_or(&s_pool,locked); // get value of s_pool and "lock" by filling with all 1's
#else
bb = s_pool.fetch_or(locked);
#endif
if (bb != locked)
break;
}
((Buf *)ptr)->__nextInPool = bb;
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,(uintptr_t)ptr);
#else
s_pool.store((uintptr_t)ptr);
#endif
}
}
SharedPtr<Buf> Buf::get()
{
uintptr_t bb;
const uintptr_t locked = ~((uintptr_t)0);
for (;;) {
#ifdef __GNUC__
bb = __sync_fetch_and_or(&s_pool,locked); // get value of s_pool and "lock" by filling with all 1's
#else
bb = s_pool.fetch_or(locked);
#endif
if (bb != locked)
break;
}
Buf *b;
if (bb == 0) {
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,bb);
#else
s_pool.store(bb);
#endif
b = (Buf *)malloc(sizeof(Buf));
if (!b)
return SharedPtr<Buf>();
} else {
b = (Buf *)bb;
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,b->__nextInPool);
#else
s_pool.store(b->__nextInPool);
#endif
}
b->__refCount.zero();
return SharedPtr<Buf>(b);
}
void Buf::freePool()
{
uintptr_t bb;
const uintptr_t locked = ~((uintptr_t)0);
for (;;) {
#ifdef __GNUC__
bb = __sync_fetch_and_or(&s_pool,locked); // get value of s_pool and "lock" by filling with all 1's
#else
bb = s_pool.fetch_or(locked);
#endif
if (bb != locked)
break;
}
#ifdef __GNUC__
__sync_fetch_and_and(&s_pool,(uintptr_t)0);
#else
s_pool.store((uintptr_t)0);
#endif
while (bb != 0) {
uintptr_t next = ((Buf *)bb)->__nextInPool;
free((void *)bb);
bb = next;
}
}
} // namespace ZeroTier

467
node/Buf.hpp Normal file
View file

@ -0,0 +1,467 @@
/*
* Copyright (c)2019 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2023-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#ifndef ZT_BUF_HPP
#define ZT_BUF_HPP
#include "Constants.hpp"
#include "AtomicCounter.hpp"
#include "Utils.hpp"
#include "SharedPtr.hpp"
#include "Mutex.hpp"
#include <cstdint>
#include <cstring>
#include <cstdlib>
// Buffers are 16384 bytes in size because this is the smallest size that can hold any packet
// and is a power of two. It needs to be a power of two because masking is significantly faster
// than integer division modulus.
#define ZT_BUF_MEM_SIZE 0x00004000
#define ZT_BUF_MEM_MASK 0x00003fffU
namespace ZeroTier {
/**
* Buffer and methods for branch-free bounds-checked data assembly and parsing
*
* This implements an extremely fast buffer for packet assembly and parsing that avoids
* branching whenever possible. To be safe it must be used correctly!
*
* The read methods are prefixed by 'r', and write methods with 'w'. All methods take
* an iterator, which is just an int that should be initialized to 0 (or whatever starting
* position is desired). All read methods will advance the iterator regardless of outcome.
*
* Read and write methods fail silently in the event of overflow. They do not corrupt or
* access memory outside the bounds of Buf, but will otherwise produce undefined results.
*
* IT IS THE RESPONSIBILITY OF THE USER of this class to use the readOverflow() and
* writeOverflow() static methods to check the iterator for overflow after each series
* of reads and writes and BEFORE ANY PARSING or other decisions are made on the basis
* of the data obtained from a buffer. Failure to do so can result in bugs due
* to parsing and branching on undefined or corrupt data.
*
* ^^ THIS IS VERY IMPORTANT ^^
*
* A typical packet assembly consists of repeated calls to the write methods followed by
* a check to writeOverflow() before final packet armoring and transport. A typical packet
* disassembly and parsing consists of a series of read calls to obtain the packet's
* fields followed by a call to readOverflow() to check that these fields are valid. The
* packet is discarded if readOverflow() returns true. Some packet parsers may make
* additional reads and in this case readOverflow() must be checked after each set of
* reads to ensure that overflow did not occur.
*
* Buf uses a lock-free pool for extremely fast allocation and deallocation.
*/
class Buf
{
friend class SharedPtr<Buf>;
private:
// Direct construction isn't allowed; use get().
ZT_ALWAYS_INLINE Buf() {}
ZT_ALWAYS_INLINE Buf(const Buf &b) {}
public:
static void operator delete(void *ptr,std::size_t sz);
/**
* Get obtains a buffer from the pool or allocates a new buffer if the pool is empty
*
* @return Buffer
*/
static SharedPtr<Buf> get();
/**
* Free buffers in the pool
*
* New buffers will be created and the pool repopulated if get() is called
* and outstanding buffers will still be returned to the pool. This just
* frees buffers currently held in reserve.
*/
static void freePool();
/**
* Check for overflow beyond the size of the buffer
*
* This is used to check for overflow when writing. It returns true if the iterator
* has passed beyond the capacity of the buffer.
*
* @param ii Iterator to check
* @return True if iterator has read past the size of the buffer
*/
static ZT_ALWAYS_INLINE bool writeOverflow(const int &ii) { return ((ii - ZT_BUF_MEM_SIZE) > 0); }
/**
* Check for overflow beyond the size of the data that should be in the buffer
*
* This is used to check for overflow when reading, with the second argument being the
* size of the meaningful data actually present in the buffer.
*
* @param ii Iterator to check
* @param size Size of data that should be in buffer
* @return True if iterator has read past the size of the data
*/
static ZT_ALWAYS_INLINE bool readOverflow(const int &ii,const unsigned int size) { return ((ii - (int)size) > 0); }
////////////////////////////////////////////////////////////////////////////
// Read methods
////////////////////////////////////////////////////////////////////////////
/**
* Read a byte
*
* @param ii Iterator
* @return Byte (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint8_t rI8(int &ii) const
{
const unsigned int s = (unsigned int)ii++;
return data[s & ZT_BUF_MEM_MASK];
}
/**
* Read a 16-bit integer
*
* @param ii Integer
* @return Integer (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint16_t rI16(int &ii) const
{
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 2;
#ifdef ZT_NO_TYPE_PUNNING
return (
((uint16_t)data[s] << 8U) |
(uint16_t)data[s + 1]);
#else
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(data + s));
#endif
}
/**
* Read a 32-bit integer
*
* @param ii Integer
* @return Integer (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint32_t rI32(int &ii) const
{
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 4;
#ifdef ZT_NO_TYPE_PUNNING
return (
((uint32_t)data[s] << 24U) |
((uint32_t)data[s + 1] << 16U) |
((uint32_t)data[s + 2] << 8U) |
(uint32_t)data[s + 3]);
#else
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(data + s));
#endif
}
/**
* Read a 64-bit integer
*
* @param ii Integer
* @return Integer (undefined on overflow)
*/
ZT_ALWAYS_INLINE uint64_t rI64(int &ii) const
{
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 8;
#ifdef ZT_NO_TYPE_PUNNING
return (
((uint64_t)data[s] << 56U) |
((uint64_t)data[s + 1] << 48U) |
((uint64_t)data[s + 2] << 40U) |
((uint64_t)data[s + 3] << 32U) |
((uint64_t)data[s + 4] << 24U) |
((uint64_t)data[s + 5] << 16U) |
((uint64_t)data[s + 6] << 8U) |
(uint64_t)data[s + 7]);
#else
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(data + s));
#endif
}
/**
* Read an object supporting the marshal/unmarshal interface
*
* If the return value is negative the object's state is undefined. A return value of
* zero typically also indicates a problem, though this may depend on the object type.
*
* Since objects may be invalid even if there is no overflow, it's important to check
* the return value of this function in all cases and discard invalid packets as it
* indicates.
*
* @tparam T Object type
* @param ii Iterator
* @param obj Object to read
* @return Bytes read or a negative value on unmarshal error (passed from object) or overflow
*/
template<typename T>
ZT_ALWAYS_INLINE int rO(int &ii,T &obj) const
{
if (ii < ZT_BUF_MEM_SIZE) {
int ms = obj.unmarshal(data + ii, ZT_BUF_MEM_SIZE - ii);
if (ms > 0)
ii += ms;
return ms;
}
return -1;
}
/**
* Read a C-style string from the buffer, making a copy and advancing the iterator
*
* Use this if the buffer's memory may get changed between reading and processing
* what is read.
*
* @param ii Iterator
* @param buf Buffer to receive string
* @param bufSize Capacity of buffer in bytes
* @return Pointer to buf or NULL on overflow or error
*/
ZT_ALWAYS_INLINE char *rS(int &ii,char *const buf,const unsigned int bufSize) const
{
const char *const s = (const char *)(data + ii);
const int sii = ii;
while (ii < ZT_BUF_MEM_SIZE) {
if (data[ii++] == 0) {
memcpy(buf,s,ii - sii);
return buf;
}
}
return nullptr;
}
/**
* Obtain a pointer to a C-style string in the buffer without copying and advance the iterator
*
* The iterator is advanced even if this fails and returns NULL so that readOverflow()
* will indicate that an overflow occurred. As with other reads the string's contents are
* undefined if readOverflow() returns true.
*
* This version avoids a copy and so is faster if the buffer won't be modified between
* reading and processing.
*
* @param ii Iterator
* @return Pointer to null-terminated C-style string or NULL on overflow or error
*/
ZT_ALWAYS_INLINE const char *rSnc(int &ii) const
{
const char *const s = (const char *)(data + ii);
while (ii < ZT_BUF_MEM_SIZE) {
if (data[ii++] == 0)
return s;
}
return nullptr;
}
/**
* Read a byte array from the buffer, making a copy and advancing the iterator
*
* Use this if the buffer's memory may get changed between reading and processing
* what is read.
*
* @param ii Iterator
* @param bytes Buffer to contain data to read
* @param len Length of buffer
* @return Pointer to data or NULL on overflow or error
*/
ZT_ALWAYS_INLINE void *rB(int &ii,void *bytes,unsigned int len) const
{
const void *const b = (const void *)(data + ii);
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE) {
memcpy(bytes, b, len);
return bytes;
}
return nullptr;
}
/**
* Obtain a pointer to a field in the buffer without copying and advance the iterator
*
* The iterator is advanced even if this fails and returns NULL so that readOverflow()
* will indicate that an overflow occurred.
*
* This version avoids a copy and so is faster if the buffer won't be modified between
* reading and processing.
*
* @param ii Iterator
* @param len Length of data field to obtain a pointer to
* @return Pointer to field or NULL on overflow
*/
ZT_ALWAYS_INLINE const void *rBnc(int &ii,unsigned int len) const
{
const void *const b = (const void *)(data + ii);
return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr;
}
////////////////////////////////////////////////////////////////////////////
// Write methods
////////////////////////////////////////////////////////////////////////////
/**
* Write a byte
*
* @param ii Iterator
* @param n Byte
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint8_t n)
{
const unsigned int s = (unsigned int)ii++;
data[s & ZT_BUF_MEM_MASK] = n;
}
/**
* Write a 16-bit integer in big-endian byte order
*
* @param ii Iterator
* @param n Integer
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint16_t n)
{
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 2;
#ifdef ZT_NO_TYPE_PUNNING
data[s] = (uint8_t)(n >> 8U);
data[s + 1] = (uint8_t)n;
#else
*reinterpret_cast<uint16_t *>(data + s) = Utils::hton(n);
#endif
}
/**
* Write a 32-bit integer in big-endian byte order
*
* @param ii Iterator
* @param n Integer
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint32_t n)
{
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 4;
#ifdef ZT_NO_TYPE_PUNNING
data[s] = (uint8_t)(n >> 24U);
data[s + 1] = (uint8_t)(n >> 16U);
data[s + 2] = (uint8_t)(n >> 8U);
data[s + 3] = (uint8_t)n;
#else
*reinterpret_cast<uint32_t *>(data + s) = Utils::hton(n);
#endif
}
/**
* Write a 64-bit integer in big-endian byte order
*
* @param ii Iterator
* @param n Integer
*/
ZT_ALWAYS_INLINE void wI(int &ii,uint64_t n)
{
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 8;
#ifdef ZT_NO_TYPE_PUNNING
data[s] = (uint8_t)(n >> 56U);
data[s + 1] = (uint8_t)(n >> 48U);
data[s + 2] = (uint8_t)(n >> 40U);
data[s + 3] = (uint8_t)(n >> 32U);
data[s + 4] = (uint8_t)(n >> 24U);
data[s + 5] = (uint8_t)(n >> 16U);
data[s + 6] = (uint8_t)(n >> 8U);
data[s + 7] = (uint8_t)n;
#else
*reinterpret_cast<uint64_t *>(data + s) = Utils::hton(n);
#endif
}
/**
* Write an object implementing the marshal interface
*
* @tparam T Object type
* @param ii Iterator
* @param t Object to write
*/
template<typename T>
ZT_ALWAYS_INLINE void wO(int &ii,T &t)
{
const unsigned int s = (unsigned int)ii;
if ((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE) {
int ms = t.marshal(data + s);
if (ms > 0)
ii += ms;
} else {
ii += T::marshalSizeMax(); // mark as overflowed even if we didn't do anything
}
}
/**
* Write a C-style null-terminated string (including the trailing zero)
*
* @param ii Iterator
* @param s String to write (writes an empty string if this is NULL)
*/
ZT_ALWAYS_INLINE void wS(int &ii,const char *s)
{
if (s) {
char c;
do {
c = *(s++);
wI(ii,(uint8_t)c);
} while (c);
} else {
wI(ii,(uint8_t)0);
}
}
/**
* Write a byte array
*
* @param ii Iterator
* @param bytes Bytes to write
* @param len Size of data in bytes
*/
ZT_ALWAYS_INLINE void wB(int &ii,const void *const bytes,const unsigned int len)
{
unsigned int s = (unsigned int)ii;
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE)
memcpy(data + s, bytes, len);
}
////////////////////////////////////////////////////////////////////////////
ZT_ALWAYS_INLINE Buf &operator=(const Buf &b)
{
if (&b != this)
memcpy(data,b.data,ZT_BUF_MEM_SIZE);
return *this;
}
/**
* Raw buffer
*
* The extra eight bytes permit silent overflow of integer types without reading or writing
* beyond Buf's memory and without branching or extra masks. They can be ignored otherwise.
*/
uint8_t data[ZT_BUF_MEM_SIZE + 8];
private:
volatile uintptr_t __nextInPool;
AtomicCounter __refCount;
};
} // namespace ZeroTier
#endif

View file

@ -8,6 +8,7 @@ endif(WIN32)
set(core_headers
Address.hpp
AtomicCounter.hpp
Buf.hpp
Buffer.hpp
C25519.hpp
Capability.hpp
@ -50,6 +51,7 @@ set(core_headers
set(core_src
AES.cpp
Buf.cpp
C25519.cpp
Credential.cpp
ECC384.cpp

View file

@ -32,31 +32,33 @@
#include "AES.hpp"
#include "SHA512.hpp"
namespace ZeroTier {
namespace Utils {
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <immintrin.h>
static bool _zt_rdrand_supported()
CPUIDRegisters::CPUIDRegisters()
{
#ifdef __WINDOWS__
int regs[4];
__cpuid(regs,1);
return (((regs[2] >> 30) & 1) != 0);
eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3];
#else
uint32_t eax,ebx,ecx,edx;
__asm__ __volatile__ (
"cpuid"
: "=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)
: "a"(1),"c"(0)
);
return ((ecx & (1 << 30)) != 0);
#endif
rdrand = ((ecx & (1U << 30U)) != 0);
aes = ( ((ecx & (1U << 25U)) != 0) && ((ecx & (1U << 19U)) != 0) && ((ecx & (1U << 1U)) != 0) ); // AES, PCLMUL, SSE4.1
}
static const bool _rdrandSupported = _zt_rdrand_supported();
CPUIDRegisters CPUID;
#endif
namespace ZeroTier {
namespace Utils {
const char HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
bool secureEq(const void *a,const void *b,unsigned int len)
@ -213,7 +215,7 @@ void getSecureRandom(void *buf,unsigned int bytes)
randomState[0] ^= (uint64_t)time(nullptr);
randomState[1] ^= (uint64_t)((uintptr_t)buf);
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
if (_rdrandSupported) {
if (CPUID.rdrand) {
uint64_t tmp = 0;
_rdrand64_step((unsigned long long *)&tmp);
randomState[2] ^= tmp;

View file

@ -20,6 +20,12 @@
#include <cstring>
#include <ctime>
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <emmintrin.h>
#include <xmmintrin.h>
#include <immintrin.h>
#endif
#include <string>
#include <stdexcept>
#include <vector>
@ -31,6 +37,17 @@ namespace ZeroTier {
namespace Utils {
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
struct CPUIDRegisters
{
uint32_t eax,ebx,ecx,edx;
bool rdrand;
bool aes;
CPUIDRegisters();
};
extern CPUIDRegisters CPUID;
#endif
/**
* Hexadecimal characters 0-f
*/