Преглед на файлове

Integrating new crypto, work still in progress...

Adam Ierymenko преди 12 години
родител
ревизия
ceb024ab03
променени са 8 файла, в които са добавени 126 реда и са изтрити 203 реда
  1. 51 1
      node/Identity.cpp
  2. 0 1
      node/Node.cpp
  3. 25 21
      node/NodeConfig.cpp
  4. 30 37
      node/Packet.hpp
  5. 12 12
      node/PacketDecoder.cpp
  6. 5 5
      node/Switch.cpp
  7. 0 100
      node/Utils.cpp
  8. 3 26
      node/Utils.hpp

+ 51 - 1
node/Identity.cpp

@@ -71,14 +71,64 @@ std::string Identity::toString(bool includePrivate) const
 
 	r.append(_address.toString());
 	r.append(":2:"); // 2 == IDENTITY_TYPE_C25519
+	r.append(Utils::hex(_publicKey.data,_publicKey.size()));
+	r.push_back(':');
+	r.append(Utils::hex(_signature.data,_signature.size()));
+	if ((_privateKey)&&(includePrivate)) {
+		r.push_back(':');
+		r.append(Utils::hex(_privateKey.data,_privateKey.size()));
+	}
 
 	return r;
 }
 
 bool Identity::fromString(const char *str)
 {
+	char *saveptr = (char *)0;
+	char tmp[4096];
+	if (!Utils::scopy(tmp,sizeof(tmp),str))
+		return false;
+
+	delete _privateKey;
+	_privateKey = (C25519::Private *)0;
+
+	int fno = 0;
+	for(char *f=Utils::stok(tmp,":",&saveptr);(f);f=Utils::stok((char *)0,":",&saveptr)) {
+		switch(fno++) {
+			case 0:
+				_address = Address(f);
+				if (_address.isReserved())
+					return false;
+				break;
+			case 1:
+				if (strcmp(f,"2"))
+					return false;
+				break;
+			case 2:
+				if (Utils::unhex(f,_publicKey.data,_publicKey.size()) != _publicKey.size())
+					return false;
+				break;
+			case 3:
+				if (Utils::unhex(f,_signature.data,_signature.size()) != _signature.size())
+					return false;
+				break;
+			case 4:
+				_privateKey = new C25519::Private();
+				if (Utils::unhex(f,_privateKey->data,_privateKey->size()) != _privateKey->size())
+					return false;
+				break;
+			default:
+				return false;
+		}
+	}
+	if (fno < 4)
+		return false;
+
+	return true;
 }
 
+// These are fixed parameters and can't be changed without a new
+// identity type.
 #define ZT_IDENTITY_DERIVEADDRESS_DIGESTS 540672
 #define ZT_IDENTITY_DERIVEADDRESS_ROUNDS 4
 
@@ -91,7 +141,7 @@ Address Identity::deriveAddress(const void *keyBytes,unsigned int keyLen)
 	 * unfortunately cannot be used here. If that were used, it would be
 	 * equivalently costly to simply increment/vary the public key and find
 	 * a collision as it would be to find the address. We need something
-	 * that creates a costly 1:~1 mapping from key to address, hence this odd
+	 * that creates a costly 1:~1 mapping from key to address, hence this
 	 * algorithm.
 	 *
 	 * Search for "sequential memory hard algorithm" for academic references

+ 0 - 1
node/Node.cpp

@@ -57,7 +57,6 @@
 #include "Logger.hpp"
 #include "InetAddress.hpp"
 #include "Salsa20.hpp"
-#include "HMAC.hpp"
 #include "RuntimeEnvironment.hpp"
 #include "NodeConfig.hpp"
 #include "Defaults.hpp"

+ 25 - 21
node/NodeConfig.cpp

@@ -35,8 +35,6 @@
 #include <map>
 #include <set>
 
-#include <openssl/sha.h>
-
 #include "Constants.hpp"
 
 #ifdef __WINDOWS__
@@ -54,7 +52,8 @@
 #include "InetAddress.hpp"
 #include "Peer.hpp"
 #include "Salsa20.hpp"
-#include "HMAC.hpp"
+#include "Poly1305.hpp"
+#include "SHA512.hpp"
 #include "Node.hpp"
 
 #ifdef __WINDOWS__
