Kaynağa Gözat

Roots now understand encrypted HELLO.

Adam Ierymenko 11 ay önce
ebeveyn
işleme
0ab4e2f750
4 değiştirilmiş dosya ile 57 ekleme ve 11 silme
  1. 0 9
      node/AES.hpp
  2. 3 1
      node/Identity.hpp
  3. 34 0
      node/Packet.hpp
  4. 20 1
      root/root.cpp

+ 0 - 9
node/AES.hpp

@@ -135,17 +135,8 @@ public:
 		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;
 		}
 

+ 3 - 1
node/Identity.hpp

@@ -447,7 +447,9 @@ public:
 
 	ZT_ALWAYS_INLINE unsigned long hashCode() const { return ((unsigned long)_address.toInt() + (unsigned long)_pub.c25519[0] + (unsigned long)_pub.c25519[1] + (unsigned long)_pub.c25519[2]); }
 
-private:
+	ZT_ALWAYS_INLINE const uint8_t *c25519SecretKey() const { return this->_priv.c25519; }
+
+	private:
 	Address _address;
 	Type _type;
 	bool _hasPrivate;

+ 34 - 0
node/Packet.hpp

@@ -111,6 +111,17 @@
  */
 #define ZT_PROTO_FLAG_FRAGMENTED 0x40
 
+/**
+ * Header flag indicating ephemeral keying and second encryption pass.
+ *
+ * If this is set, the packet will have an ephemeral key appended to it its payload
+ * will be encrypted with AES-CTR using this ephemeral key and the packet's header
+ * as an IV.
+ *
+ * Note that this is a reuse of a flag that has long been deprecated and ignored.
+ */
+#define ZT_PROTO_FLAG_EXTENDED_ARMOR 0x80
+
 /**
  * Verb flag indicating payload is compressed with LZ4
  */
@@ -1153,6 +1164,29 @@ public:
 		b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
 	}
 
+	/**
+     * @return True if packet is encrypted with an extra ephemeral key
+     */
+    inline bool extendedArmor() const
+    {
+        return (((unsigned char)(*this)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_EXTENDED_ARMOR) != 0);
+    }
+
+    /**
+     * Set this packet's extended armor flag
+     *
+     * @param f Extended armor flag value
+     */
+    inline void setExtendedArmor(bool f)
+    {
+        if (f) {
+            (*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_EXTENDED_ARMOR;
+        }
+        else {
+            (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_EXTENDED_ARMOR);
+        }
+    }
+
 	/**
 	 * Get the trusted path ID for this packet (only meaningful if cipher is trusted path)
 	 *

+ 20 - 1
root/root.cpp

@@ -61,6 +61,7 @@
 #include "../node/Packet.hpp"
 #include "../node/SharedPtr.hpp"
 #include "../node/Utils.hpp"
+#include "../node/AES.hpp"
 #include "../osdep/BlockingQueue.hpp"
 #include "../osdep/OSUtils.hpp"
 #include "geoip-html.h"
@@ -265,6 +266,8 @@ static ZT_ALWAYS_INLINE std::array<uint64_t, 2> ip6ToH128(const InetAddress& ip)
     return i128;
 }
 
+#define ZT_PACKET_IDX_EXTENDED_ARMOR_START 19
+
 static void handlePacket(const int sock, const InetAddress* const ip, Packet& pkt)
 {
     char ipstr[128], ipstr2[128], astr[32], astr2[32], tmpstr[256];
@@ -281,6 +284,23 @@ static void handlePacket(const int sock, const InetAddress* const ip, Packet& pk
     if ((! fragment) && (! pkt.fragmented()) && (dest == s_self.address())) {
         SharedPtr<RootPeer> peer;
 
+        if ((pkt.cipher() == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE) && pkt.extendedArmor()) {
+            if (pkt.size() < (ZT_PROTO_MIN_PACKET_LENGTH + 32)) {
+                return;
+            }
+            uint8_t ephemeralSymmetric[64];
+            C25519::agree(s_self.c25519SecretKey(), (const uint8_t *)pkt.data() + (pkt.size() - 32), ephemeralSymmetric);
+            SHA512(ephemeralSymmetric, ephemeralSymmetric, 32);
+
+            AES cipher(ephemeralSymmetric);
+            uint32_t ctrIv[4];
+            memcpy(ctrIv, pkt.data(), 12);
+            ctrIv[3] = 0;
+            cipher.ctr((const uint8_t *)ctrIv, (const uint8_t *)pkt.data() + ZT_PACKET_IDX_EXTENDED_ARMOR_START, (pkt.size() - ZT_PACKET_IDX_EXTENDED_ARMOR_START) - 32, (uint8_t *)pkt.data() + ZT_PACKET_IDX_EXTENDED_ARMOR_START);
+
+            pkt.setSize(pkt.size() - 32);
+        }
+
         // If this is an un-encrypted HELLO, either learn a new peer or verify
         // that this is a peer we already know.
         if ((pkt.cipher() == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE) && (pkt.verb() == Packet::VERB_HELLO)) {
@@ -304,7 +324,6 @@ static void handlePacket(const int sock, const InetAddress* const ip, Packet& pk
                             pkt.reset(source, s_self.address(), Packet::VERB_ERROR);
                             pkt.append((uint8_t)Packet::VERB_HELLO);
                             pkt.append(origId);
-                            ;
                             pkt.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION);
                             pkt.armor(key, true);
                             sendto(sock, pkt.data(), pkt.size(), SENDTO_FLAGS, (const struct sockaddr*)ip, (socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));