libsmb: Use reparse_data_buffer_parse() in cli_readlink()
[Samba.git] / lib / crypto / gnutls_aead_aes_256_cbc_hmac_sha512.c
blob2e37dcd23aae0feed76c86c556da483ff42dc10f
1 /*
2 * Copyright (c) 2021-2022 Andreas Schneider <asn@samba.org>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "includes.h"
19 #include "lib/util/data_blob.h"
20 #include <gnutls/gnutls.h>
21 #include <gnutls/crypto.h>
22 #include "gnutls_helpers.h"
24 #define SAMR_AES_VERSION_BYTE 0x01
25 #define SAMR_AES_VERSION_BYTE_LEN 1
27 static NTSTATUS calculate_enc_key(const DATA_BLOB *cek,
28 const DATA_BLOB *key_salt,
29 uint8_t enc_key[32])
31 gnutls_mac_algorithm_t hash_algo = GNUTLS_MAC_SHA512;
32 size_t hmac_size = gnutls_hmac_get_len(hash_algo);
33 uint8_t enc_key_data[hmac_size];
34 int rc;
36 rc = gnutls_hmac_fast(hash_algo,
37 cek->data,
38 cek->length,
39 key_salt->data,
40 key_salt->length,
41 enc_key_data);
42 if (rc < 0) {
43 return gnutls_error_to_ntstatus(rc,
44 NT_STATUS_ENCRYPTION_FAILED);
47 /* The key gets truncated to 32 byte */
48 memcpy(enc_key, enc_key_data, 32);
49 BURN_DATA(enc_key_data);
51 return NT_STATUS_OK;
54 static NTSTATUS calculate_mac_key(const DATA_BLOB *cek,
55 const DATA_BLOB *mac_salt,
56 uint8_t mac_key[64])
58 int rc;
60 rc = gnutls_hmac_fast(GNUTLS_MAC_SHA512,
61 cek->data,
62 cek->length,
63 mac_salt->data,
64 mac_salt->length,
65 mac_key);
66 if (rc < 0) {
67 return gnutls_error_to_ntstatus(rc,
68 NT_STATUS_ENCRYPTION_FAILED);
71 return NT_STATUS_OK;
74 /* This is an implementation of [MS-SAMR] 3.2.2.4 AES Cipher Usage */
76 NTSTATUS
77 samba_gnutls_aead_aes_256_cbc_hmac_sha512_encrypt(TALLOC_CTX *mem_ctx,
78 const DATA_BLOB *plaintext,
79 const DATA_BLOB *cek,
80 const DATA_BLOB *key_salt,
81 const DATA_BLOB *mac_salt,
82 const DATA_BLOB *iv,
83 DATA_BLOB *pciphertext,
84 uint8_t pauth_tag[64])
86 gnutls_hmac_hd_t hmac_hnd = NULL;
87 gnutls_mac_algorithm_t hmac_algo = GNUTLS_MAC_SHA512;
88 size_t hmac_size = gnutls_hmac_get_len(hmac_algo);
89 gnutls_cipher_hd_t cipher_hnd = NULL;
90 gnutls_cipher_algorithm_t cipher_algo = GNUTLS_CIPHER_AES_256_CBC;
91 uint32_t aes_block_size = gnutls_cipher_get_block_size(cipher_algo);
92 gnutls_datum_t iv_datum = {
93 .data = iv->data,
94 .size = iv->length,
96 uint8_t enc_key_data[32] = {0};
97 gnutls_datum_t enc_key = {
98 .data = enc_key_data,
99 .size = sizeof(enc_key_data),
101 uint8_t *cipher_text = NULL;
102 size_t cipher_text_len = 0;
103 uint8_t mac_key_data[64] = {0};
104 gnutls_datum_t mac_key = {
105 .data = mac_key_data,
106 .size = sizeof(mac_key_data),
108 uint8_t version_byte = SAMR_AES_VERSION_BYTE;
109 uint8_t version_byte_len = SAMR_AES_VERSION_BYTE_LEN;
110 uint8_t auth_data[hmac_size];
111 DATA_BLOB padded_plaintext;
112 size_t padding;
113 NTSTATUS status;
114 int rc;
117 * We don't want to overflow 'pauth_tag', which is 64 bytes in
118 * size.
120 SMB_ASSERT(hmac_size == 64);
122 if (plaintext->length == 0 || cek->length == 0 ||
123 key_salt->length == 0 || mac_salt->length == 0 || iv->length == 0) {
124 return NT_STATUS_INVALID_PARAMETER;
128 * PKCS#7 padding
130 * TODO: Use gnutls_cipher_encrypt3()
133 if (plaintext->length + aes_block_size < plaintext->length) {
134 return NT_STATUS_INVALID_BUFFER_SIZE;
137 padded_plaintext.length =
138 aes_block_size * (plaintext->length / aes_block_size) +
139 aes_block_size;
141 padding = padded_plaintext.length - plaintext->length;
143 padded_plaintext =
144 data_blob_talloc(mem_ctx, NULL, padded_plaintext.length);
145 if (padded_plaintext.data == NULL) {
146 return NT_STATUS_NO_MEMORY;
149 /* Allocate buffer for cipher text */
150 cipher_text_len = padded_plaintext.length;
151 cipher_text = talloc_size(mem_ctx, cipher_text_len);
152 if (cipher_text == NULL) {
153 data_blob_free(&padded_plaintext);
154 return NT_STATUS_NO_MEMORY;
157 memcpy(padded_plaintext.data, plaintext->data, plaintext->length);
158 memset(padded_plaintext.data + plaintext->length, padding, padding);
160 status = calculate_enc_key(cek, key_salt, enc_key_data);
161 if (!NT_STATUS_IS_OK(status)) {
162 data_blob_clear_free(&padded_plaintext);
163 return status;
166 /* Encrypt plaintext */
167 rc = gnutls_cipher_init(&cipher_hnd, cipher_algo, &enc_key, &iv_datum);
168 if (rc < 0) {
169 data_blob_clear_free(&padded_plaintext);
170 BURN_DATA(enc_key_data);
171 TALLOC_FREE(cipher_text);
172 return gnutls_error_to_ntstatus(rc,
173 NT_STATUS_ENCRYPTION_FAILED);
176 rc = gnutls_cipher_encrypt2(cipher_hnd,
177 padded_plaintext.data,
178 padded_plaintext.length,
179 cipher_text,
180 cipher_text_len);
181 gnutls_cipher_deinit(cipher_hnd);
182 data_blob_clear_free(&padded_plaintext);
183 BURN_DATA(enc_key_data);
184 if (rc < 0) {
185 TALLOC_FREE(cipher_text);
186 return gnutls_error_to_ntstatus(rc,
187 NT_STATUS_ENCRYPTION_FAILED);
190 /* Calculate mac key */
191 status = calculate_mac_key(cek, mac_salt, mac_key_data);
192 if (!NT_STATUS_IS_OK(status)) {
193 TALLOC_FREE(cipher_text);
194 return status;
197 /* Generate auth tag */
198 rc = gnutls_hmac_init(&hmac_hnd, hmac_algo, mac_key.data, mac_key.size);
199 BURN_DATA(mac_key_data);
200 if (rc < 0) {
201 TALLOC_FREE(cipher_text);
202 return gnutls_error_to_ntstatus(rc,
203 NT_STATUS_ENCRYPTION_FAILED);
206 rc = gnutls_hmac(hmac_hnd, &version_byte, sizeof(uint8_t));
207 if (rc < 0) {
208 TALLOC_FREE(cipher_text);
209 gnutls_hmac_deinit(hmac_hnd, NULL);
210 return gnutls_error_to_ntstatus(rc,
211 NT_STATUS_ENCRYPTION_FAILED);
214 rc = gnutls_hmac(hmac_hnd, iv->data, iv->length);
215 if (rc < 0) {
216 TALLOC_FREE(cipher_text);
217 gnutls_hmac_deinit(hmac_hnd, NULL);
218 return gnutls_error_to_ntstatus(rc,
219 NT_STATUS_ENCRYPTION_FAILED);
222 rc = gnutls_hmac(hmac_hnd, cipher_text, cipher_text_len);
223 if (rc < 0) {
224 TALLOC_FREE(cipher_text);
225 gnutls_hmac_deinit(hmac_hnd, NULL);
226 return gnutls_error_to_ntstatus(rc,
227 NT_STATUS_ENCRYPTION_FAILED);
230 rc = gnutls_hmac(hmac_hnd, &version_byte_len, sizeof(uint8_t));
231 if (rc < 0) {
232 TALLOC_FREE(cipher_text);
233 gnutls_hmac_deinit(hmac_hnd, NULL);
234 return gnutls_error_to_ntstatus(rc,
235 NT_STATUS_ENCRYPTION_FAILED);
237 gnutls_hmac_deinit(hmac_hnd, auth_data);
239 if (pciphertext != NULL) {
240 pciphertext->length = cipher_text_len;
241 pciphertext->data = cipher_text;
243 (void)memcpy(pauth_tag, auth_data, hmac_size);
245 return NT_STATUS_OK;
248 NTSTATUS
249 samba_gnutls_aead_aes_256_cbc_hmac_sha512_decrypt(TALLOC_CTX *mem_ctx,
250 const DATA_BLOB *ciphertext,
251 const DATA_BLOB *cdk,
252 const DATA_BLOB *key_salt,
253 const DATA_BLOB *mac_salt,
254 const DATA_BLOB *iv,
255 const uint8_t auth_tag[64],
256 DATA_BLOB *pplaintext)
258 gnutls_hmac_hd_t hmac_hnd = NULL;
259 gnutls_mac_algorithm_t hash_algo = GNUTLS_MAC_SHA512;
260 size_t hmac_size = gnutls_hmac_get_len(hash_algo);
261 uint8_t dec_key_data[32];
262 uint8_t mac_key_data[64];
263 gnutls_datum_t mac_key = {
264 .data = mac_key_data,
265 .size = sizeof(mac_key_data),
267 gnutls_cipher_hd_t cipher_hnd = NULL;
268 gnutls_cipher_algorithm_t cipher_algo = GNUTLS_CIPHER_AES_256_CBC;
269 gnutls_datum_t dec_key = {
270 .data = dec_key_data,
271 .size = sizeof(dec_key_data),
273 gnutls_datum_t iv_datum = {
274 .data = iv->data,
275 .size = iv->length,
277 uint8_t version_byte = SAMR_AES_VERSION_BYTE;
278 uint8_t version_byte_len = SAMR_AES_VERSION_BYTE_LEN;
279 uint8_t auth_data[hmac_size];
280 uint8_t padding;
281 size_t i;
282 NTSTATUS status;
283 bool equal;
284 int rc;
286 if (cdk->length == 0 || ciphertext->length == 0 ||
287 key_salt->length == 0 || mac_salt->length == 0 || iv->length == 0 ||
288 pplaintext == NULL) {
289 return NT_STATUS_INVALID_PARAMETER;
292 /* Calculate mac key */
293 status = calculate_mac_key(cdk, mac_salt, mac_key_data);
294 if (!NT_STATUS_IS_OK(status)) {
295 return status;
298 rc = gnutls_hmac_init(&hmac_hnd, hash_algo, mac_key.data, mac_key.size);
299 BURN_DATA(mac_key_data);
300 if (rc < 0) {
301 return gnutls_error_to_ntstatus(rc,
302 NT_STATUS_DECRYPTION_FAILED);
305 rc = gnutls_hmac(hmac_hnd, &version_byte, sizeof(uint8_t));
306 if (rc < 0) {
307 gnutls_hmac_deinit(hmac_hnd, NULL);
308 return gnutls_error_to_ntstatus(rc,
309 NT_STATUS_DECRYPTION_FAILED);
312 rc = gnutls_hmac(hmac_hnd, iv->data, iv->length);
313 if (rc < 0) {
314 gnutls_hmac_deinit(hmac_hnd, NULL);
315 return gnutls_error_to_ntstatus(rc,
316 NT_STATUS_DECRYPTION_FAILED);
319 rc = gnutls_hmac(hmac_hnd, ciphertext->data, ciphertext->length);
320 if (rc < 0) {
321 gnutls_hmac_deinit(hmac_hnd, NULL);
322 return gnutls_error_to_ntstatus(rc,
323 NT_STATUS_DECRYPTION_FAILED);
326 rc = gnutls_hmac(hmac_hnd, &version_byte_len, sizeof(uint8_t));
327 if (rc < 0) {
328 gnutls_hmac_deinit(hmac_hnd, NULL);
329 return gnutls_error_to_ntstatus(rc,
330 NT_STATUS_DECRYPTION_FAILED);
332 gnutls_hmac_deinit(hmac_hnd, auth_data);
334 equal = mem_equal_const_time(auth_data, auth_tag, sizeof(auth_data));
335 if (!equal) {
336 return NT_STATUS_DECRYPTION_FAILED;
339 *pplaintext = data_blob_talloc_zero(mem_ctx, ciphertext->length);
340 if (pplaintext->data == NULL) {
341 return NT_STATUS_NO_MEMORY;
344 /* Calculate decryption key */
345 status = calculate_enc_key(cdk, key_salt, dec_key_data);
346 if (!NT_STATUS_IS_OK(status)) {
347 return status;
350 rc = gnutls_cipher_init(&cipher_hnd, cipher_algo, &dec_key, &iv_datum);
351 BURN_DATA(dec_key_data);
352 if (rc < 0) {
353 data_blob_free(pplaintext);
354 return gnutls_error_to_ntstatus(rc,
355 NT_STATUS_DECRYPTION_FAILED);
358 rc = gnutls_cipher_decrypt2(cipher_hnd,
359 ciphertext->data,
360 ciphertext->length,
361 pplaintext->data,
362 pplaintext->length);
363 gnutls_cipher_deinit(cipher_hnd);
364 if (rc < 0) {
365 data_blob_clear_free(pplaintext);
366 return gnutls_error_to_ntstatus(rc,
367 NT_STATUS_DECRYPTION_FAILED);
371 * PKCS#7 padding
373 * TODO: Use gnutls_cipher_decrypt3()
377 * The plaintext is always padded.
379 * We already checked for ciphertext->length == 0 above and the
380 * pplaintext->length is equal to ciphertext->length here. We need to
381 * remove the padding from the plaintext size.
383 padding = pplaintext->data[pplaintext->length - 1];
384 if (padding == 0 || padding > 16) {
385 data_blob_clear_free(pplaintext);
386 return NT_STATUS_DECRYPTION_FAILED;
389 for (i = pplaintext->length - padding; i < pplaintext->length; i++) {
390 if (pplaintext->data[i] != padding) {
391 data_blob_clear_free(pplaintext);
392 return NT_STATUS_DECRYPTION_FAILED;
396 pplaintext->length -= padding;
398 return NT_STATUS_OK;