@@ -68,10 +67,11 @@ NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken)
 	_r(renv),
 	_controlSocket(true,ZT_CONTROL_UDP_PORT,false,&_CBcontrolPacketHandler,this)
 {
-	SHA256_CTX sha;
-	SHA256_Init(&sha);
-	SHA256_Update(&sha,authToken,strlen(authToken));
-	SHA256_Final(_controlSocketKey,&sha);
+	{
+		unsigned int csk[64];
+		SHA512::hash(authToken,strlen(authToken));
+		memcpy(_controlSocketKey,csk,32);
+	}
 
 	std::map<std::string,bool> networksDotD(Utils::listDirectory((_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str()));
 	std::set<uint64_t> nwids;
@@ -249,12 +249,13 @@ std::vector<std::string> NodeConfig::execute(const char *command)
 std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > NodeConfig::encodeControlMessage(const void *key,unsigned long conversationId,const std::vector<std::string> &payload)
 	throw(std::out_of_range)
 {
-	char hmac[32];
+	char poly1305tag[ZT_POLY1305_MAC_LEN];
+	char iv[8];
 	char keytmp[32];
 	std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > packets;
 	Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> packet;
 
-	packet.setSize(16); // room for HMAC and IV
+	packet.setSize(16); // room for poly1305 auth tag and IV
 	packet.append((uint32_t)(conversationId & 0xffffffff));
 
 	for(unsigned int i=0;i<payload.size();++i) {
@@ -262,20 +263,21 @@ std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > NodeConfig::encodeControlMe
 		packet.append((unsigned char)0);
 
 		if (((i + 1) >= payload.size())||((packet.size() + payload[i + 1].length() + 1) >= packet.capacity())) {
-			Utils::getSecureRandom(packet.field(8,8),8);
+			Utils::getSecureRandom(iv,8);
+			memcpy(packet.field(8,8),iv,8);
 
-			Salsa20 s20(key,256,packet.field(8,8));
+			Salsa20 s20(key,256,iv);
 			s20.encrypt(packet.field(16,packet.size() - 16),packet.field(16,packet.size() - 16),packet.size() - 16);
 
 			memcpy(keytmp,key,32);
-			for(unsigned int i=0;i<32;++i)
-				keytmp[i] ^= 0x77; // use a different permutation of key for HMAC than for Salsa20
-			HMAC::sha256(keytmp,32,packet.field(16,packet.size() - 16),packet.size() - 16,hmac);
-			memcpy(packet.field(0,8),hmac,8);
+			for(unsigned int i=0;i<8;++i)
+				keytmp[i] ^= iv[i]; // can't reuse poly1305 keys, so mangle key with IV each time
+			Poly1305::compute(poly1305tag,packet.field(16,packet.size() - 16),packet.size() - 16,keytmp);
+			memcpy(packet.field(0,8),poly1305tag,8);
 
 			packets.push_back(packet);
 
-			packet.setSize(16); // room for HMAC and IV
+			packet.setSize(16); // room for poly1305 auth tag and IV
 			packet.append((uint32_t)(conversationId & 0xffffffff));
 		}
 	}
@@ -285,8 +287,9 @@ std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > NodeConfig::encodeControlMe
 
 bool NodeConfig::decodeControlMessagePacket(const void *key,const void *data,unsigned int len,unsigned long &conversationId,std::vector<std::string> &payload)
 {
-	char hmac[32];
+	char poly1305tag[ZT_POLY1305_MAC_LEN];
 	char keytmp[32];
+	char iv[8];
 
 	try {
 		if (len < 20)
@@ -295,10 +298,11 @@ bool NodeConfig::decodeControlMessagePacket(const void *key,const void *data,uns
 		Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> packet(data,len);
 
 		memcpy(keytmp,key,32);
-		for(unsigned int i=0;i<32;++i)
-			keytmp[i] ^= 0x77; // use a different permutation of key for HMAC than for Salsa20
-		HMAC::sha256(keytmp,32,packet.field(16,packet.size() - 16),packet.size() - 16,hmac);
-		if (memcmp(packet.field(0,8),hmac,8))
+		memcpy(iv,packet.field(8,8),8);
+		for(unsigned int i=0;i<8;++i)
+			keytmp[i] ^= iv[i];
+		Poly1305::compute(poly1305tag,packet.field(16,packet.size() - 16),packet.size() - 16,keytmp);
+		if (!Utils::secureEq(packet.field(0,8),poly1305tag,8))
 			return false;
 
 		Salsa20 s20(key,256,packet.field(8,8));

+ 30 - 37
node/Packet.hpp

@@ -35,7 +35,7 @@
 #include <iostream>
 
 #include "Address.hpp"
-#include "HMAC.hpp"
+#include "Poly1305.hpp"
 #include "Salsa20.hpp"
 #include "Utils.hpp"
 #include "Constants.hpp"
@@ -65,7 +65,7 @@
  * Header flag indicating that a packet is encrypted with Salsa20
  *
  * If this is not set, then the packet's payload is in the clear and the
- * HMAC is over this (since there is no ciphertext). Otherwise the HMAC is
+ * MAC is over this (since there is no ciphertext). Otherwise the MAC is
  * of the ciphertext after encryption.
  */
 #define ZT_PROTO_FLAG_ENCRYPTED 0x80
@@ -89,7 +89,7 @@
 #define ZT_PACKET_IDX_DEST 8
 #define ZT_PACKET_IDX_SOURCE 13
 #define ZT_PACKET_IDX_FLAGS 18
-#define ZT_PACKET_IDX_HMAC 19
+#define ZT_PACKET_IDX_MAC 19
 #define ZT_PACKET_IDX_VERB 27
 #define ZT_PACKET_IDX_PAYLOAD 28
 
@@ -201,7 +201,7 @@ namespace ZeroTier {
  *   <[5] destination ZT address>
  *   <[5] source ZT address>
  *   <[1] flags (LS 5 bits) and ZT hop count (MS 3 bits)>
- *   <[8] first 8 bytes of 32-byte HMAC-SHA-256 MAC>
+ *   <[8] 8-bit MAC (currently first 8 bytes of poly1305 tag)>
  *   [... -- begin encryption envelope -- ...]
  *   <[1] encrypted flags (MS 3 bits) and verb (LS 5 bits)>
  *   [... verb-specific payload ...]
@@ -770,39 +770,39 @@ public:
 	}
 
 	/**
-	 * Compute the HMAC of this packet's payload and set HMAC field
+	 * Generate a message authenticationc code and set MAC field of packet
 	 * 
 	 * For encrypted packets, this must be called after encryption.
 	 *
 	 * @param key 256-bit (32 byte) key
 	 */
-	inline void hmacSet(const void *key)
+	inline void macSet(const void *key)
 	{
-		unsigned char mac[32];
+		unsigned char mac[16];
 		unsigned char key2[32];
 		_mangleKey((const unsigned char *)key,key2);
-		unsigned int hmacLen = (size() >= ZT_PACKET_IDX_VERB) ? (size() - ZT_PACKET_IDX_VERB) : 0;
-		HMAC::sha256(key2,sizeof(key2),field(ZT_PACKET_IDX_VERB,hmacLen),hmacLen,mac);
-		memcpy(field(ZT_PACKET_IDX_HMAC,8),mac,8);
+		unsigned int macLen = (size() >= ZT_PACKET_IDX_VERB) ? (size() - ZT_PACKET_IDX_VERB) : 0;
+		Poly1305::compute(mac,field(ZT_PACKET_IDX_VERB,macLen),macLen,key2);
+		memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8);
 	}
 
 	/**
-	 * Check the HMAC of this packet's payload
+	 * Check the MAC of this packet's payload
 	 * 
 	 * For encrypted packets, this must be checked before decryption.
 	 *
 	 * @param key 256-bit (32 byte) key
 	 */
-	inline bool hmacVerify(const void *key) const
+	inline bool macVerify(const void *key) const
 	{
-		unsigned char mac[32];
+		unsigned char mac[16];
 		unsigned char key2[32];
 		if (size() < ZT_PACKET_IDX_VERB)
 			return false; // incomplete packets fail
 		_mangleKey((const unsigned char *)key,key2);
-		unsigned int hmacLen = size() - ZT_PACKET_IDX_VERB;
-		HMAC::sha256(key2,sizeof(key2),field(ZT_PACKET_IDX_VERB,hmacLen),hmacLen,mac);
-		return (!memcmp(field(ZT_PACKET_IDX_HMAC,8),mac,8));
+		unsigned int macLen = size() - ZT_PACKET_IDX_VERB;
+		Poly1305::compute(mac,field(ZT_PACKET_IDX_VERB,macLen),macLen,key2);
+		return Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8);
 	}
 
 	/**
@@ -895,38 +895,31 @@ public:
 
 private:
 	/**
-	 * Deterministically mangle a 256-bit crypto key based on packet characteristics
-	 * 
-	 * This takes the static agreed-upon input key and mangles it using
-	 * info from the packet. This serves two purposes:
-	 * 
-	 * (1) It reduces the (already minute) probability of a duplicate key /
-	 *     IV combo, which is good since keys are extremely long-lived. Another
-	 *     way of saying this is that it increases the effective IV size by
-	 *     using other parts of the packet as IV material.
-	 * (2) It causes HMAC to fail should any of the following change: ordering
-	 *     of source and dest addresses, flags, IV, or packet size. HMAC has
-	 *     no explicit scheme for AAD (additional authenticated data).
-	 * 
-	 * NOTE: this function will have to be changed if the order of any packet
-	 * fields or their sizes/padding changes in the spec.
+	 * Deterministically mangle a 256-bit crypto key based on packet
 	 *
 	 * @param in Input key (32 bytes)
 	 * @param out Output buffer (32 bytes)
 	 */
 	inline void _mangleKey(const unsigned char *in,unsigned char *out) const
 	{
-		// Random IV (Salsa20 also uses the IV natively, but HMAC doesn't), and
-		// destination and source addresses. Using dest and source addresses
-		// gives us a (likely) different key space for a->b vs b->a.
+		// IV and source/destination addresses. Salsa uses the IV natively
+		// so this is redundant there, but not harmful. But Poly1305 depends
+		// on the key being mangled with the IV. Using the source and
+		// destination addresses bifurcates the key space into a different
+		// key space for each direction of the conversation.
 		for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
 			out[i] = in[i] ^ (unsigned char)(*this)[i];
-		// Flags, but masking off hop count which is altered by forwarding nodes
+
+		// Flags, but with hop count masked off. Hop count is altered by forwarding
+		// nodes. It's one of the only parts of a packet modifiable by people
+		// without the key.
 		out[18] = in[18] ^ ((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & 0xf8);
-		// Raw packet size in bytes -- each raw packet size defines a possibly
-		// different space of keys.
+
+		// Raw packet size in bytes -- thus each packet size defines a new
+		// key space.
 		out[19] = in[19] ^ (unsigned char)(size() & 0xff);
 		out[20] = in[20] ^ (unsigned char)((size() >> 8) & 0xff); // little endian
+
 		// Rest of raw key is used unchanged
 		for(unsigned int i=21;i<32;++i)
 			out[i] = in[i];

+ 12 - 12
node/PacketDecoder.cpp

@@ -75,8 +75,8 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
 		}
 
 		// No saved state? Verify MAC before we proceed.
-		if (!hmacVerify(peer->macKey())) {
-			TRACE("dropped packet from %s(%s), HMAC authentication failed (size: %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),size());
+		if (!macVerify(peer->macKey())) {
+			TRACE("dropped packet from %s(%s), authentication failed (size: %u)",source().toString().c_str(),_remoteAddress.toString().c_str(),size());
 			return true;
 		}
 
@@ -85,7 +85,7 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
 			decrypt(peer->cryptKey());
 		} else {
 			// Unencrypted is tolerated in case we want to run this on
-			// devices where squeezing out cycles matters. HMAC is
+			// devices where squeezing out cycles matters. MAC is
 			// what's really important. But log it in debug to catch any
 			// packets being mistakenly sent in the clear.
 			TRACE("ODD: %s from %s(%s) wasn't encrypted",Packet::verbString(verb()),source().toString().c_str(),_remoteAddress.toString().c_str());
@@ -130,7 +130,7 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
 				return _doNETWORK_CONFIG_REFRESH(_r,peer);
 			default:
 				// This might be something from a new or old version of the protocol.
-				// Technically it passed HMAC so the packet is still valid, but we
+				// Technically it passed MAC so the packet is still valid, but we
 				// ignore it.
 				TRACE("ignored unrecognized verb %.2x from %s(%s)",(unsigned int)v,source().toString().c_str(),_remoteAddress.toString().c_str());
 				return true;
@@ -162,7 +162,7 @@ void PacketDecoder::_CBaddPeerFromHello(void *arg,const SharedPtr<Peer> &p,Topol
 				outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
 				outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
 				outp.encrypt(p->cryptKey());
-				outp.hmacSet(p->macKey());
+				outp.macSet(p->macKey());
 				_r->demarc->send(req->localPort,req->remoteAddress,outp.data(),outp.size(),-1);
 			}	break;
 
@@ -172,7 +172,7 @@ void PacketDecoder::_CBaddPeerFromHello(void *arg,const SharedPtr<Peer> &p,Topol
 				outp.append(req->helloPacketId);
 				outp.append((unsigned char)Packet::ERROR_IDENTITY_INVALID);
 				outp.encrypt(p->cryptKey());
-				outp.hmacSet(p->macKey());
+				outp.macSet(p->macKey());
 				_r->demarc->send(req->localPort,req->remoteAddress,outp.data(),outp.size(),-1);
 			}	break;
 
@@ -183,7 +183,7 @@ void PacketDecoder::_CBaddPeerFromHello(void *arg,const SharedPtr<Peer> &p,Topol
 				outp.append(req->helloPacketId);
 				outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
 				outp.encrypt(p->cryptKey());
-				outp.hmacSet(p->macKey());
+				outp.macSet(p->macKey());
 				_r->demarc->send(req->localPort,req->remoteAddress,outp.data(),outp.size(),-1);
 			}	break;
 		}
@@ -268,7 +268,7 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r)
 			outp.append(packetId());
 			outp.append(timestamp);
 			outp.encrypt(existingPeer->cryptKey());
-			outp.hmacSet(existingPeer->macKey());
+			outp.macSet(existingPeer->macKey());
 			_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
 			return true;
 		}
@@ -353,7 +353,7 @@ bool PacketDecoder::_doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 			outp.append(packetId());
 			p->identity().serialize(outp,false);
 			outp.encrypt(peer->cryptKey());
-			outp.hmacSet(peer->macKey());
+			outp.macSet(peer->macKey());
 			_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
 			TRACE("sent WHOIS response to %s for %s",source().toString().c_str(),Address(payload(),ZT_ADDRESS_LENGTH).toString().c_str());
 		} else {
@@ -363,7 +363,7 @@ bool PacketDecoder::_doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 			outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
 			outp.append(payload(),ZT_ADDRESS_LENGTH);
 			outp.encrypt(peer->cryptKey());
-			outp.hmacSet(peer->macKey());
+			outp.macSet(peer->macKey());
 			_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
 			TRACE("sent WHOIS ERROR to %s for %s (not found)",source().toString().c_str(),Address(payload(),ZT_ADDRESS_LENGTH).toString().c_str());
 		}
@@ -467,7 +467,7 @@ bool PacketDecoder::_doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedP
 		outp.append(packetId());
 		outp.append((uint16_t)numAccepted);
 		outp.encrypt(peer->cryptKey());
-		outp.hmacSet(peer->macKey());
+		outp.macSet(peer->macKey());
 		_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
 	} catch (std::exception &ex) {
 		TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
@@ -654,7 +654,7 @@ bool PacketDecoder::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *_r,const
 			outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
 			outp.append(nwid);
 			outp.encrypt(peer->cryptKey());
-			outp.hmacSet(peer->macKey());
+			outp.macSet(peer->macKey());
 			_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
 #ifndef __WINDOWS__
 		}

+ 5 - 5
node/Switch.cpp

@@ -218,7 +218,7 @@ bool Switch::sendHELLO(const SharedPtr<Peer> &dest,Demarc::Port localPort,const
 	outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
 	outp.append(now);
 	_r->identity.serialize(outp,false);
-	outp.hmacSet(dest->macKey());
+	outp.macSet(dest->macKey());
 
 	if (_r->demarc->send(localPort,remoteAddr,outp.data(),outp.size(),-1)) {
 		dest->onSent(_r,false,Packet::VERB_HELLO,now);
@@ -277,7 +277,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 			outp.append(cg.first.rawIpData(),4);
 		}
 		outp.encrypt(p1p->cryptKey());
-		outp.hmacSet(p1p->macKey());
+		outp.macSet(p1p->macKey());
 		if (p1p->send(_r,outp.data(),outp.size(),now))
 			p1p->onSent(_r,false,Packet::VERB_RENDEZVOUS,now);
 	}
@@ -293,7 +293,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 			outp.append(cg.second.rawIpData(),4);
 		}
 		outp.encrypt(p2p->cryptKey());
-		outp.hmacSet(p2p->macKey());
+		outp.macSet(p2p->macKey());
 		if (p2p->send(_r,outp.data(),outp.size(),now))
 			p2p->onSent(_r,false,Packet::VERB_RENDEZVOUS,now);
 	}
