by default fill the ping payload with a chacha stream instead of
authordlg <dlg@openbsd.org>
Sun, 19 Apr 2015 12:56:42 +0000 (12:56 +0000)
committerdlg <dlg@openbsd.org>
Sun, 19 Apr 2015 12:56:42 +0000 (12:56 +0000)
an unvarying payload.

each ping process generates a random key, and each packet then uses
the timestamps mac as the IV for the stream.

this allows us to have a different payload per packet that we can
recalculate and compare in the same was as the static payload was
checked before. by aggressively varying the payload we hope to
generate more opportunities for dodgy network equipment to show
errors.

note that we do siphash before chacha because we want to be strict
about the timestamp payload, but we want to be able to recognise
errors in the rest of the payload and where those errors were. doing
chacha before siphash would have us than fail the whole packet if
a checksum doesnt match.

discussed with jp aumasson
ok florian@

sbin/ping/ping.c

index 7485cfa..7ce9b4b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ping.c,v 1.119 2015/04/19 12:45:37 dlg Exp $  */
+/*     $OpenBSD: ping.c,v 1.120 2015/04/19 12:56:42 dlg Exp $  */
 /*     $NetBSD: ping.c,v 1.20 1995/08/11 22:37:58 cgd Exp $    */
 
 /*
 #include <string.h>
 #include <limits.h>
 #include <stdlib.h>
+
 #include <siphash.h>
+#define KEYSTREAM_ONLY
+#include <crypto/chacha_private.h>
 
 struct tv64 {
        u_int64_t       tv64_sec;
@@ -162,6 +165,7 @@ int bufspace = IP_MAXPACKET;
 
 struct tv64 tv64_offset;
 SIPHASH_KEY mac_key;
+chacha_ctx fill_stream;
 
 void fill(char *, char *);
 void catcher(int signo);
@@ -188,7 +192,7 @@ main(int argc, char *argv[])
        struct hostent *hp;
        struct sockaddr_in *to;
        struct in_addr saddr;
-       int ch, i, optval = 1, packlen, preload, maxsize, df = 0, tos = 0;
+       int ch, optval = 1, packlen, preload, maxsize, df = 0, tos = 0;
        u_char *datap, *packet, ttl = MAXTTL, loop = 1;
        char *target, hnamebuf[HOST_NAME_MAX+1];
        char rspace[3 + 4 * NROUTES + 1];       /* record route space */
@@ -385,9 +389,11 @@ main(int argc, char *argv[])
        packlen = datalen + MAXIPLEN + MAXICMPLEN;
        if (!(packet = malloc((size_t)packlen)))
                err(1, "malloc");
-       if (!(options & F_PINGFILLED))
-               for (i = sizeof(struct payload); i < datalen; ++i)
-                       *datap++ = i;
+       if (!(options & F_PINGFILLED) && datalen > sizeof(struct payload)) {
+               u_int8_t key[32];
+               arc4random_buf(key, sizeof(key));
+               chacha_keysetup(&fill_stream, key, sizeof(key) * 8, 0);
+       }
 
        ident = getpid() & 0xFFFF;
 
@@ -647,6 +653,14 @@ pinger(void)
                SipHash24_Final(&payload.mac, &ctx);
 
                memcpy(&outpack[8], &payload, sizeof(payload));
+
+               if (!(options & F_PINGFILLED) && datalen > sizeof(payload)) {
+                       u_int8_t *dp = &outpack[8 + sizeof(payload)];
+
+                       chacha_ivsetup(&fill_stream, payload.mac);
+                       chacha_encrypt_bytes(&fill_stream, dp, dp,
+                           datalen - sizeof(payload));
+               }
        }
 
        cc = datalen + 8;                       /* skips ICMP portion */
@@ -700,6 +714,7 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from)
        char *pkttime;
        quad_t triptime = 0;
        int hlen, hlen2, dupflag;
+       struct payload payload;
 
        if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
                err(1, "clock_gettime(CLOCK_MONOTONIC)");
@@ -723,7 +738,6 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from)
                ++nreceived;
                if (cc >= 8 + sizeof(struct payload)) {
                        SIPHASH_CTX ctx;
-                       struct payload payload;
                        struct tv64 *tv64 = &payload.tv64;
                        u_int8_t mac[SIPHASH_DIGEST_LENGTH];
 
@@ -790,6 +804,11 @@ pr_pack(char *buf, int cc, struct sockaddr_in *from)
                                (void)printf(" (TRUNC!)");
                        cp = (u_char *)&icp->icmp_data[sizeof(struct payload)];
                        dp = &outpack[8 + sizeof(struct payload)];
+                       if (!(options & F_PINGFILLED)) {
+                               chacha_ivsetup(&fill_stream, payload.mac);
+                               chacha_encrypt_bytes(&fill_stream, dp, dp,
+                                   datalen - sizeof(payload));
+                       }
                        for (i = 8 + sizeof(struct payload);
                            i < cc && i < datalen;
                            ++i, ++cp, ++dp) {