1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
/* SPDX-License-Identifier: GPL-2.0
*
* Copyright (C) 2015-2021 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.
*/
#pragma once
#include "arithmetic.h"
#include "crypto.h"
enum NOISE_LENGTHS
{
NOISE_PUBLIC_KEY_LEN = CURVE25519_KEY_SIZE,
NOISE_SYMMETRIC_KEY_LEN = CHACHA20POLY1305_KEY_SIZE,
NOISE_TIMESTAMP_LEN = sizeof(UINT64) + sizeof(UINT32),
NOISE_AUTHTAG_LEN = CHACHA20POLY1305_AUTHTAG_SIZE,
NOISE_HASH_LEN = BLAKE2S_HASH_SIZE
};
#define NoiseEncryptedLen(PlainLen) ((PlainLen) + NOISE_AUTHTAG_LEN)
enum COOKIE_VALUES
{
COOKIE_SECRET_MAX_AGE = 2 * 60,
COOKIE_SECRET_LATENCY = 5,
COOKIE_NONCE_LEN = XCHACHA20POLY1305_NONCE_SIZE,
COOKIE_LEN = 16
};
enum COUNTER_VALUES
{
COUNTER_BITS_TOTAL = 8192,
COUNTER_REDUNDANT_BITS = BITS_PER_POINTER,
COUNTER_WINDOW_SIZE = COUNTER_BITS_TOTAL - COUNTER_REDUNDANT_BITS
};
#define REKEY_AFTER_MESSAGES (1ULL << 60)
#define REJECT_AFTER_MESSAGES (~0ULL - COUNTER_WINDOW_SIZE - 1)
#define REKEY_TIMEOUT 5
#define REKEY_TIMEOUT_JITTER_MAX_SYS_TIME_UNITS (SYS_TIME_UNITS_PER_SEC / 3)
#define REKEY_AFTER_TIME 120
#define REJECT_AFTER_TIME 180
#define INITIATIONS_PER_SECOND 50
#define MAX_PEERS_PER_DEVICE (1U << 20)
#define KEEPALIVE_TIMEOUT 10
#define MAX_TIMER_HANDSHAKES (90 / REKEY_TIMEOUT)
enum L4_LENGTHS
{
UDP_HEADER_LEN = 8,
};
enum MESSAGE_TYPE
{
MESSAGE_TYPE_INVALID = 0,
MESSAGE_TYPE_HANDSHAKE_INITIATION = 1,
MESSAGE_TYPE_HANDSHAKE_RESPONSE = 2,
MESSAGE_TYPE_HANDSHAKE_COOKIE = 3,
MESSAGE_TYPE_DATA = 4
};
typedef struct _IPV4HDR
{
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
UINT8 Ihl : 4, Version : 4;
#elif REG_DWORD == REG_DWORD_BIG_ENDIAN
UINT8 Version : 4, Ihl : 4;
#endif
UINT8 Tos;
UINT16_BE TotLen;
UINT16_BE Id;
UINT16_BE FragOff;
UINT8 Ttl;
UINT8 Protocol;
UINT16_BE Check;
UINT32_BE Saddr;
UINT32_BE Daddr;
} IPV4HDR;
typedef struct _IPV6HDR
{
#if REG_DWORD == REG_DWORD_LITTLE_ENDIAN
UINT8 Priority : 4, Version : 4;
#elif REG_DWORD == REG_DWORD_BIG_ENDIAN
UINT8 Version : 4, Priority : 4;
#endif
UINT8 FlowLbl[3];
UINT16_BE PayloadLen;
UINT8 Nexthdr;
UINT8 HopLimit;
IN6_ADDR Saddr;
IN6_ADDR Daddr;
} IPV6HDR;
typedef struct _MESSAGE_HEADER
{
/* The actual layout of this that we want is:
* u8 type
* u8 reserved_zero[3]
*
* But it turns out that by encoding this as little endian,
* we achieve the same thing, and it makes checking faster.
*/
UINT32_LE Type;
} MESSAGE_HEADER;
typedef struct _MESSAGE_MACS
{
UINT8 Mac1[COOKIE_LEN];
UINT8 Mac2[COOKIE_LEN];
} MESSAGE_MACS;
typedef struct _MESSAGE_HANDSHAKE_INITIATION
{
MESSAGE_HEADER Header;
UINT32_LE SenderIndex;
UINT8 UnencryptedEphemeral[NOISE_PUBLIC_KEY_LEN];
UINT8 EncryptedStatic[NoiseEncryptedLen(NOISE_PUBLIC_KEY_LEN)];
UINT8 EncryptedTimestamp[NoiseEncryptedLen(NOISE_TIMESTAMP_LEN)];
MESSAGE_MACS Macs;
} MESSAGE_HANDSHAKE_INITIATION;
typedef struct _MESSAGE_HANDSHAKE_RESPONSE
{
MESSAGE_HEADER Header;
UINT32_LE SenderIndex;
UINT32_LE ReceiverIndex;
UINT8 UnencryptedEphemeral[NOISE_PUBLIC_KEY_LEN];
UINT8 EncryptedNothing[NoiseEncryptedLen(0)];
MESSAGE_MACS Macs;
} MESSAGE_HANDSHAKE_RESPONSE;
typedef struct _MESSAGE_HANDSHAKE_COOKIE
{
MESSAGE_HEADER Header;
UINT32_LE ReceiverIndex;
UINT8 Nonce[COOKIE_NONCE_LEN];
UINT8 EncryptedCookie[NoiseEncryptedLen(COOKIE_LEN)];
} MESSAGE_HANDSHAKE_COOKIE;
typedef struct _MESSAGE_DATA
{
MESSAGE_HEADER Header;
UINT32_LE KeyIdx;
UINT64_LE Counter;
UINT8 EncryptedData[];
} MESSAGE_DATA;
#define MessageDataLen(PlainLen) (NoiseEncryptedLen(PlainLen) + sizeof(MESSAGE_DATA))
enum MESSAGE_ALIGNMENTS
{
MESSAGE_PADDING_MULTIPLE = 16,
MESSAGE_MINIMUM_LENGTH = MessageDataLen(0)
};
#define DATA_PACKET_MINIMUM_LENGTH (max(sizeof(IPV4HDR), sizeof(IPV6HDR)) + UDP_HEADER_LEN + MESSAGE_MINIMUM_LENGTH)
#define MTU_MAX (ALIGN_DOWN_BY_T(SIZE_T, MAXLONG, MESSAGE_PADDING_MULTIPLE) - DATA_PACKET_MINIMUM_LENGTH)
|