@@ -617,7 +617,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread
 		Packet outp(supernode->address(),_r->identity.address(),Packet::VERB_WHOIS);
 		addr.appendTo(outp);
 		outp.encrypt(supernode->cryptKey());
-		outp.hmacSet(supernode->macKey());
+		outp.macSet(supernode->macKey());
 
 		uint64_t now = Utils::now();
 		if (supernode->send(_r,outp.data(),outp.size(),now)) {
@@ -654,7 +654,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
 
 		if (encrypt)
 			tmp.encrypt(peer->cryptKey());
-		tmp.hmacSet(peer->macKey());
+		tmp.macSet(peer->macKey());
 
 		if (via->send(_r,tmp.data(),chunkSize,now)) {
 			if (chunkSize < tmp.size()) {

+ 0 - 100
node/Utils.cpp

@@ -181,36 +181,6 @@ const uint64_t Utils::crc64Table[256] = {
 	0x536fa08fdfd90e51ULL,0x29b7d047efec8728ULL
 };
 
-const char Utils::base64EncMap[64] = {
-	0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,
-	0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,
-	0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,
-	0x59,0x5A,0x61,0x62,0x63,0x64,0x65,0x66,
-	0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,
-	0x6F,0x70,0x71,0x72,0x73,0x74,0x75,0x76,
-	0x77,0x78,0x79,0x7A,0x30,0x31,0x32,0x33,
-	0x34,0x35,0x36,0x37,0x38,0x39,0x2B,0x2F
-};
-
-const char Utils::base64DecMap[128] = {
-	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x00,0x00,0x00,0x3E,0x00,0x00,0x00,0x3F,
-	0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,
-	0x3C,0x3D,0x00,0x00,0x00,0x00,0x00,0x00,
-	0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,
-	0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
-	0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,
-	0x17,0x18,0x19,0x00,0x00,0x00,0x00,0x00,
-	0x00,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,
-	0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
-	0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,
-	0x31,0x32,0x33,0x00,0x00,0x00,0x00,0x00
-};
-
 static const char *DAY_NAMES[7] = { "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
 static const char *MONTH_NAMES[12] = { "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" };
 
@@ -249,76 +219,6 @@ std::map<std::string,bool> Utils::listDirectory(const char *path)
 	return r;
 }
 
-std::string Utils::base64Encode(const void *data,unsigned int len)
-{
-	if (!len)
-		return std::string();
-
-	std::string out;
-	unsigned int sidx = 0;
-
-	if (len > 1) {
-		while (sidx < (len - 2)) {
-			out.push_back(base64EncMap[(((const unsigned char *)data)[sidx] >> 2) & 077]);
-			out.push_back(base64EncMap[((((const unsigned char *)data)[sidx + 1] >> 4) & 017) | ((((const unsigned char *)data)[sidx] << 4) & 077)]);
-			out.push_back(base64EncMap[((((const unsigned char *)data)[sidx + 2] >> 6) & 003) | ((((const unsigned char *)data)[sidx + 1] << 2) & 077)]);
-			out.push_back(base64EncMap[((const unsigned char *)data)[sidx + 2] & 077]);
-			sidx += 3;
-		}
-	}
-	if (sidx < len) {
-		out.push_back(base64EncMap[(((const unsigned char *)data)[sidx] >> 2) & 077]);
-		if (sidx < len - 1) {
-			out.push_back(base64EncMap[((((const unsigned char *)data)[sidx + 1] >> 4) & 017) | ((((const unsigned char *)data)[sidx] << 4) & 077)]);
-			out.push_back(base64EncMap[(((const unsigned char *)data)[sidx + 1] << 2) & 077]);
-		} else out.push_back(base64EncMap[(((const unsigned char *)data)[sidx] << 4) & 077]);
-	}
-	while (out.length() < (((len + 2) / 3) * 4))
-		out.push_back('=');
-
-	return out;
-}
-
-std::string Utils::base64Decode(const char *data,unsigned int len)
-{
-	if (!len)
-		return std::string();
-	std::string out;
-
-	while ((len)&&(((const unsigned char *)data)[len-1] == '='))
-		--len;
-
-	for (unsigned idx=0;idx<len;idx++) {
-		unsigned char ch = ((const unsigned char *)data)[idx];
-		if ((ch > 47 && ch < 58) || (ch > 64 && ch < 91) || (ch > 96 && ch < 123) || ch == '+' || ch == '/' || ch == '=')
-			out.push_back(base64DecMap[ch]);
-		else return std::string();
-	}
-
-	unsigned outLen = len - ((len + 3) / 4);
-	if ((!outLen)||((((outLen + 2) / 3) * 4) < len))
-		return std::string();
-
-	unsigned sidx = 0;
-	unsigned didx = 0;
-	if (outLen > 1) {
-		while (didx < outLen - 2) {
-			out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx + 1] >> 4) & 003));
-			out[didx + 1] = (((out[sidx + 1] << 4) & 255) | ((out[sidx + 2] >> 2) & 017));
-			out[didx + 2] = (((out[sidx + 2] << 6) & 255) | (out[sidx + 3] & 077));
-			sidx += 4;
-			didx += 3;
-		}
-	}
-
-	if (didx < outLen)
-		out[didx] = (((out[sidx] << 2) & 255) | ((out[sidx + 1] >> 4) & 003));
-	if (++didx < outLen)
-		out[didx] = (((out[sidx + 1] << 4) & 255) | ((out[sidx + 2] >> 2) & 017));
-
-	return out.substr(0,outLen);
-}
-
 std::string Utils::hex(const void *data,unsigned int len)
 {
 	std::string r;

+ 3 - 26
node/Utils.hpp

@@ -87,13 +87,8 @@ public:
 			p2 += 8;
 			len -= 8;
 		}
