1 /*
2 * Copyright (C) 2014-2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <assert.h>
18 #include <lk/compiler.h>
19 #include <stdbool.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include <openssl/evp.h>
24 #include <openssl/hmac.h>
25 #include <openssl/rand.h>
26
27 #include "crypt.h"
28
29 /* Backwards compatability */
30 #if OPENSSL_VERSION_NUMBER < 0x10100000
EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX * ctx)31 static void EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX* ctx) {
32 EVP_CIPHER_CTX_cleanup(ctx);
33 EVP_CIPHER_CTX_init(ctx);
34 }
35
HMAC_CTX_new(void)36 static HMAC_CTX* HMAC_CTX_new(void) {
37 HMAC_CTX* ctx = malloc(sizeof(HMAC_CTX));
38 if (ctx) {
39 HMAC_CTX_init(ctx);
40 }
41 return ctx;
42 }
43
HMAC_CTX_reset(HMAC_CTX * ctx)44 static void HMAC_CTX_reset(HMAC_CTX* ctx) {
45 HMAC_CTX_cleanup(ctx);
46 HMAC_CTX_init(ctx);
47 }
48
HMAC_CTX_free(HMAC_CTX * ctx)49 static void HMAC_CTX_free(HMAC_CTX* ctx) {
50 if (ctx) {
51 HMAC_CTX_cleanup(ctx);
52 free(ctx);
53 }
54 }
55 #endif
56
57 /*
58 * The OpenSSL 1.1.0 API requires we allocate these dynamically. Cache them
59 * globally to avoid alocator thrash and the potential for another dynamic
60 * failure.
61 */
62 static EVP_CIPHER_CTX* cipher_ctx;
63 static HMAC_CTX* hmac_ctx;
64
crypt_init(void)65 void crypt_init(void) {
66 assert(!cipher_ctx);
67 assert(!hmac_ctx);
68
69 cipher_ctx = EVP_CIPHER_CTX_new();
70 assert(cipher_ctx);
71
72 hmac_ctx = HMAC_CTX_new();
73 assert(hmac_ctx);
74 }
75
crypt_shutdown(void)76 void crypt_shutdown(void) {
77 EVP_CIPHER_CTX_free(cipher_ctx);
78 cipher_ctx = NULL;
79
80 HMAC_CTX_free(hmac_ctx);
81 hmac_ctx = NULL;
82 }
83
84 /**
85 * crypt - Helper function for encrypt and decrypt.
86 * @key: Key object.
87 * @data_in_out: Data to encrypt or decrypt.
88 * @data_size: Number of bytes in @data_in_out.
89 * @iv: Initialization vector to use for Cipher Block Chaining.
90 * @encrypt: %true to select encrypt, %false to select decrypt.
91 *
92 * Return: 0 on success, -1 if an error was detected.
93 */
crypt(const struct key * key,void * data_in_out,size_t data_size,const struct iv * iv,bool encrypt)94 static int crypt(const struct key* key,
95 void* data_in_out,
96 size_t data_size,
97 const struct iv* iv,
98 bool encrypt) {
99 int evp_ret;
100 const EVP_CIPHER* cipher;
101 int out_data_size;
102 size_t key_len;
103
104 /*
105 * Make sure iv is large enough. Current implementation allows static
106 * check.
107 * TODO: Switch to runtime check for selcted cipher if EVP_MAX_IV_LENGTH
108 * changes to cover larger ivs used by other cipers.
109 */
110 STATIC_ASSERT(sizeof(*iv) >= EVP_MAX_IV_LENGTH);
111
112 cipher = EVP_aes_128_ctr();
113 key_len = EVP_CIPHER_key_length(cipher);
114 if (key_len > sizeof(*key)) {
115 fprintf(stderr, "key too small for selected cipher, %zd < %zd\n",
116 sizeof(*key), key_len);
117 evp_ret = 0;
118 goto err;
119 }
120
121 assert(cipher_ctx);
122 EVP_CIPHER_CTX_reset(cipher_ctx);
123
124 evp_ret = EVP_CipherInit_ex(cipher_ctx, cipher, NULL, key->byte, iv->byte,
125 encrypt);
126 if (!evp_ret) {
127 fprintf(stderr, "EVP_CipherInit_ex failed\n");
128 goto err;
129 }
130
131 evp_ret = EVP_CIPHER_CTX_set_padding(cipher_ctx, 0);
132 if (!evp_ret) {
133 fprintf(stderr, "EVP_CIPHER_CTX_set_padding failed\n");
134 goto err;
135 }
136
137 evp_ret = EVP_CipherUpdate(cipher_ctx, data_in_out, &out_data_size,
138 data_in_out, data_size);
139 if (!evp_ret) {
140 fprintf(stderr, "EVP_CipherUpdate failed\n");
141 goto err;
142 }
143 if (out_data_size != (int)data_size) {
144 fprintf(stderr, "bad output data size %d != %zd\n", out_data_size,
145 data_size);
146 evp_ret = 0;
147 goto err;
148 }
149
150 evp_ret = EVP_CipherFinal_ex(cipher_ctx, NULL, &out_data_size);
151 if (!evp_ret) {
152 fprintf(stderr, "EVP_CipherFinal_ex failed\n");
153 goto err;
154 }
155
156 err:
157 return evp_ret ? 0 : -1;
158 }
159
160 /**
161 * str_hash - Cacluate a 64-bit hash for a string.
162 * @str: Key object.
163 *
164 * Return: Low 8 bytes of SHA1 hash as a little endian 64 bit value.
165 */
str_hash(const char * str)166 uint64_t str_hash(const char* str) {
167 int evp_ret;
168 size_t len = strlen(str);
169 uint8_t md[EVP_MAX_MD_SIZE];
170 uint64_t ret;
171
172 evp_ret = EVP_Digest(str, len, md, NULL, EVP_sha1(), NULL);
173 if (!evp_ret) {
174 fprintf(stderr, "EVP_Digest failed\n");
175 assert(false);
176 return 0;
177 }
178 STATIC_ASSERT(sizeof(ret) <= sizeof(md));
179 memcpy(&ret, md, sizeof(ret));
180 return ret;
181 }
182
183 /**
184 * calculate_mac - Calulate keyed-hash message authentication code (HMAC SHA256)
185 * @key: Key object.
186 * @mac: Mac object to return calulated mac in.
187 * @data: Data to calculate mac for.
188 * @data_size: Number of bytes in @data.
189 *
190 * Return: 0 on success, -1 if an error was detected.
191 */
calculate_mac(const struct key * key,struct mac * mac,const void * data,size_t data_size)192 int calculate_mac(const struct key* key,
193 struct mac* mac,
194 const void* data,
195 size_t data_size) {
196 int hmac_ret;
197 unsigned int md_len;
198 unsigned char mac_buf[EVP_MAX_MD_SIZE];
199
200 assert(hmac_ctx);
201 HMAC_CTX_reset(hmac_ctx);
202
203 hmac_ret = HMAC_Init_ex(hmac_ctx, key, sizeof(*key), EVP_sha256(), NULL);
204 if (!hmac_ret) {
205 fprintf(stderr, "HMAC_Init_ex failed\n");
206 goto err;
207 }
208
209 hmac_ret = HMAC_Update(hmac_ctx, data, data_size);
210 if (!hmac_ret) {
211 fprintf(stderr, "HMAC_Update failed\n");
212 goto err;
213 }
214
215 hmac_ret = HMAC_Final(hmac_ctx, mac_buf, &md_len);
216 if (!hmac_ret) {
217 fprintf(stderr, "HMAC_Final failed\n");
218 goto err;
219 }
220 if (md_len < sizeof(*mac)) {
221 fprintf(stderr, "bad md_len %d < %zd\n", md_len, sizeof(*mac));
222 hmac_ret = 0;
223 goto err;
224 }
225 memcpy(mac, mac_buf, sizeof(*mac));
226
227 err:
228 return hmac_ret ? 0 : -1;
229 }
230
231 /**
232 * generate_iv - Generate a random iv value.
233 * @iv_out: IV object.
234 *
235 * Return: 0 on success, -1 if an error was detected.
236 */
generate_iv(struct iv * iv_out)237 int generate_iv(struct iv* iv_out) {
238 int rand_ret;
239
240 rand_ret = RAND_bytes(iv_out->byte, sizeof(iv_out->byte));
241 if (!rand_ret) {
242 fprintf(stderr, "RAND_bytes failed\n");
243 }
244 return rand_ret ? 0 : -1;
245 }
246
247 /**
248 * storage_encrypt - Encrypt data using AES-128-CTR.
249 * @key: Key object.
250 * @data_in_out: Data to encrypt.
251 * @data_size: Number of bytes in @data_in_out, but be a multiple of
252 * AES_BLOCK_SIZE.
253 * @iv_in: Initialization vector to use for Cipher Block Chaining.
254 *
255 * Return: 0 on success, -1 if an error was detected.
256 */
storage_encrypt(const struct key * key,void * data_in_out,size_t data_size,const struct iv * iv_in)257 int storage_encrypt(const struct key* key,
258 void* data_in_out,
259 size_t data_size,
260 const struct iv* iv_in) {
261 return crypt(key, data_in_out, data_size, iv_in, true);
262 }
263
264 /**
265 * storage_decrypt - Decrypt data using AES-128-CTR.
266 * @key: Key object.
267 * @data_in_out: Data to decrypt.
268 * @data_size: Number of bytes in @data_in_out, but be a multiple of
269 * AES_BLOCK_SIZE.
270 * @iv_in: Initialization vector to use for Cipher Block Chaining.
271 *
272 * Return: 0 on success, -1 if an error was detected.
273 */
storage_decrypt(const struct key * key,void * data_in_out,size_t data_size,const struct iv * iv_in)274 int storage_decrypt(const struct key* key,
275 void* data_in_out,
276 size_t data_size,
277 const struct iv* iv_in) {
278 return crypt(key, data_in_out, data_size, iv_in, false);
279 }
280