syncookies: use SipHash in place of SHA1
authorJason A. Donenfeld <Jason@zx2c4.com>
Sun, 8 Jan 2017 12:54:03 +0000 (13:54 +0100)
committerDavid S. Miller <davem@davemloft.net>
Mon, 9 Jan 2017 18:58:57 +0000 (13:58 -0500)
SHA1 is slower and less secure than SipHash, and so replacing syncookie
generation with SipHash makes natural sense. Some BSDs have been doing
this for several years in fact.

The speedup should be similar -- and even more impressive -- to the
speedup from the sequence number fix in this series.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: David Miller <davem@davemloft.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/syncookies.c
net/ipv6/syncookies.c

index 3e88467d70eec498e0a167474084c98c89069574..496b97e17aaf7ed2cf41cef303cb0696927f66ac 100644 (file)
 #include <linux/tcp.h>
 #include <linux/slab.h>
 #include <linux/random.h>
-#include <linux/cryptohash.h>
+#include <linux/siphash.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <net/tcp.h>
 #include <net/route.h>
 
-static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
+static siphash_key_t syncookie_secret[2] __read_mostly;
 
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
@@ -48,24 +48,13 @@ static u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
 #define TSBITS 6
 #define TSMASK (((__u32)1 << TSBITS) - 1)
 
-static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], ipv4_cookie_scratch);
-
 static u32 cookie_hash(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport,
                       u32 count, int c)
 {
-       __u32 *tmp;
-
        net_get_random_once(syncookie_secret, sizeof(syncookie_secret));
-
-       tmp  = this_cpu_ptr(ipv4_cookie_scratch);
-       memcpy(tmp + 4, syncookie_secret[c], sizeof(syncookie_secret[c]));
-       tmp[0] = (__force u32)saddr;
-       tmp[1] = (__force u32)daddr;
-       tmp[2] = ((__force u32)sport << 16) + (__force u32)dport;
-       tmp[3] = count;
-       sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
-
-       return tmp[17];
+       return siphash_4u32((__force u32)saddr, (__force u32)daddr,
+                           (__force u32)sport << 16 | (__force u32)dport,
+                           count, &syncookie_secret[c]);
 }
 
 
index a4d49760bf434e0800fb92cf10cdd6e6ce22f5e5..895ff650db43017ef39344679771d94ad6eaaf00 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <linux/tcp.h>
 #include <linux/random.h>
-#include <linux/cryptohash.h>
+#include <linux/siphash.h>
 #include <linux/kernel.h>
 #include <net/ipv6.h>
 #include <net/tcp.h>
@@ -24,7 +24,7 @@
 #define COOKIEBITS 24  /* Upper bits store count */
 #define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)
 
-static u32 syncookie6_secret[2][16-4+SHA_DIGEST_WORDS] __read_mostly;
+static siphash_key_t syncookie6_secret[2] __read_mostly;
 
 /* RFC 2460, Section 8.3:
  * [ipv6 tcp] MSS must be computed as the maximum packet size minus 60 [..]
@@ -41,30 +41,27 @@ static __u16 const msstab[] = {
        9000 - 60,
 };
 
-static DEFINE_PER_CPU(__u32 [16 + 5 + SHA_WORKSPACE_WORDS], ipv6_cookie_scratch);
-
-static u32 cookie_hash(const struct in6_addr *saddr, const struct in6_addr *daddr,
+static u32 cookie_hash(const struct in6_addr *saddr,
+                      const struct in6_addr *daddr,
                       __be16 sport, __be16 dport, u32 count, int c)
 {
-       __u32 *tmp;
+       const struct {
+               struct in6_addr saddr;
+               struct in6_addr daddr;
+               u32 count;
+               __be16 sport;
+               __be16 dport;
+       } __aligned(SIPHASH_ALIGNMENT) combined = {
+               .saddr = *saddr,
+               .daddr = *daddr,
+               .count = count,
+               .sport = sport,
+               .dport = dport
+       };
 
        net_get_random_once(syncookie6_secret, sizeof(syncookie6_secret));
-
-       tmp  = this_cpu_ptr(ipv6_cookie_scratch);
-
-       /*
-        * we have 320 bits of information to hash, copy in the remaining
-        * 192 bits required for sha_transform, from the syncookie6_secret
-        * and overwrite the digest with the secret
-        */
-       memcpy(tmp + 10, syncookie6_secret[c], 44);
-       memcpy(tmp, saddr, 16);
-       memcpy(tmp + 4, daddr, 16);
-       tmp[8] = ((__force u32)sport << 16) + (__force u32)dport;
-       tmp[9] = count;
-       sha_transform(tmp + 16, (__u8 *)tmp, tmp + 16 + 5);
-
-       return tmp[17];
+       return siphash(&combined, offsetofend(typeof(combined), dport),
+                      &syncookie6_secret[c]);
 }
 
 static __u32 secure_tcp_syn_cookie(const struct in6_addr *saddr,