-
-		while (len) {
-			diff |= (uint64_t)(*p1 ^ *p2);
-			++p1;
-			++p2;
-			--len;
-		}
+		while (len--)
+			diff |= (uint64_t)(*p1++ ^ *p2++);
 
 		return (diff == 0ULL);
 	}
@@ -449,22 +444,6 @@ public:
 		return writeFile(path,s.data(),(unsigned int)s.length());
 	}
 
-	/**
-	 * @param data Binary data to encode
-	 * @param len Length of data
-	 * @return Base64-encoded string
-	 */
-	static std::string base64Encode(const void *data,unsigned int len);
-	inline static std::string base64Encode(const std::string &data) { return base64Encode(data.data(),(unsigned int)data.length()); }
-
-	/**
-	 * @param data Base64-encoded string
-	 * @param len Length of encoded string
-	 * @return Decoded binary date
-	 */
-	static std::string base64Decode(const char *data,unsigned int len);
-	inline static std::string base64Decode(const std::string &data) { return base64Decode(data.data(),(unsigned int)data.length()); }
-
 	/**
 	 * Split a string by delimiter, with optional escape and quote characters
 	 *
@@ -477,7 +456,7 @@ public:
 	static std::vector<std::string> split(const char *s,const char *const sep,const char *esc,const char *quot);
 
 	/**
-	 * Tokenize a string
+	 * Tokenize a string (alias for strtok_r or strtok_s depending on platform)
 	 *
 	 * @param str String to split
 	 * @param delim Delimiters
@@ -772,8 +751,6 @@ public:
 
 private:
 	static const uint64_t crc64Table[256];
-	static const char base64EncMap[64];
-	static const char base64DecMap[128];
 };
 
 } // namespace ZeroTier