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}
  79#endif
  80
  81#ifdef CONFIG_INET
  82__u32 secure_ip_id(__be32 daddr)
  83{
  84        u32 hash[MD5_DIGEST_WORDS];
  85
  86        hash[0] = (__force __u32) daddr;
  87        hash[1] = net_secret[13];
  88        hash[2] = net_secret[14];
  89        hash[3] = net_secret[15];
  90
  91        md5_transform(hash, net_secret);
  92
  93        return hash[0];
  94}
  95
  96__u32 secure_ipv6_id(const __be32 daddr[4])
  97{
  98        __u32 hash[4];
  99
 100        memcpy(hash, daddr, 16);
 101        md5_transform(hash, net_secret);
 102
 103        return hash[0];
 104}
 105
 106__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr,
 107                                 __be16 sport, __be16 dport)
 108{
 109        u32 hash[MD5_DIGEST_WORDS];
 110
 111        hash[0] = (__force u32)saddr;
 112        hash[1] = (__force u32)daddr;
 113        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
 114        hash[3] = net_secret[15];
 115
 116        md5_transform(hash, net_secret);
 117
 118        return seq_scale(hash[0]);
 119}
 120
 121u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
 122{
 123        u32 hash[MD5_DIGEST_WORDS];
 124
 125        hash[0] = (__force u32)saddr;
 126        hash[1] = (__force u32)daddr;
 127        hash[2] = (__force u32)dport ^ net_secret[14];
 128        hash[3] = net_secret[15];
 129
 130        md5_transform(hash, net_secret);
 131
 132        return hash[0];
 133}
 134EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral);
 135#endif
 136
 137#if IS_ENABLED(CONFIG_IP_DCCP)
 138u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr,
 139                                __be16 sport, __be16 dport)
 140{
 141        u32 hash[MD5_DIGEST_WORDS];
 142        u64 seq;
 143
 144        hash[0] = (__force u32)saddr;
 145        hash[1] = (__force u32)daddr;
 146        hash[2] = ((__force u16)sport << 16) + (__force u16)dport;
 147        hash[3] = net_secret[15];
 148
 149        md5_transform(hash, net_secret);
 150
 151        seq = hash[0] | (((u64)hash[1]) << 32);
 152        seq += ktime_to_ns(ktime_get_real());
 153        seq &= (1ull << 48) - 1;
 154
 155        return seq;
 156}
 157EXPORT_SYMBOL(secure_dccp_sequence_number);
 158
 159#if IS_ENABLED(CONFIG_IPV6)
 160u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr,
 161                                  __be16 sport, __be16 dport)
 162{
 163        u32 secret[MD5_MESSAGE_BYTES / 4];
 164        u32 hash[MD5_DIGEST_WORDS];
 165        u64 seq;
 166        u32 i;
 167
 168        memcpy(hash, saddr, 16);
 169        for (i = 0; i < 4; i++)
 170                secret[i] = net_secret[i] + daddr[i];
 171        secret[4] = net_secret[4] +
 172                (((__force u16)sport << 16) + (__force u16)dport);
 173        for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++)
 174                secret[i] = net_secret[i];
 175
 176        md5_transform(hash, secret);
 177
 178        seq = hash[0] | (((u64)hash[1]) << 32);
 179        seq += ktime_to_ns(ktime_get_real());
 180        seq &= (1ull << 48) - 1;
 181
 182        return seq;
 183}
 184EXPORT_SYMBOL(secure_dccpv6_sequence_number);
 185#endif
 186#endif
 187
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.