Line data Source code
1 : /**
2 : * The MIT License (MIT)
3 : *
4 : * Copyright (c) 2021 RSK Labs Ltd
5 : *
6 : * Permission is hereby granted, free of charge, to any person obtaining a copy
7 : * of this software and associated documentation files (the "Software"), to
8 : * deal in the Software without restriction, including without limitation the
9 : * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 : * sell copies of the Software, and to permit persons to whom the Software is
11 : * furnished to do so, subject to the following conditions:
12 : *
13 : * The above copyright notice and this permission notice shall be included in
14 : * all copies or substantial portions of the Software.
15 : *
16 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22 : * IN THE SOFTWARE.
23 : */
24 :
25 : #include <stdlib.h>
26 : #include <stdbool.h>
27 : #include <stdint.h>
28 : #include <string.h>
29 : #include "hal/log.h"
30 : #include "random.h"
31 : #include <openenclave/corelibc/stdlib.h>
32 : #include <mbedtls/gcm.h>
33 :
34 : #define AES_GCM_KEY_SIZE 32 // AES-256
35 : #define AES_IV_SIZE 12 // Recommended IV size for GCM
36 : #define AES_TAG_SIZE 16 // Authentication tag size
37 :
38 3 : size_t aes_gcm_get_encrypted_size(size_t cleartext_size) {
39 3 : if (cleartext_size + AES_IV_SIZE + AES_TAG_SIZE < cleartext_size)
40 1 : return 0; // Overflow
41 2 : return cleartext_size + AES_IV_SIZE + AES_TAG_SIZE;
42 : }
43 :
44 8 : bool aes_gcm_encrypt(uint8_t* key,
45 : size_t key_size,
46 : uint8_t* in,
47 : size_t in_size,
48 : uint8_t* out,
49 : size_t* out_size) {
50 8 : bool retval = false;
51 : mbedtls_gcm_context gcm_ctx;
52 8 : mbedtls_gcm_init(&gcm_ctx);
53 : uint8_t iv[AES_IV_SIZE];
54 : uint8_t tag[AES_TAG_SIZE];
55 8 : uint8_t* ciphertext = NULL;
56 :
57 : // Sizes check
58 8 : if (AES_GCM_KEY_SIZE != key_size) {
59 : LOG("AES-GCM encrypt error: expected a %u-byte key\n",
60 : AES_GCM_KEY_SIZE);
61 2 : goto aes_gcm_encrypt_exit;
62 : }
63 6 : if (in_size == 0) {
64 : LOG("AES-GCM encrypt error: input buffer too small\n");
65 1 : goto aes_gcm_encrypt_exit;
66 : }
67 5 : if (*out_size < in_size + sizeof(iv) + sizeof(tag)) {
68 : LOG("AES-GCM encrypt error: output buffer too small\n");
69 1 : goto aes_gcm_encrypt_exit;
70 : }
71 :
72 : // Init buffers
73 4 : ciphertext = oe_malloc(in_size);
74 4 : if (!random_getrandom(iv, sizeof(iv))) {
75 : LOG("AES-GCM encrypt error: error generating IV\n");
76 1 : goto aes_gcm_encrypt_exit;
77 : }
78 :
79 : // Set key
80 3 : if (mbedtls_gcm_setkey(
81 : &gcm_ctx, MBEDTLS_CIPHER_ID_AES, key, key_size * 8) != 0) {
82 : LOG("AES-GCM encrypt error: failed to set key\n");
83 1 : goto aes_gcm_encrypt_exit;
84 : }
85 :
86 : // Encrypt
87 2 : if (mbedtls_gcm_crypt_and_tag(&gcm_ctx,
88 : MBEDTLS_GCM_ENCRYPT,
89 : in_size,
90 : iv,
91 : sizeof(iv),
92 : NULL,
93 : 0,
94 : in,
95 : ciphertext,
96 : sizeof(tag),
97 : tag)) {
98 : LOG("AES-GCM encrypt error: encryption failed\n");
99 1 : goto aes_gcm_encrypt_exit;
100 : }
101 :
102 : // Output
103 1 : explicit_bzero(out, *out_size);
104 1 : memcpy(out, iv, sizeof(iv));
105 1 : memcpy(out + sizeof(iv), ciphertext, in_size);
106 1 : memcpy(out + sizeof(iv) + in_size, tag, sizeof(tag));
107 1 : *out_size = sizeof(iv) + in_size + sizeof(tag);
108 1 : retval = true;
109 :
110 8 : aes_gcm_encrypt_exit:
111 8 : mbedtls_gcm_free(&gcm_ctx);
112 8 : if (ciphertext)
113 4 : oe_free(ciphertext);
114 8 : return retval;
115 : }
116 :
117 7 : bool aes_gcm_decrypt(uint8_t* key,
118 : size_t key_size,
119 : uint8_t* in,
120 : size_t in_size,
121 : uint8_t* out,
122 : size_t* out_size) {
123 7 : bool retval = false;
124 : mbedtls_gcm_context gcm_ctx;
125 7 : mbedtls_gcm_init(&gcm_ctx);
126 7 : size_t cleartext_size = in_size - AES_IV_SIZE - AES_TAG_SIZE;
127 :
128 : // Sizes check
129 7 : if (AES_GCM_KEY_SIZE != key_size) {
130 : LOG("AES-GCM decrypt error: expected a %u-byte key\n",
131 : AES_GCM_KEY_SIZE);
132 2 : goto aes_gcm_decrypt_exit;
133 : }
134 5 : if (in_size <= AES_IV_SIZE + AES_TAG_SIZE) {
135 : LOG("AES-GCM decrypt error: input buffer too small\n");
136 1 : goto aes_gcm_decrypt_exit;
137 : }
138 4 : if (*out_size < cleartext_size) {
139 : LOG("AES-GCM decrypt error: output buffer too small\n");
140 1 : goto aes_gcm_decrypt_exit;
141 : }
142 :
143 : // Set key
144 3 : if (mbedtls_gcm_setkey(
145 : &gcm_ctx, MBEDTLS_CIPHER_ID_AES, key, key_size * 8) != 0) {
146 : LOG("AES-GCM decrypt error: failed to set key\n");
147 1 : goto aes_gcm_decrypt_exit;
148 : }
149 :
150 : // Decrypt
151 2 : if (mbedtls_gcm_auth_decrypt(&gcm_ctx,
152 : cleartext_size,
153 : in,
154 : AES_IV_SIZE,
155 : NULL,
156 : 0,
157 2 : &in[AES_IV_SIZE + cleartext_size],
158 : AES_TAG_SIZE,
159 2 : &in[AES_IV_SIZE],
160 : out) != 0) {
161 : LOG("AES-GCM decrypt error: decryption failed\n");
162 1 : goto aes_gcm_decrypt_exit;
163 : }
164 :
165 : // Ok
166 1 : *out_size = cleartext_size;
167 1 : retval = true;
168 :
169 7 : aes_gcm_decrypt_exit:
170 7 : mbedtls_gcm_free(&gcm_ctx);
171 7 : return retval;
172 : }
|