linux/net/core/secure_seq.c
<<
>>
Prefs
   1#include <linux/kernel.h>
   2#include <linux/init.h>
   3#include <linux/cryptohash.h>
   4#include <linux/module.h>
   5#include <linux/cache.h>
   6#include <linux/random.h>
   7#include <linux/hrtimer.h>
   8#include <linux/ktime.h>
   9#include <linux/string.h>
  10
  11#include <net/secure_seq.h>
  12
  13static u32 net_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned;
  14
  15static int __init net_secret_init(void)
  16{
  17        get_random_bytes(net_secret, sizeof(net_secret));
  18        return 0;
  19}
  20late_initcall(net_secret_init);
  21
  22#ifdef CONFIG_INET
  23static u32 seq_scale(u32 seq)
  24{
  25        /*
  26         *      As close as possible to RFC 793, which
  27         *      suggests using a 250 kHz clock.
  28         *      Further reading shows this assumes 2 Mb/s networks.
  29         *      For 10 Mb/s Ethernet, a 1 MHz clock is appropriate.
  30         *      For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but
  31         *      we also need to limit the resolution so that the u32 seq
  32         *      overlaps less than one time per MSL (2 minutes).
  33         *      Choosing a clock of 64 ns period is OK. (period of 274 s)
  34         */
  35        return seq + (ktime_to_ns(ktime_get_real()) >> 6);
  36}
  37#endif
  38
  39#if IS_ENABLED(CONFIG_IPV6)
  40__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr,
  41                                   __be16 sport, __be16 dport)
  42{
  43        u32 secret[MD5_MESSAGE_BYTES / 4];
  44        u32 hash[MD5_DIGEST_WORDS];
  45        u32 i;
  46
  47        memcpy(hash, saddr, 16);
  48        for (i = 0; i < 4; i++)
  49                secret[i] = net_secret[i] + (__force u32)daddr[i];
  50        secret[4] = net_secret[4] +
  51                (((__force u16)sport << 16) + (__force u16)dport);
  52        for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
  53                secret[i] = net_secret[i];
  54
  55        md5_transform(hash, secret);
  56
  57        return seq_scale(hash[0]);
  58}
  59EXPORT_SYMBOL(secure_tcpv6_sequence_number);
  60
  61u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr,
  62                               __be16 dport)
  63{
  64        u32 secret[MD5_MESSAGE_BYTES / 4];
  65        u32 hash[MD5_DIGEST_WORDS];
  66        u32 i;
  67
  68        memcpy(hash, saddr, 16);
  69        for (i = 0; i < 4; i++)
  70                secret[i] = net_secret[i] + (__force u32) daddr[i];
  71        secret[4] = net_secret[4] + (__force u32)dport;
  72        for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
  73                secret[i] = net_secret[i];
  74
  75        md5_transform(hash, secret);
  76
  77        return hash[0];
  78}
  79EXPORT_SYMBOL(secure_ipv6_port_ephemeral);
  80#endif
  81
  82#ifdef CONFIG_INET
  83__u32 secure_ip_id(__be32 daddr)
  84{
  85        u32 hash[MD5_DIGEST_WORDS];
  86
  87        hash[0] = (__force __u32) daddr;
  88        hash[1] = net_secret[13];
  89        hash[2] = net_secret[14];
  90        hash[3] = net_secret[15];
  91
  92        md5_transform(hash, net_secret);
  93
  94        return hash[0];
  95}
  96
  97__u32 secure_ipv6_id(const __be32 daddr[4])
  98{
  99        __u32 hash[4];
 100
 101        memcpy(hash, daddr, 16);
 102        md5_transform(hash, net_secret);
 103
 104        return hash[0];
 105}
 106
 107__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
 108                                 __be16 sport, __be16 dport)
 109{
 110        u32 hash[MD5_DIGEST_WORDS];
 111
 112        hash[0] = (__force u32)saddr;
 113        hash[1] = (__force u32)daddr;
 114        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
 115        hash[3] = net_secret[15];
 116
 117        md5_transform(hash, net_secret);
 118
 119        return seq_scale(hash[0]);
 120}
 121
 122u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
 123{
 124        u32 hash[MD5_DIGEST_WORDS];
 125
 126        hash[0] = (__force u32)saddr;
 127        hash[1] = (__force u32)daddr;
 128        hash[2] = (__force u32)dport ^ net_secret[14];
 129        hash[3] = net_secret[15];
 130
 131        md5_transform(hash, net_secret);
 132
 133        return hash[0];
 134}
 135EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
 136#endif
 137
 138#if IS_ENABLED(CONFIG_IP_DCCP)
 139u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
 140                                __be16 sport, __be16 dport)
 141{
 142        u32 hash[MD5_DIGEST_WORDS];
 143        u64 seq;
 144
 145        hash[0] = (__force u32)saddr;
 146        hash[1] = (__force u32)daddr;
 147        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
 148        hash[3] = net_secret[15];
 149
 150        md5_transform(hash, net_secret);
 151
 152        seq = hash[0] | (((u64)hash[1]) << 32);
 153        seq += ktime_to_ns(ktime_get_real());
 154        seq &= (1ull << 48) - 1;
 155
 156        return seq;
 157}
 158EXPORT_SYMBOL(secure_dccp_sequence_number);
 159
 160#if IS_ENABLED(CONFIG_IPV6)
 161u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
 162                                  __be16 sport, __be16 dport)
 163{
 164        u32 secret[MD5_MESSAGE_BYTES / 4];
 165        u32 hash[MD5_DIGEST_WORDS];
 166        u64 seq;
 167        u32 i;
 168
 169        memcpy(hash, saddr, 16);
 170        for (i = 0; i < 4; i++)
 171                secret[i] = net_secret[i] + daddr[i];
 172        secret[4] = net_secret[4] +
 173                (((__force u16)sport << 16) + (__force u16)dport);
 174        for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
 175                secret[i] = net_secret[i];
 176
 177        md5_transform(hash, secret);
 178
 179        seq = hash[0] | (((u64)hash[1]) << 32);
 180        seq += ktime_to_ns(ktime_get_real());
 181        seq &= (1ull << 48) - 1;
 182
 183        return seq;
 184}
 185EXPORT_SYMBOL(secure_dccpv6_sequence_number);
 186#endif
 187#endif
 188
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.