diff --git a/node/CMWC4096.hpp b/node/CMWC4096.hpp deleted file mode 100644 index b62d7d672..000000000 --- a/node/CMWC4096.hpp +++ /dev/null @@ -1,91 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_CMWC4096_HPP -#define ZT_CMWC4096_HPP - -#include -#include "Utils.hpp" - -namespace ZeroTier { - -/** - * Complement Multiply With Carry random number generator - * - * Based on original code posted to Usenet in the public domain by - * George Marsaglia. Period is approximately 2^131086. - * - * This is not used for cryptographic purposes but for a very fast - * and high-quality PRNG elsewhere in the code. - */ -class CMWC4096 -{ -public: - /** - * Construct and initialize from secure random source - */ - CMWC4096() - throw() - { - Utils::getSecureRandom(Q,sizeof(Q)); - Utils::getSecureRandom(&c,sizeof(c)); - c %= 809430660; - i = 4095; - } - - inline uint32_t next32() - throw() - { - uint32_t __i = ++i & 4095; - const uint64_t t = (18782ULL * (uint64_t)Q[__i]) + (uint64_t)c; - c = (uint32_t)(t >> 32); - uint32_t x = c + (uint32_t)t; - const uint32_t p = (uint32_t)(x < c); x += p; c += p; - return (Q[__i] = 0xfffffffe - x); - } - - inline uint64_t next64() - throw() - { - return ((((uint64_t)next32()) << 32) ^ (uint64_t)next32()); - } - - inline double nextDouble() - throw() - { - return ((double)(next32()) / 4294967296.0); - } - -private: - uint32_t Q[4096]; - uint32_t c; - uint32_t i; -}; - -} // namespace ZeroTier - -#endif diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 77ea2e66c..3c1052363 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -35,7 +35,6 @@ #include "Switch.hpp" #include "Packet.hpp" #include "Peer.hpp" -#include "CMWC4096.hpp" #include "C25519.hpp" #include "CertificateOfMembership.hpp" @@ -97,7 +96,7 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const // will return different subsets of a large multicast group. k = 0; while ((added < limit)&&(k < gs->second.members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_UDP_DEFAULT_PAYLOAD_MTU)) { - rptr = (unsigned int)RR->prng->next32(); + rptr = (unsigned int)RR->node->prng(); restart_member_scan: a = gs->second.members[rptr % (unsigned int)gs->second.members.size()].address.toInt(); @@ -171,7 +170,7 @@ void Multicaster::send( for(unsigned long i=0;i0;--i) { - unsigned long j = RR->prng->next32() % (i + 1); + unsigned long j = (unsigned long)RR->node->prng() % (i + 1); unsigned long tmp = indexes[j]; indexes[j] = indexes[i]; indexes[i] = tmp; diff --git a/node/Node.cpp b/node/Node.cpp index d8bd8910f..3df34aecb 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -37,7 +37,6 @@ #include "Node.hpp" #include "RuntimeEnvironment.hpp" #include "NetworkController.hpp" -#include "CMWC4096.hpp" #include "Switch.hpp" #include "Multicaster.hpp" #include "AntiRecursion.hpp" @@ -76,6 +75,7 @@ Node::Node( _eventCallback(eventCallback), _networks(), _networks_m(), + _prngStreamPtr(0), _now(now), _lastPingCheck(0), _lastHousekeepingRun(0) @@ -85,6 +85,15 @@ Node::Node( _newestVersionSeen[2] = ZEROTIER_ONE_VERSION_REVISION; _online = false; + // Use Salsa20 alone as a high-quality non-crypto PRNG + { + char foo[32]; + Utils::getSecureRandom(foo,32); + _prng.init(foo,256,foo,8); + memset(_prngStream,0,sizeof(_prngStream)); + _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream)); + } + std::string idtmp(dataStoreGet("identity.secret")); if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) { TRACE("identity.secret not found, generating..."); @@ -103,7 +112,6 @@ Node::Node( } try { - RR->prng = new CMWC4096(); RR->sw = new Switch(RR); RR->mc = new Multicaster(RR); RR->antiRec = new AntiRecursion(); @@ -115,7 +123,6 @@ Node::Node( delete RR->antiRec; delete RR->mc; delete RR->sw; - delete RR->prng; throw; } @@ -146,7 +153,6 @@ Node::~Node() delete RR->antiRec; delete RR->mc; delete RR->sw; - delete RR->prng; } ZT1_ResultCode Node::processWirePacket( @@ -510,6 +516,14 @@ void Node::postTrace(const char *module,unsigned int line,const char *fmt,...) } #endif // ZT_TRACE +uint64_t Node::prng() +{ + unsigned int p = (++_prngStreamPtr % (sizeof(_prngStream) / sizeof(uint64_t))); + if (!p) + _prng.encrypt(_prngStream,_prngStream,sizeof(_prngStream)); + return _prngStream[p]; +} + } // namespace ZeroTier /****************************************************************************/ diff --git a/node/Node.hpp b/node/Node.hpp index fe31576c9..579d3a576 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -44,6 +44,7 @@ #include "MAC.hpp" #include "Network.hpp" #include "Path.hpp" +#include "Salsa20.hpp" #undef TRACE #ifdef ZT_TRACE @@ -219,6 +220,11 @@ public: void postTrace(const char *module,unsigned int line,const char *fmt,...); #endif + /** + * @return Next 64-bit random number (not for cryptographic use) + */ + uint64_t prng(); + private: inline SharedPtr _network(uint64_t nwid) const { @@ -253,6 +259,10 @@ private: Mutex _backgroundTasksLock; + unsigned int _prngStreamPtr; + Salsa20 _prng; + uint64_t _prngStream[16]; // repeatedly encrypted with _prng to yield a high-quality non-crypto PRNG stream + uint64_t _now; uint64_t _lastPingCheck; uint64_t _lastHousekeepingRun; diff --git a/node/RuntimeEnvironment.hpp b/node/RuntimeEnvironment.hpp index 228040e74..e5d1f446b 100644 --- a/node/RuntimeEnvironment.hpp +++ b/node/RuntimeEnvironment.hpp @@ -38,7 +38,6 @@ namespace ZeroTier { class NodeConfig; class Switch; class Topology; -class CMWC4096; class Node; class Multicaster; class AntiRecursion; @@ -55,7 +54,6 @@ public: node(n), identity(), localNetworkController((NetworkController *)0), - prng((CMWC4096 *)0), sw((Switch *)0), mc((Multicaster *)0), antiRec((AntiRecursion *)0), @@ -83,7 +81,6 @@ public: * These are constant and never null after startup unless indicated. */ - CMWC4096 *prng; Switch *sw; Multicaster *mc; AntiRecursion *antiRec; diff --git a/node/Switch.cpp b/node/Switch.cpp index 62fa02cdc..4fd5d7696 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -42,7 +42,6 @@ #include "InetAddress.hpp" #include "Topology.hpp" #include "Peer.hpp" -#include "CMWC4096.hpp" #include "AntiRecursion.hpp" #include "Packet.hpp" @@ -236,7 +235,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c while (numBridges < ZT_MAX_BRIDGE_SPAM) { if (ab == nconf->activeBridges().end()) ab = nconf->activeBridges().begin(); - if (((unsigned long)RR->prng->next32() % (unsigned long)nconf->activeBridges().size()) == 0) { + if (((unsigned long)RR->node->prng() % (unsigned long)nconf->activeBridges().size()) == 0) { bridges[numBridges++] = *ab; ++ab; } else ++ab; @@ -327,7 +326,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) * the order we make each attempted NAT-t favor one or the other going * first, meaning if it doesn't succeed the first time it might the second * and so forth. */ - unsigned int alt = RR->prng->next32() & 1; + unsigned int alt = (unsigned int)RR->node->prng() & 1; unsigned int completed = alt + 2; while (alt != completed) { if ((alt & 1) == 0) {