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