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 (!ciphertext) {
75 : LOG("AES-GCM encrypt error: unable to allocate memory\n");
76 0 : goto aes_gcm_encrypt_exit;
77 : }
78 :
79 4 : if (!random_getrandom(iv, sizeof(iv))) {
80 : LOG("AES-GCM encrypt error: error generating IV\n");
81 1 : goto aes_gcm_encrypt_exit;
82 : }
83 :
84 : // Set key
85 3 : if (mbedtls_gcm_setkey(
86 : &gcm_ctx, MBEDTLS_CIPHER_ID_AES, key, key_size * 8) != 0) {
87 : LOG("AES-GCM encrypt error: failed to set key\n");
88 1 : goto aes_gcm_encrypt_exit;
89 : }
90 :
91 : // Encrypt
92 2 : if (mbedtls_gcm_crypt_and_tag(&gcm_ctx,
93 : MBEDTLS_GCM_ENCRYPT,
94 : in_size,
95 : iv,
96 : sizeof(iv),
97 : NULL,
98 : 0,
99 : in,
100 : ciphertext,
101 : sizeof(tag),
102 : tag)) {
103 : LOG("AES-GCM encrypt error: encryption failed\n");
104 1 : goto aes_gcm_encrypt_exit;
105 : }
106 :
107 : // Output
108 1 : explicit_bzero(out, *out_size);
109 1 : memcpy(out, iv, sizeof(iv));
110 1 : memcpy(out + sizeof(iv), ciphertext, in_size);
111 1 : memcpy(out + sizeof(iv) + in_size, tag, sizeof(tag));
112 1 : *out_size = sizeof(iv) + in_size + sizeof(tag);
113 1 : retval = true;
114 :
115 8 : aes_gcm_encrypt_exit:
116 8 : mbedtls_gcm_free(&gcm_ctx);
117 8 : if (ciphertext)
118 4 : oe_free(ciphertext);
119 8 : return retval;
120 : }
121 :
122 7 : bool aes_gcm_decrypt(uint8_t* key,
123 : size_t key_size,
124 : uint8_t* in,
125 : size_t in_size,
126 : uint8_t* out,
127 : size_t* out_size) {
128 7 : bool retval = false;
129 : mbedtls_gcm_context gcm_ctx;
130 7 : mbedtls_gcm_init(&gcm_ctx);
131 7 : size_t cleartext_size = in_size - AES_IV_SIZE - AES_TAG_SIZE;
132 :
133 : // Sizes check
134 7 : if (AES_GCM_KEY_SIZE != key_size) {
135 : LOG("AES-GCM decrypt error: expected a %u-byte key\n",
136 : AES_GCM_KEY_SIZE);
137 2 : goto aes_gcm_decrypt_exit;
138 : }
139 5 : if (in_size <= AES_IV_SIZE + AES_TAG_SIZE) {
140 : LOG("AES-GCM decrypt error: input buffer too small\n");
141 1 : goto aes_gcm_decrypt_exit;
142 : }
143 4 : if (*out_size < cleartext_size) {
144 : LOG("AES-GCM decrypt error: output buffer too small\n");
145 1 : goto aes_gcm_decrypt_exit;
146 : }
147 :
148 : // Set key
149 3 : if (mbedtls_gcm_setkey(
150 : &gcm_ctx, MBEDTLS_CIPHER_ID_AES, key, key_size * 8) != 0) {
151 : LOG("AES-GCM decrypt error: failed to set key\n");
152 1 : goto aes_gcm_decrypt_exit;
153 : }
154 :
155 : // Decrypt
156 2 : if (mbedtls_gcm_auth_decrypt(&gcm_ctx,
157 : cleartext_size,
158 : in,
159 : AES_IV_SIZE,
160 : NULL,
161 : 0,
162 2 : &in[AES_IV_SIZE + cleartext_size],
163 : AES_TAG_SIZE,
164 2 : &in[AES_IV_SIZE],
165 : out) != 0) {
166 : LOG("AES-GCM decrypt error: decryption failed\n");
167 1 : goto aes_gcm_decrypt_exit;
168 : }
169 :
170 : // Ok
171 1 : *out_size = cleartext_size;
172 1 : retval = true;
173 :
174 7 : aes_gcm_decrypt_exit:
175 7 : mbedtls_gcm_free(&gcm_ctx);
176 7 : return retval;
177 : }
|