Line | Count | Source (jump to first uncovered line) |
1 | | /* siv-gcm.c |
2 | | |
3 | | AES-GCM-SIV, RFC8452 |
4 | | |
5 | | Copyright (C) 2022 Red Hat, Inc. |
6 | | |
7 | | This file is part of GNU Nettle. |
8 | | |
9 | | GNU Nettle is free software: you can redistribute it and/or |
10 | | modify it under the terms of either: |
11 | | |
12 | | * the GNU Lesser General Public License as published by the Free |
13 | | Software Foundation; either version 3 of the License, or (at your |
14 | | option) any later version. |
15 | | |
16 | | or |
17 | | |
18 | | * the GNU General Public License as published by the Free |
19 | | Software Foundation; either version 2 of the License, or (at your |
20 | | option) any later version. |
21 | | |
22 | | or both in parallel, as here. |
23 | | |
24 | | GNU Nettle is distributed in the hope that it will be useful, |
25 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
26 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
27 | | General Public License for more details. |
28 | | |
29 | | You should have received copies of the GNU General Public License and |
30 | | the GNU Lesser General Public License along with this program. If |
31 | | not, see http://www.gnu.org/licenses/. |
32 | | */ |
33 | | |
34 | | #if HAVE_CONFIG_H |
35 | | # include "config.h" |
36 | | #endif |
37 | | |
38 | | #include "siv-gcm.h" |
39 | | #include "ghash-internal.h" |
40 | | #include "block-internal.h" |
41 | | #include "nettle-internal.h" |
42 | | #include "macros.h" |
43 | | #include "memops.h" |
44 | | #include "ctr-internal.h" |
45 | | #include <string.h> |
46 | | |
47 | 0 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) |
48 | | |
49 | | static void |
50 | | siv_gcm_derive_keys (const void *ctx, |
51 | | nettle_cipher_func *f, |
52 | | size_t key_size, |
53 | | size_t nlength, const uint8_t *nonce, |
54 | | union nettle_block16 *auth_key, |
55 | | uint8_t *encryption_key) |
56 | 0 | { |
57 | 0 | union nettle_block16 block; |
58 | 0 | union nettle_block16 out; |
59 | 0 | size_t i; |
60 | |
|
61 | 0 | block16_zero (&block); |
62 | 0 | memcpy (block.b + 4, nonce, MIN(nlength, SIV_GCM_NONCE_SIZE)); |
63 | |
|
64 | 0 | f (ctx, SIV_GCM_BLOCK_SIZE, out.b, block.b); |
65 | 0 | auth_key->u64[0] = out.u64[0]; |
66 | |
|
67 | 0 | block.b[0] = 1; |
68 | 0 | f (ctx, SIV_GCM_BLOCK_SIZE, out.b, block.b); |
69 | 0 | auth_key->u64[1] = out.u64[0]; |
70 | |
|
71 | 0 | assert (key_size % 8 == 0 && key_size / 8 + 2 <= UINT8_MAX); |
72 | | |
73 | 0 | for (i = 0; i < key_size; i += 8) |
74 | 0 | { |
75 | 0 | block.b[0]++; |
76 | 0 | f (ctx, SIV_GCM_BLOCK_SIZE, out.b, block.b); |
77 | 0 | memcpy (encryption_key + i, out.b, 8); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | static nettle_fill16_func siv_gcm_fill; |
82 | | |
83 | | static void |
84 | | siv_gcm_fill(uint8_t *ctr, size_t blocks, union nettle_block16 *buffer) |
85 | 0 | { |
86 | 0 | uint32_t c; |
87 | |
|
88 | 0 | c = LE_READ_UINT32(ctr); |
89 | |
|
90 | 0 | for (; blocks-- > 0; buffer++, c++) |
91 | 0 | { |
92 | 0 | memcpy(buffer->b + 4, ctr + 4, SIV_GCM_BLOCK_SIZE - 4); |
93 | 0 | LE_WRITE_UINT32(buffer->b, c); |
94 | 0 | } |
95 | |
|
96 | 0 | LE_WRITE_UINT32(ctr, c); |
97 | 0 | } |
98 | | |
99 | | static void |
100 | | siv_ghash_pad_update (struct gcm_key *ctx, |
101 | | union nettle_block16 *state, |
102 | | size_t length, const uint8_t *data) |
103 | 0 | { |
104 | 0 | size_t blocks; |
105 | |
|
106 | 0 | blocks = length / SIV_GCM_BLOCK_SIZE; |
107 | 0 | if (blocks > 0) |
108 | 0 | { |
109 | 0 | data = _siv_ghash_update (ctx, state, blocks, data); |
110 | 0 | length &= 0xf; |
111 | 0 | } |
112 | 0 | if (length > 0) |
113 | 0 | { |
114 | 0 | uint8_t block[SIV_GCM_BLOCK_SIZE]; |
115 | |
|
116 | 0 | memset (block + length, 0, SIV_GCM_BLOCK_SIZE - length); |
117 | 0 | memcpy (block, data, length); |
118 | 0 | _siv_ghash_update (ctx, state, 1, block); |
119 | 0 | } |
120 | 0 | } |
121 | | |
122 | | static void |
123 | | siv_gcm_authenticate (const void *ctx, |
124 | | const struct nettle_cipher *nc, |
125 | | const union nettle_block16 *authentication_key, |
126 | | const uint8_t *nonce, |
127 | | size_t alength, const uint8_t *adata, |
128 | | size_t mlength, const uint8_t *mdata, |
129 | | uint8_t *tag) |
130 | 0 | { |
131 | 0 | union nettle_block16 state; |
132 | 0 | struct gcm_key siv_ghash_key; |
133 | 0 | union nettle_block16 block; |
134 | |
|
135 | 0 | _siv_ghash_set_key (&siv_ghash_key, authentication_key); |
136 | |
|
137 | 0 | block16_zero (&state); |
138 | 0 | siv_ghash_pad_update (&siv_ghash_key, &state, alength, adata); |
139 | 0 | siv_ghash_pad_update (&siv_ghash_key, &state, mlength, mdata); |
140 | |
|
141 | 0 | block.u64[0] = bswap64_if_be (alength * 8); |
142 | 0 | block.u64[1] = bswap64_if_be (mlength * 8); |
143 | |
|
144 | 0 | _siv_ghash_update (&siv_ghash_key, &state, 1, block.b); |
145 | 0 | block16_bswap (&state, &state); |
146 | |
|
147 | 0 | memxor (state.b, nonce, SIV_GCM_NONCE_SIZE); |
148 | 0 | state.b[15] &= 0x7f; |
149 | 0 | nc->encrypt (ctx, SIV_GCM_BLOCK_SIZE, tag, state.b); |
150 | 0 | } |
151 | | |
152 | | void |
153 | | siv_gcm_encrypt_message (const struct nettle_cipher *nc, |
154 | | const void *ctx, |
155 | | void *ctr_ctx, |
156 | | size_t nlength, const uint8_t *nonce, |
157 | | size_t alength, const uint8_t *adata, |
158 | | size_t clength, uint8_t *dst, const uint8_t *src) |
159 | 0 | { |
160 | 0 | union nettle_block16 authentication_key; |
161 | 0 | TMP_DECL(encryption_key, uint8_t, NETTLE_MAX_CIPHER_KEY_SIZE); |
162 | 0 | uint8_t ctr[SIV_GCM_DIGEST_SIZE]; |
163 | 0 | uint8_t *tag = dst + clength - SIV_GCM_BLOCK_SIZE; |
164 | |
|
165 | 0 | assert (clength >= SIV_GCM_DIGEST_SIZE); |
166 | 0 | assert (nlength == SIV_GCM_NONCE_SIZE); |
167 | | |
168 | 0 | TMP_ALLOC(encryption_key, nc->key_size); |
169 | 0 | siv_gcm_derive_keys (ctx, nc->encrypt, nc->key_size, nlength, nonce, |
170 | 0 | &authentication_key, encryption_key); |
171 | | |
172 | | /* Calculate authentication tag. */ |
173 | 0 | nc->set_encrypt_key (ctr_ctx, encryption_key); |
174 | |
|
175 | 0 | siv_gcm_authenticate (ctr_ctx, nc, |
176 | 0 | &authentication_key, |
177 | 0 | nonce, alength, adata, |
178 | 0 | clength - SIV_GCM_BLOCK_SIZE, src, |
179 | 0 | tag); |
180 | | |
181 | | /* Encrypt the plaintext. */ |
182 | | |
183 | | /* The initial counter block is the tag with the most significant |
184 | | bit of the last byte set to one. */ |
185 | 0 | memcpy (ctr, tag, SIV_GCM_DIGEST_SIZE); |
186 | 0 | ctr[15] |= 0x80; |
187 | 0 | _nettle_ctr_crypt16 (ctr_ctx, nc->encrypt, siv_gcm_fill, ctr, |
188 | 0 | clength - SIV_GCM_BLOCK_SIZE, dst, src); |
189 | 0 | } |
190 | | |
191 | | int |
192 | | siv_gcm_decrypt_message (const struct nettle_cipher *nc, |
193 | | const void *ctx, |
194 | | void *ctr_ctx, |
195 | | size_t nlength, const uint8_t *nonce, |
196 | | size_t alength, const uint8_t *adata, |
197 | | size_t mlength, uint8_t *dst, const uint8_t *src) |
198 | 0 | { |
199 | 0 | union nettle_block16 authentication_key; |
200 | 0 | TMP_DECL(encryption_key, uint8_t, NETTLE_MAX_CIPHER_KEY_SIZE); |
201 | 0 | union nettle_block16 state; |
202 | 0 | uint8_t tag[SIV_GCM_DIGEST_SIZE]; |
203 | |
|
204 | 0 | assert (nlength == SIV_GCM_NONCE_SIZE); |
205 | | |
206 | 0 | TMP_ALLOC(encryption_key, nc->key_size); |
207 | 0 | siv_gcm_derive_keys (ctx, nc->encrypt, nc->key_size, nlength, nonce, |
208 | 0 | &authentication_key, encryption_key); |
209 | |
|
210 | 0 | memcpy (state.b, src + mlength, SIV_GCM_DIGEST_SIZE); |
211 | | /* The initial counter block is the tag with the most significant |
212 | | bit of the last byte set to one. */ |
213 | 0 | state.b[15] |= 0x80; |
214 | | |
215 | | /* Decrypt the ciphertext. */ |
216 | 0 | nc->set_encrypt_key (ctr_ctx, encryption_key); |
217 | |
|
218 | 0 | _nettle_ctr_crypt16 (ctr_ctx, nc->encrypt, siv_gcm_fill, state.b, |
219 | 0 | mlength, dst, src); |
220 | | |
221 | | /* Calculate authentication tag. */ |
222 | 0 | siv_gcm_authenticate (ctr_ctx, nc, |
223 | 0 | &authentication_key, |
224 | 0 | nonce, alength, adata, |
225 | 0 | mlength, dst, |
226 | 0 | tag); |
227 | |
|
228 | 0 | return memeql_sec (tag, src + mlength, SIV_GCM_DIGEST_SIZE); |
229 | 0 | } |