1 /* $OpenBSD: crypto.c,v 1.6 2016/09/03 14:42:08 gilles Exp $ */ 2 3 /* 4 * Copyright (c) 2013 Gilles Chehade <gilles@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/stat.h> 21 22 #include <stdlib.h> 23 #include <string.h> 24 25 #include <openssl/evp.h> 26 27 28 #define CRYPTO_BUFFER_SIZE 16384 29 30 #define GCM_TAG_SIZE 16 31 #define IV_SIZE 12 32 #define KEY_SIZE 32 33 34 /* bump if we ever switch from aes-256-gcm to anything else */ 35 #define API_VERSION 1 36 37 38 int crypto_setup(const char *, size_t); 39 int crypto_encrypt_file(FILE *, FILE *); 40 int crypto_decrypt_file(FILE *, FILE *); 41 size_t crypto_encrypt_buffer(const char *, size_t, char *, size_t); 42 size_t crypto_decrypt_buffer(const char *, size_t, char *, size_t); 43 44 static struct crypto_ctx { 45 unsigned char key[KEY_SIZE]; 46 } cp; 47 48 int 49 crypto_setup(const char *key, size_t len) 50 { 51 if (len != KEY_SIZE) 52 return 0; 53 54 memset(&cp, 0, sizeof cp); 55 56 /* openssl rand -hex 16 */ 57 memcpy(cp.key, key, sizeof cp.key); 58 59 return 1; 60 } 61 62 int 63 crypto_encrypt_file(FILE * in, FILE * out) 64 { 65 EVP_CIPHER_CTX ctx; 66 uint8_t ibuf[CRYPTO_BUFFER_SIZE]; 67 uint8_t obuf[CRYPTO_BUFFER_SIZE]; 68 uint8_t iv[IV_SIZE]; 69 uint8_t tag[GCM_TAG_SIZE]; 70 uint8_t version = API_VERSION; 71 size_t r, w; 72 int len; 73 int ret = 0; 74 struct stat sb; 75 76 /* XXX - Do NOT encrypt files bigger than 64GB */ 77 if (fstat(fileno(in), &sb) < 0) 78 return 0; 79 if (sb.st_size >= 0x1000000000LL) 80 return 0; 81 82 /* prepend version byte*/ 83 if ((w = fwrite(&version, 1, sizeof version, out)) != sizeof version) 84 return 0; 85 86 /* generate and prepend IV */ 87 memset(iv, 0, sizeof iv); 88 arc4random_buf(iv, sizeof iv); 89 if ((w = fwrite(iv, 1, sizeof iv, out)) != sizeof iv) 90 return 0; 91 92 EVP_CIPHER_CTX_init(&ctx); 93 EVP_EncryptInit_ex(&ctx, EVP_aes_256_gcm(), NULL, cp.key, iv); 94 95 /* encrypt until end of file */ 96 while ((r = fread(ibuf, 1, CRYPTO_BUFFER_SIZE, in)) != 0) { 97 if (!EVP_EncryptUpdate(&ctx, obuf, &len, ibuf, r)) 98 goto end; 99 if (len && (w = fwrite(obuf, len, 1, out)) != 1) 100 goto end; 101 } 102 if (!feof(in)) 103 goto end; 104 105 /* finalize and write last chunk if any */ 106 if (!EVP_EncryptFinal_ex(&ctx, obuf, &len)) 107 goto end; 108 if (len && (w = fwrite(obuf, len, 1, out)) != 1) 109 goto end; 110 111 /* get and append tag */ 112 EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, sizeof tag, tag); 113 if ((w = fwrite(tag, sizeof tag, 1, out)) != 1) 114 goto end; 115 116 fflush(out); 117 ret = 1; 118 119 end: 120 EVP_CIPHER_CTX_cleanup(&ctx); 121 return ret; 122 } 123 124 int 125 crypto_decrypt_file(FILE * in, FILE * out) 126 { 127 EVP_CIPHER_CTX ctx; 128 uint8_t ibuf[CRYPTO_BUFFER_SIZE]; 129 uint8_t obuf[CRYPTO_BUFFER_SIZE]; 130 uint8_t iv[IV_SIZE]; 131 uint8_t tag[GCM_TAG_SIZE]; 132 uint8_t version; 133 size_t r, w; 134 off_t sz; 135 int len; 136 int ret = 0; 137 struct stat sb; 138 139 /* input file too small to be an encrypted file */ 140 if (fstat(fileno(in), &sb) < 0) 141 return 0; 142 if (sb.st_size <= (off_t) (sizeof version + sizeof tag + sizeof iv)) 143 return 0; 144 sz = sb.st_size; 145 146 /* extract tag */ 147 if (fseek(in, -sizeof(tag), SEEK_END) == -1) 148 return 0; 149 if ((r = fread(tag, 1, sizeof tag, in)) != sizeof tag) 150 return 0; 151 152 if (fseek(in, 0, SEEK_SET) == -1) 153 return 0; 154 155 /* extract version */ 156 if ((r = fread(&version, 1, sizeof version, in)) != sizeof version) 157 return 0; 158 if (version != API_VERSION) 159 return 0; 160 161 /* extract IV */ 162 memset(iv, 0, sizeof iv); 163 if ((r = fread(iv, 1, sizeof iv, in)) != sizeof iv) 164 return 0; 165 166 /* real ciphertext length */ 167 sz -= sizeof version; 168 sz -= sizeof iv; 169 sz -= sizeof tag; 170 171 172 EVP_CIPHER_CTX_init(&ctx); 173 EVP_DecryptInit_ex(&ctx, EVP_aes_256_gcm(), NULL, cp.key, iv); 174 175 /* set expected tag */ 176 EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, sizeof tag, tag); 177 178 /* decrypt until end of ciphertext */ 179 while (sz) { 180 if (sz > CRYPTO_BUFFER_SIZE) 181 r = fread(ibuf, 1, CRYPTO_BUFFER_SIZE, in); 182 else 183 r = fread(ibuf, 1, sz, in); 184 if (!r) 185 break; 186 if (!EVP_DecryptUpdate(&ctx, obuf, &len, ibuf, r)) 187 goto end; 188 if (len && (w = fwrite(obuf, len, 1, out)) != 1) 189 goto end; 190 sz -= r; 191 } 192 if (ferror(in)) 193 goto end; 194 195 /* finalize, write last chunk if any and perform authentication check */ 196 if (!EVP_DecryptFinal_ex(&ctx, obuf, &len)) 197 goto end; 198 if (len && (w = fwrite(obuf, len, 1, out)) != 1) 199 goto end; 200 201 fflush(out); 202 ret = 1; 203 204 end: 205 EVP_CIPHER_CTX_cleanup(&ctx); 206 return ret; 207 } 208 209 size_t 210 crypto_encrypt_buffer(const char *in, size_t inlen, char *out, size_t outlen) 211 { 212 EVP_CIPHER_CTX ctx; 213 uint8_t iv[IV_SIZE]; 214 uint8_t tag[GCM_TAG_SIZE]; 215 uint8_t version = API_VERSION; 216 off_t sz; 217 int olen; 218 int len = 0; 219 int ret = 0; 220 221 /* output buffer does not have enough room */ 222 if (outlen < inlen + sizeof version + sizeof tag + sizeof iv) 223 return 0; 224 225 /* input should not exceed 64GB */ 226 sz = inlen; 227 if (sz >= 0x1000000000LL) 228 return 0; 229 230 /* prepend version */ 231 *out = version; 232 len++; 233 234 /* generate IV */ 235 memset(iv, 0, sizeof iv); 236 arc4random_buf(iv, sizeof iv); 237 memcpy(out + len, iv, sizeof iv); 238 len += sizeof iv; 239 240 EVP_CIPHER_CTX_init(&ctx); 241 EVP_EncryptInit_ex(&ctx, EVP_aes_256_gcm(), NULL, cp.key, iv); 242 243 /* encrypt buffer */ 244 if (!EVP_EncryptUpdate(&ctx, out + len, &olen, in, inlen)) 245 goto end; 246 len += olen; 247 248 /* finalize and write last chunk if any */ 249 if (!EVP_EncryptFinal_ex(&ctx, out + len, &olen)) 250 goto end; 251 len += olen; 252 253 /* get and append tag */ 254 EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, sizeof tag, tag); 255 memcpy(out + len, tag, sizeof tag); 256 ret = len + sizeof tag; 257 258 end: 259 EVP_CIPHER_CTX_cleanup(&ctx); 260 return ret; 261 } 262 263 size_t 264 crypto_decrypt_buffer(const char *in, size_t inlen, char *out, size_t outlen) 265 { 266 EVP_CIPHER_CTX ctx; 267 uint8_t iv[IV_SIZE]; 268 uint8_t tag[GCM_TAG_SIZE]; 269 int olen; 270 int len = 0; 271 int ret = 0; 272 273 /* out does not have enough room */ 274 if (outlen < inlen - sizeof tag + sizeof iv) 275 return 0; 276 277 /* extract tag */ 278 memcpy(tag, in + inlen - sizeof tag, sizeof tag); 279 inlen -= sizeof tag; 280 281 /* check version */ 282 if (*in != API_VERSION) 283 return 0; 284 in++; 285 inlen--; 286 287 /* extract IV */ 288 memset(iv, 0, sizeof iv); 289 memcpy(iv, in, sizeof iv); 290 inlen -= sizeof iv; 291 in += sizeof iv; 292 293 EVP_CIPHER_CTX_init(&ctx); 294 EVP_DecryptInit_ex(&ctx, EVP_aes_256_gcm(), NULL, cp.key, iv); 295 296 /* set expected tag */ 297 EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_TAG, sizeof tag, tag); 298 299 /* decrypt buffer */ 300 if (!EVP_DecryptUpdate(&ctx, out, &olen, in, inlen)) 301 goto end; 302 len += olen; 303 304 /* finalize, write last chunk if any and perform authentication check */ 305 if (!EVP_DecryptFinal_ex(&ctx, out + len, &olen)) 306 goto end; 307 ret = len + olen; 308 309 end: 310 EVP_CIPHER_CTX_cleanup(&ctx); 311 return ret; 312 } 313 314 #if 0 315 int 316 main(int argc, char *argv[]) 317 { 318 if (argc != 3) { 319 printf("usage: crypto <key> <buffer>\n"); 320 return 1; 321 } 322 323 if (!crypto_setup(argv[1], strlen(argv[1]))) { 324 printf("crypto_setup failed\n"); 325 return 1; 326 } 327 328 { 329 char encbuffer[4096]; 330 size_t enclen; 331 char decbuffer[4096]; 332 size_t declen; 333 334 printf("encrypt/decrypt buffer: "); 335 enclen = crypto_encrypt_buffer(argv[2], strlen(argv[2]), 336 encbuffer, sizeof encbuffer); 337 338 /* uncomment below to provoke integrity check failure */ 339 /* 340 * encbuffer[13] = 0x42; 341 * encbuffer[14] = 0x42; 342 * encbuffer[15] = 0x42; 343 * encbuffer[16] = 0x42; 344 */ 345 346 declen = crypto_decrypt_buffer(encbuffer, enclen, 347 decbuffer, sizeof decbuffer); 348 if (declen != 0 && !strncmp(argv[2], decbuffer, declen)) 349 printf("ok\n"); 350 else 351 printf("nope\n"); 352 } 353 354 { 355 FILE *fpin; 356 FILE *fpout; 357 printf("encrypt/decrypt file: "); 358 359 fpin = fopen("/etc/passwd", "r"); 360 fpout = fopen("/tmp/passwd.enc", "w"); 361 if (!crypto_encrypt_file(fpin, fpout)) { 362 printf("encryption failed\n"); 363 return 1; 364 } 365 fclose(fpin); 366 fclose(fpout); 367 368 /* uncomment below to provoke integrity check failure */ 369 /* 370 * fpin = fopen("/tmp/passwd.enc", "a"); 371 * fprintf(fpin, "borken"); 372 * fclose(fpin); 373 */ 374 fpin = fopen("/tmp/passwd.enc", "r"); 375 fpout = fopen("/tmp/passwd.dec", "w"); 376 if (!crypto_decrypt_file(fpin, fpout)) 377 printf("nope\n"); 378 else 379 printf("ok\n"); 380 fclose(fpin); 381 fclose(fpout); 382 } 383 384 385 return 0; 386 } 387 #endif 388