wireguard: add dos mitigation support
[vpp.git] / src / plugins / wireguard / wireguard_chachapoly.c
1 /*
2  * Copyright (c) 2022 Rubicon Communications, LLC.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <wireguard/wireguard.h>
17 #include <wireguard/wireguard_chachapoly.h>
18 #include <wireguard/wireguard_hchacha20.h>
19
20 bool
21 wg_chacha20poly1305_calc (vlib_main_t *vm, u8 *src, u32 src_len, u8 *dst,
22                           u8 *aad, u32 aad_len, u64 nonce,
23                           vnet_crypto_op_id_t op_id,
24                           vnet_crypto_key_index_t key_index)
25 {
26   vnet_crypto_op_t _op, *op = &_op;
27   u8 iv[12];
28   u8 tag_[NOISE_AUTHTAG_LEN] = {};
29   u8 src_[] = {};
30
31   clib_memset (iv, 0, 12);
32   clib_memcpy (iv + 4, &nonce, sizeof (nonce));
33
34   vnet_crypto_op_init (op, op_id);
35
36   op->tag_len = NOISE_AUTHTAG_LEN;
37   if (op_id == VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC)
38     {
39       op->tag = src + src_len - NOISE_AUTHTAG_LEN;
40       src_len -= NOISE_AUTHTAG_LEN;
41       op->flags |= VNET_CRYPTO_OP_FLAG_HMAC_CHECK;
42     }
43   else
44     op->tag = tag_;
45
46   op->src = !src ? src_ : src;
47   op->len = src_len;
48
49   op->dst = dst;
50   op->key_index = key_index;
51   op->aad = aad;
52   op->aad_len = aad_len;
53   op->iv = iv;
54
55   vnet_crypto_process_ops (vm, op, 1);
56   if (op_id == VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC)
57     {
58       clib_memcpy (dst + src_len, op->tag, NOISE_AUTHTAG_LEN);
59     }
60
61   return (op->status == VNET_CRYPTO_OP_STATUS_COMPLETED);
62 }
63
64 void
65 wg_xchacha20poly1305_encrypt (vlib_main_t *vm, u8 *src, u32 src_len, u8 *dst,
66                               u8 *aad, u32 aad_len,
67                               u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
68                               u8 key[CHACHA20POLY1305_KEY_SIZE])
69 {
70   int i;
71   u32 derived_key[CHACHA20POLY1305_KEY_SIZE / sizeof (u32)];
72   u64 h_nonce;
73
74   clib_memcpy (&h_nonce, nonce + 16, sizeof (h_nonce));
75   h_nonce = le64toh (h_nonce);
76   hchacha20 (derived_key, nonce, key);
77
78   for (i = 0; i < (sizeof (derived_key) / sizeof (derived_key[0])); i++)
79     (derived_key[i]) = htole32 ((derived_key[i]));
80
81   uint32_t key_idx;
82
83   key_idx =
84     vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305,
85                          (uint8_t *) derived_key, CHACHA20POLY1305_KEY_SIZE);
86
87   wg_chacha20poly1305_calc (vm, src, src_len, dst, aad, aad_len, h_nonce,
88                             VNET_CRYPTO_OP_CHACHA20_POLY1305_ENC, key_idx);
89
90   vnet_crypto_key_del (vm, key_idx);
91   wg_secure_zero_memory (derived_key, CHACHA20POLY1305_KEY_SIZE);
92 }
93
94 bool
95 wg_xchacha20poly1305_decrypt (vlib_main_t *vm, u8 *src, u32 src_len, u8 *dst,
96                               u8 *aad, u32 aad_len,
97                               u8 nonce[XCHACHA20POLY1305_NONCE_SIZE],
98                               u8 key[CHACHA20POLY1305_KEY_SIZE])
99 {
100   int ret, i;
101   u32 derived_key[CHACHA20POLY1305_KEY_SIZE / sizeof (u32)];
102   u64 h_nonce;
103
104   clib_memcpy (&h_nonce, nonce + 16, sizeof (h_nonce));
105   h_nonce = le64toh (h_nonce);
106   hchacha20 (derived_key, nonce, key);
107
108   for (i = 0; i < (sizeof (derived_key) / sizeof (derived_key[0])); i++)
109     (derived_key[i]) = htole32 ((derived_key[i]));
110
111   uint32_t key_idx;
112
113   key_idx =
114     vnet_crypto_key_add (vm, VNET_CRYPTO_ALG_CHACHA20_POLY1305,
115                          (uint8_t *) derived_key, CHACHA20POLY1305_KEY_SIZE);
116
117   ret =
118     wg_chacha20poly1305_calc (vm, src, src_len, dst, aad, aad_len, h_nonce,
119                               VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC, key_idx);
120
121   vnet_crypto_key_del (vm, key_idx);
122   wg_secure_zero_memory (derived_key, CHACHA20POLY1305_KEY_SIZE);
123
124   return ret;
125 }
126
127 /*
128  * fd.io coding-style-patch-verification: ON
129  *
130  * Local Variables:
131  * eval: (c-set-style "gnu")
132  * End:
133  */