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