1 /*===========================================================================
2 *
3 * PUBLIC DOMAIN NOTICE
4 * National Center for Biotechnology Information
5 *
6 * This software/database is a "United States Government Work" under the
7 * terms of the United States Copyright Act. It was written as part of
8 * the author's official duties as a United States Government employee and
9 * thus cannot be copyrighted. This software/database is freely available
10 * to the public for use. The National Library of Medicine and the U.S.
11 * Government have not placed any restriction on its use or reproduction.
12 *
13 * Although all reasonable efforts have been taken to ensure the accuracy
14 * and reliability of the software and data, the NLM and the U.S.
15 * Government do not and cannot warrant the performance or results that
16 * may be obtained by using this software or data. The NLM and the U.S.
17 * Government disclaim all warranties, express or implied, including
18 * warranties of performance, merchantability or fitness for any particular
19 * purpose.
20 *
21 * Please cite the author in any work or product based on this material.
22 *
23 * ===========================================================================
24 */
25
26 #include <krypto/extern.h>
27 #include <krypto/rsa-aes-hmac.h>
28
29 #include <klib/rc.h>
30 #include <klib/text.h>
31 #include <klib/log.h>
32 #include <klib/debug.h>
33 #include <klib/status.h>
34 #include <klib/data-buffer.h>
35
36 #include <mbedtls/pk.h>
37 #include <mbedtls/aes.h>
38 #include <mbedtls/entropy.h>
39 #include <mbedtls/ctr_drbg.h>
40 #include <mbedtls/error.h>
41
42 #define AES_KEY_BITS 256
43 #define AES_BLOCK_BYTES 16
44 #define SHA_256_BITS 256
45
46 static
aes_block_trunc(size_t s)47 size_t aes_block_trunc ( size_t s )
48 {
49 return s & ~ ( size_t ) ( AES_BLOCK_BYTES - 1 );
50 }
51
52 static
aes_block_round_up(size_t s)53 size_t aes_block_round_up ( size_t s )
54 {
55 return aes_block_trunc ( s + AES_BLOCK_BYTES - 1 );
56 }
57
58 typedef struct Rgn Rgn;
59 struct Rgn
60 {
61 uint8_t * p;
62 size_t s;
63 };
64
65 static
RgnInit(Rgn * r,void * p,size_t s)66 Rgn * RgnInit ( Rgn * r, void * p, size_t s )
67 {
68 r -> p = p;
69 r -> s = s;
70 return r;
71 }
72
73 static
RgnEqual(const Rgn * a,const Rgn * b)74 bool RgnEqual ( const Rgn * a, const Rgn * b )
75 {
76 return a -> s == b -> s && memcmp ( a -> p, b -> p, a -> s ) == 0;
77 }
78
79 static
RgnCopy(Rgn * dst,const Rgn * src)80 Rgn * RgnCopy ( Rgn * dst, const Rgn * src )
81 {
82 memmove ( dst -> p, src -> p,
83 ( dst -> s <= src -> s ) ? dst -> s : src -> s );
84 return dst;
85 }
86
87 static
RgnFill(Rgn * self,uint8_t b)88 Rgn * RgnFill ( Rgn * self, uint8_t b )
89 {
90 memset ( self -> p, b, self -> s );
91 return self;
92 }
93
94 static
RgnSubRgn(const Rgn * self,size_t offset)95 Rgn RgnSubRgn ( const Rgn * self, size_t offset )
96 {
97 Rgn sub = * self;
98 if ( offset > self -> s )
99 {
100 sub . p += self -> s;
101 sub . s = 0;
102 }
103 else
104 {
105 sub . p += offset;
106 sub . s -= offset;
107 }
108 return sub;
109 }
110
111 static
RgnSubRgn2(const Rgn * self,size_t offset,size_t bytes)112 Rgn RgnSubRgn2 ( const Rgn * self, size_t offset, size_t bytes )
113 {
114 Rgn sub = RgnSubRgn ( self, offset );
115 if ( bytes < sub . s )
116 sub . s = bytes;
117 return sub;
118 }
119
120 static
KDataBufferMakeRgn(const KDataBuffer * b)121 Rgn KDataBufferMakeRgn ( const KDataBuffer * b )
122 {
123 Rgn rgn;
124 rgn . p = ( uint8_t * ) b -> base;
125 rgn . s = KDataBufferBytes ( b );
126 return rgn;
127 }
128
129 static
handle_mbedtls_return(const char * func_desc,int ret)130 rc_t handle_mbedtls_return ( const char * func_desc, int ret )
131 {
132 if ( ret != 0 )
133 {
134 return -1;
135 }
136 return 0;
137 }
138
139 #define CALL_MBEDTLS( func_name, params ) \
140 handle_mbedtls_return ( # func_name, vdb_ ## func_name params )
141
142 typedef struct EncryptStuff EncryptStuff;
143 struct EncryptStuff
144 {
145 mbedtls_entropy_context entropy;
146 mbedtls_ctr_drbg_context ctr_drbg;
147 mbedtls_pk_context pek;
148 mbedtls_md_context_t md;
149 mbedtls_aes_context aes;
150 uint32_t state;
151 unsigned char sk [ AES_KEY_BITS / 8 ];
152 };
153
154 enum
155 {
156 es_nada = 0,
157
158 es_entropy,
159 es_ctr_drbg,
160 es_pek,
161 es_aes_key,
162 es_md,
163 es_aes,
164
165 es_invalid,
166 es_last_valid = es_invalid - 1
167 };
168
169 static
EncryptStuffInit(EncryptStuff * s)170 void EncryptStuffInit ( EncryptStuff * s )
171 {
172 s -> state = es_nada;
173 }
174
175 static
EncryptStuffWhack(EncryptStuff * s)176 void EncryptStuffWhack ( EncryptStuff * s )
177 {
178 switch ( s -> state )
179 {
180 case es_aes:
181 vdb_mbedtls_aes_free ( & s -> aes );
182 case es_md:
183 vdb_mbedtls_md_free ( & s -> md );
184 case es_aes_key:
185 memset ( s -> sk, 0, sizeof s -> sk );
186 case es_pek:
187 vdb_mbedtls_pk_free ( & s -> pek );
188 case es_ctr_drbg:
189 vdb_mbedtls_ctr_drbg_free ( & s -> ctr_drbg );
190 case es_entropy:
191 vdb_mbedtls_entropy_free ( & s -> entropy );
192 break;
193 }
194 }
195
196 static
EncryptStuffAdvance(EncryptStuff * s,uint32_t state)197 rc_t EncryptStuffAdvance ( EncryptStuff * s, uint32_t state )
198 {
199 rc_t rc = 0;
200
201 STATUS ( STAT_GEEK, "%s - advancing from state %u to %u\n", __func__, s -> state, state );
202
203 if ( state > es_last_valid )
204 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcParam, rcInvalid );
205 if ( state != s -> state + 1 )
206 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcParam, rcInvalid );
207
208 switch ( state )
209 {
210 case es_entropy:
211 vdb_mbedtls_entropy_init ( & s -> entropy );
212 break;
213 case es_ctr_drbg:
214 vdb_mbedtls_ctr_drbg_init ( & s -> ctr_drbg );
215 break;
216 case es_pek:
217 vdb_mbedtls_pk_init ( & s -> pek );
218 break;
219 case es_aes_key:
220 rc = CALL_MBEDTLS ( mbedtls_ctr_drbg_random, ( & s -> ctr_drbg, s -> sk, sizeof s -> sk ) );
221 break;
222 case es_md:
223 vdb_mbedtls_md_init ( & s -> md );
224 break;
225 case es_aes:
226 vdb_mbedtls_aes_init ( & s -> aes );
227 break;
228 }
229
230 if ( rc == 0 )
231 s -> state = state;
232
233 return rc;
234 }
235
236 static
RsaAesHmacEncryptInt(KDataBuffer * out,const void * in,size_t in_bytes,const char * zpek)237 rc_t RsaAesHmacEncryptInt ( KDataBuffer * out,
238 const void * in, size_t in_bytes, const char * zpek )
239 {
240 /* initialized, empty byte buffer */
241 rc_t rc = KDataBufferMakeBytes ( out, 0 );
242 if ( rc == 0 )
243 {
244 EncryptStuff s;
245 EncryptStuffInit ( & s );
246
247 do
248 {
249 uint32_t i;
250 size_t esk_size;
251 Rgn pt, ob, digest, ct, rgn, rgn2;
252 unsigned char iv [ AES_BLOCK_BYTES ];
253 unsigned char esk [ MBEDTLS_MPI_MAX_SIZE ];
254 const char * pers = "krypty the AES generating bear";
255
256 /* capture the input as "pt" plaintext region */
257 STATUS ( STAT_GEEK, "%s - capturing plaintext region\n", __func__ );
258 RgnInit ( & pt, ( void * ) in, in_bytes );
259
260 /* initialize entropy and prng */
261 STATUS ( STAT_PRG, "%s - initializing entropy\n", __func__ );
262 rc = EncryptStuffAdvance ( & s, es_entropy );
263 if ( rc != 0 )
264 break;
265 STATUS ( STAT_PRG, "%s - initializing PRNG\n", __func__ );
266 rc = EncryptStuffAdvance ( & s, es_ctr_drbg );
267 if ( rc != 0 )
268 break;
269
270 /* set random seed and entropy function,
271 flavor oddly with some constant data... */
272 STATUS ( STAT_PRG, "%s - seeding PRNG\n", __func__ );
273 rc = CALL_MBEDTLS ( mbedtls_ctr_drbg_seed, ( & s . ctr_drbg,
274 vdb_mbedtls_entropy_func, & s . entropy,
275 ( const unsigned char * ) pers, strlen ( pers )
276 ) );
277 if ( rc != 0 )
278 break;
279
280 /* initialize the public encryption key */
281 STATUS ( STAT_PRG, "%s - initializing RSA context\n", __func__ );
282 rc = EncryptStuffAdvance ( & s, es_pek );
283 if ( rc != 0 )
284 break;
285
286 /* parse the PEM key */
287 STATUS ( STAT_PRG, "%s - parsing PEK\n", __func__ );
288 rc = CALL_MBEDTLS ( mbedtls_pk_parse_public_key, ( & s . pek,
289 ( const unsigned char * ) zpek, strlen ( zpek ) + 1 ) );
290 if ( rc != 0 )
291 break;
292
293 /* fill symmetric AES key with random bits */
294 STATUS ( STAT_PRG, "%s - creating random AES key\n", __func__ );
295 rc = EncryptStuffAdvance ( & s, es_aes_key );
296 if ( rc != 0 )
297 break;
298
299 /* encrypt the AES key with RSA key */
300 STATUS ( STAT_PRG, "%s - encrypting AES key with RSA key\n", __func__ );
301 rc = CALL_MBEDTLS ( mbedtls_pk_encrypt, ( & s . pek,
302 s . sk, sizeof s . sk,
303 esk, & esk_size, sizeof esk,
304 vdb_mbedtls_ctr_drbg_random, & s . ctr_drbg
305 ) );
306 if ( rc != 0 )
307 break;
308
309 /* at THIS point, we know how large the output buffer has to be.
310 we can resize it now and then work within the allocated regions. */
311 STATUS ( STAT_PRG, "%s - setting output buffer size\n", __func__ );
312 rc = KDataBufferResize ( out,
313 esk_size + /* RSA-encrypted AES key */
314 sizeof iv + /* initialization vector */
315 aes_block_round_up ( pt . s ) + /* AES ciphertext */
316 ( SHA_256_BITS / 8 ) /* SHA-256-HMAC */
317 );
318 if ( rc != 0 )
319 break;
320 STATUS ( STAT_GEEK, "%s - size set to %lu bytes:\n", __func__, out -> elem_count );
321 STATUS ( STAT_GEEK, "%s - esk size = %zu\n", __func__, esk_size );
322 STATUS ( STAT_GEEK, "%s - iv size = %zu\n", __func__, sizeof iv );
323 STATUS ( STAT_GEEK, "%s - ct size = %zu\n", __func__, aes_block_round_up ( pt . s ) );
324 STATUS ( STAT_GEEK, "%s - hmac size = %zu\n", __func__, ( SHA_256_BITS / 8 ) );
325
326 /* capture the output buffer in a region */
327 STATUS ( STAT_GEEK, "%s - capturing output buffer as Rgn\n", __func__ );
328 ob = KDataBufferMakeRgn ( out );
329 STATUS ( STAT_GEEK, "%s - output Rgn ptr = %p\n", __func__, ob . p );
330 STATUS ( STAT_GEEK, "%s - output Rgn size = %zu\n", __func__, ob . s );
331
332 /* copy "esk" to output buffer */
333 STATUS ( STAT_GEEK, "%s - copying %zu byte esk to output\n", __func__, esk_size );
334 RgnCopy ( & ob, RgnInit ( & rgn, esk, esk_size ) );
335
336 /* forget about this portion of the buffer
337 operation is safe even for reassigning to self
338 */
339 STATUS ( STAT_GEEK, "%s - redefining output Rgn to skip over esk\n", __func__ );
340 ob = RgnSubRgn ( & ob, esk_size );
341 STATUS ( STAT_GEEK, "%s - output Rgn ptr = %p\n", __func__, ob . p );
342 STATUS ( STAT_GEEK, "%s - output Rgn size = %zu\n", __func__, ob . s );
343
344 /* capture digest region */
345 STATUS ( STAT_GEEK, "%s - capturing digest as Rgn\n", __func__ );
346 digest = RgnSubRgn ( & ob, ob . s - SHA_256_BITS / 8 );
347 STATUS ( STAT_GEEK, "%s - digest Rgn ptr = %p\n", __func__, digest . p );
348 STATUS ( STAT_GEEK, "%s - digest Rgn size = %zu\n", __func__, digest . s );
349 STATUS ( STAT_GEEK, "%s - redefining output Rgn to remove digest\n", __func__ );
350 ob = RgnSubRgn2 ( & ob, 0, ob . s - digest . s );
351 STATUS ( STAT_GEEK, "%s - output Rgn ptr = %p\n", __func__, ob . p );
352 STATUS ( STAT_GEEK, "%s - output Rgn size = %zu\n", __func__, ob . s );
353
354 /* fill IV with random bits */
355 STATUS ( STAT_PRG, "%s - filling iv buffer with random bits\n", __func__ );
356 rc = CALL_MBEDTLS ( mbedtls_ctr_drbg_random, ( & s . ctr_drbg, iv, sizeof iv ) );
357 if ( rc != 0 )
358 break;
359
360 /* store padding adjust in lowest nibble
361 and yes, we KNOW this will fit because
362 each AES block is 16 bytes, meaning the
363 adjustment will be 0..15
364 */
365 STATUS ( STAT_GEEK, "%s - encoding padding bytes into last nibble of iv\n", __func__ );
366 assert ( AES_BLOCK_BYTES == 16 );
367 assert ( sizeof iv == AES_BLOCK_BYTES );
368 iv [ sizeof iv - 1 ] &= 0xF0;
369 iv [ sizeof iv - 1 ] |= ( sizeof iv - ( in_bytes & 0xF ) ) & 0xF;
370
371 /* output "iv" to the buffer */
372 STATUS ( STAT_GEEK, "%s - copying iv into output Rgn\n", __func__ );
373 RgnCopy ( & ob, RgnInit ( & rgn2, iv, sizeof iv ) );
374
375 /* capture ciphertext region */
376 STATUS ( STAT_GEEK, "%s - capturing ct Rgn\n", __func__ );
377 ct = RgnSubRgn ( & ob, rgn2 . s );
378 STATUS ( STAT_GEEK, "%s - ct Rgn ptr = %p\n", __func__, ct . p );
379 STATUS ( STAT_GEEK, "%s - ct Rgn size = %zu\n", __func__, ct . s );
380 assert ( ( ct . s % AES_BLOCK_BYTES ) == 0 );
381
382 /* initialize message digest for SHA-256 HMAC */
383 STATUS ( STAT_PRG, "%s - initializing MD context\n", __func__ );
384 rc = EncryptStuffAdvance ( & s, es_md );
385 if ( rc != 0 )
386 break;
387 STATUS ( STAT_PRG, "%s - setting up MD context for SHA-256\n", __func__ );
388 rc = CALL_MBEDTLS ( mbedtls_md_setup, ( & s . md,
389 vdb_mbedtls_md_info_from_type ( MBEDTLS_MD_SHA256 ), true ) );
390 if ( rc != 0 )
391 break;
392
393 /* temporarily generate a derived HMAC key in "digest"
394 initialy, it will have its lower 16 bytes taken from iv,
395 and its upper 16 bytes zeroed.
396
397 do this NOW because we're about to destroy "iv"
398 */
399 STATUS ( STAT_GEEK, "%s - capturing initial HMAC key material from iv\n", __func__ );
400 RgnCopy ( RgnFill ( & digest, 0 ), RgnInit ( & rgn2, iv, sizeof iv ) );
401
402 /* initialize the AES context */
403 STATUS ( STAT_PRG, "%s - initializing AES context\n", __func__ );
404 rc = EncryptStuffAdvance ( & s, es_aes );
405 if ( rc != 0 )
406 break;
407
408 /* bind the secret key to the context
409 this key is still needed for later...
410 */
411 STATUS ( STAT_PRG, "%s - binding key to AES context\n", __func__ );
412 rc = CALL_MBEDTLS ( mbedtls_aes_setkey_enc, ( & s . aes, s . sk, AES_KEY_BITS ) );
413 if ( rc != 0 )
414 break;
415
416 /* encrypt as many full blocks as possible */
417 STATUS ( STAT_PRG, "%s - AES-encrypting whole blocks of plaintext in CBC mode\n", __func__ );
418 rc = CALL_MBEDTLS ( mbedtls_aes_crypt_cbc,
419 ( & s . aes, MBEDTLS_AES_ENCRYPT,
420 aes_block_trunc ( pt . s ),
421 iv, pt . p, ct . p )
422 );
423 if ( rc != 0 )
424 break;
425
426 /* in the very likely case that the input
427 was not a perfect multiple of block size */
428 if ( ( pt . s & ( AES_BLOCK_BYTES - 1 ) ) != 0 )
429 {
430 Rgn odd;
431 unsigned char last [ AES_BLOCK_BYTES ];
432
433 /* capture odd tail block of plaintext */
434 STATUS ( STAT_GEEK, "%s - capturing last partial block of pt Rgn\n", __func__ );
435 odd = RgnSubRgn ( & pt, aes_block_trunc ( pt . s ) );
436
437 /* copy and zero-pad into a full block */
438 STATUS ( STAT_GEEK, "%s - padding partial to whole block\n", __func__ );
439 RgnCopy ( RgnFill ( RgnInit ( & rgn, last, sizeof last ), 0 ), & odd );
440
441 /* get the last block of ct as destination */
442 STATUS ( STAT_GEEK, "%s - capturing last block of ct Rgn\n", __func__ );
443 rgn = RgnSubRgn ( & ct, ct . s - AES_BLOCK_BYTES );
444 assert ( rgn . s == sizeof last );
445
446 /* encrypt the last block */
447 STATUS ( STAT_PRG, "%s - AES-encrypting last partial block of plaintext in CBC mode\n", __func__ );
448 rc = CALL_MBEDTLS ( mbedtls_aes_crypt_cbc,
449 ( & s . aes, MBEDTLS_AES_ENCRYPT,
450 rgn . s, iv, last, rgn . p )
451 );
452 if ( rc != 0 )
453 break;
454 }
455
456 /* now convert digest into an HMAC key derived from iv and sk */
457 STATUS ( STAT_GEEK, "%s - deriving HMAC key from iv and AES key\n", __func__ );
458 for ( i = 0; i < 8 * 1024; ++ i )
459 {
460 vdb_mbedtls_md_starts ( & s . md );
461 vdb_mbedtls_md_update ( & s . md, digest . p, digest . s );
462 vdb_mbedtls_md_update ( & s . md, s . sk, sizeof s . sk );
463 vdb_mbedtls_md_finish ( & s . md, digest . p );
464 }
465
466 /* at this point, the digest has sensitive information */
467 STATUS ( STAT_GEEK, "%s - priming MD for SHA-256-HMAC\n", __func__ );
468 rc = CALL_MBEDTLS ( mbedtls_md_hmac_starts, ( & s . md,
469 digest . p, digest . s ) );
470 if ( rc != 0 )
471 break;
472
473 /* hash iv + ciphertext */
474 STATUS ( STAT_PRG, "%s - hashing iv + ciphertext\n", __func__ );
475 rc = CALL_MBEDTLS ( mbedtls_md_hmac_update, ( & s . md, ob . p, ob . s ) );
476 if ( rc != 0 )
477 break;
478
479 /* retrieve the HMAC digest, which is no longer sensitive */
480 STATUS ( STAT_GEEK, "%s - capturing HMAC digest into output buffer\n", __func__ );
481 rc = CALL_MBEDTLS ( mbedtls_md_hmac_finish, ( & s . md, digest . p ) );
482
483 } while ( false );
484
485 EncryptStuffWhack ( & s );
486 }
487
488 /* ANY sort of an error means whack the output */
489 if ( rc != 0 )
490 KDataBufferWipeNWhack ( out );
491
492 return rc;
493 }
494
495 typedef struct DecryptStuff DecryptStuff;
496 struct DecryptStuff
497 {
498 mbedtls_entropy_context entropy;
499 mbedtls_ctr_drbg_context ctr_drbg;
500 mbedtls_pk_context pdk;
501 mbedtls_md_context_t md;
502 mbedtls_aes_context aes;
503 uint32_t state;
504 unsigned char sk [ AES_KEY_BITS / 8 ];
505 unsigned char digest [ SHA_256_BITS / 8 ];
506 };
507
508 enum
509 {
510 ds_nada = 0,
511
512 ds_entropy,
513 ds_ctr_drbg,
514 ds_pdk,
515 ds_aes_key,
516 ds_md,
517 ds_aes,
518
519 ds_invalid,
520 ds_last_valid = ds_invalid - 1
521 };
522
523 static
DecryptStuffInit(DecryptStuff * s)524 void DecryptStuffInit ( DecryptStuff * s )
525 {
526 s -> state = ds_nada;
527 }
528
529 static
DecryptStuffWhack(DecryptStuff * s)530 void DecryptStuffWhack ( DecryptStuff * s )
531 {
532 switch ( s -> state )
533 {
534 case ds_aes:
535 vdb_mbedtls_aes_free ( & s -> aes );
536 case ds_md:
537 memset ( s -> digest, 0, sizeof s -> digest );
538 vdb_mbedtls_md_free ( & s -> md );
539 case ds_aes_key:
540 memset ( s -> sk, 0, sizeof s -> sk );
541 case ds_pdk:
542 vdb_mbedtls_pk_free ( & s -> pdk );
543 case ds_ctr_drbg:
544 vdb_mbedtls_ctr_drbg_free ( & s -> ctr_drbg );
545 case ds_entropy:
546 vdb_mbedtls_entropy_free ( & s -> entropy );
547 break;
548 }
549 }
550
551 static
DecryptStuffAdvance(DecryptStuff * s,uint32_t state)552 rc_t DecryptStuffAdvance ( DecryptStuff * s, uint32_t state )
553 {
554 rc_t rc = 0;
555
556 STATUS ( STAT_GEEK, "%s - advancing from state %u to %u\n", __func__, s -> state, state );
557
558 if ( state > ds_last_valid )
559 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcParam, rcInvalid );
560 if ( state != s -> state + 1 )
561 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcParam, rcInvalid );
562
563 switch ( state )
564 {
565 case ds_entropy:
566 vdb_mbedtls_entropy_init ( & s -> entropy );
567 break;
568 case ds_ctr_drbg:
569 vdb_mbedtls_ctr_drbg_init ( & s -> ctr_drbg );
570 break;
571 case ds_pdk:
572 vdb_mbedtls_pk_init ( & s -> pdk );
573 break;
574 case ds_aes_key:
575 break;
576 case ds_md:
577 vdb_mbedtls_md_init ( & s -> md );
578 break;
579 case ds_aes:
580 vdb_mbedtls_aes_init ( & s -> aes );
581 break;
582 }
583
584 if ( rc == 0 )
585 s -> state = state;
586
587 return rc;
588 }
589
590 static
RsaAesHmacDecryptInt(KDataBuffer * out,const void * in,size_t in_bytes,const char * zpdk,const char * zpwd)591 rc_t RsaAesHmacDecryptInt ( KDataBuffer * out,
592 const void * in, size_t in_bytes,
593 const char * zpdk, const char * zpwd )
594 {
595 /* initialized, empty byte buffer */
596 rc_t rc = KDataBufferMakeBytes ( out, 0 );
597 if ( rc == 0 )
598 {
599 DecryptStuff s;
600 DecryptStuffInit ( & s );
601
602 do
603 {
604 uint32_t i;
605 size_t sk_size;
606 Rgn ib, esk, hmac, ct, pt, rgn, rgn2;
607 unsigned char iv [ AES_BLOCK_BYTES ];
608 const char * pers = "krypty the AES decrypting bear";
609
610 /* capture input as a Rgn, even casting away const... */
611 STATUS ( STAT_GEEK, "%s - capturing input as Rgn\n", __func__ );
612 RgnInit ( & ib, ( void * ) in, in_bytes );
613
614 /* initialize entropy and prng */
615 STATUS ( STAT_PRG, "%s - initializing entropy\n", __func__ );
616 rc = DecryptStuffAdvance ( & s, ds_entropy );
617 if ( rc != 0 )
618 break;
619 STATUS ( STAT_PRG, "%s - initializing PRNG\n", __func__ );
620 rc = DecryptStuffAdvance ( & s, ds_ctr_drbg );
621 if ( rc != 0 )
622 break;
623
624 /* set random seed and entropy function,
625 flavor oddly with some constant data... */
626 STATUS ( STAT_PRG, "%s - seeding PRNG\n", __func__ );
627 rc = CALL_MBEDTLS ( mbedtls_ctr_drbg_seed, ( & s . ctr_drbg,
628 vdb_mbedtls_entropy_func, & s . entropy,
629 ( const unsigned char * ) pers, strlen ( pers )
630 ) );
631 if ( rc != 0 )
632 break;
633
634 /* initialize the private decryption key */
635 STATUS ( STAT_PRG, "%s - initializing RSA context\n", __func__ );
636 rc = DecryptStuffAdvance ( & s, ds_pdk );
637 if ( rc != 0 )
638 break;
639
640 /* parse the PEM keyfile */
641 STATUS ( STAT_PRG, "%s - parsing PDK from file\n", __func__ );
642 rc = CALL_MBEDTLS ( mbedtls_pk_parse_keyfile, ( & s . pdk, zpdk, zpwd ) );
643 if ( rc != 0 )
644 break;
645
646 /* capture encrypted symmetric key */
647 STATUS ( STAT_GEEK, "%s - capturing esk from input\n", __func__ );
648 esk = RgnSubRgn2 ( & ib, 0, vdb_mbedtls_pk_get_len ( & s . pdk ) );
649 STATUS ( STAT_GEEK, "%s - esk Rgn ptr = %p\n", __func__, esk . p );
650 STATUS ( STAT_GEEK, "%s - esk Rgn size = %zu\n", __func__, esk . s );
651 if ( esk . s != vdb_mbedtls_pk_get_len ( & s . pdk ) )
652 {
653 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcData, rcInsufficient );
654 break;
655 }
656
657 /* this is a noop - manually initialized next */
658 rc = DecryptStuffAdvance ( & s, ds_aes_key );
659 if ( rc != 0 )
660 break;
661
662 /* decrypt symmetric key */
663 STATUS ( STAT_PRG, "%s - decrypting AES key with RSA key\n", __func__ );
664 rc = CALL_MBEDTLS ( mbedtls_pk_decrypt, ( & s .pdk,
665 esk . p, esk . s, s . sk, & sk_size, sizeof s . sk,
666 vdb_mbedtls_ctr_drbg_random, & s . ctr_drbg ) );
667 if ( rc != 0 )
668 break;
669 STATUS ( STAT_GEEK, "%s - AES key size = %zu\n", __func__, sk_size );
670 if ( sk_size != sizeof s . sk )
671 {
672 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcData, rcCorrupt );
673 break;
674 }
675
676 /* skip over encrypted key */
677 STATUS ( STAT_GEEK, "%s - redefining input Rgn to skip over esk\n", __func__ );
678 ib = RgnSubRgn ( & ib, esk . s );
679 STATUS ( STAT_GEEK, "%s - input Rgn ptr = %p\n", __func__, ib . p );
680 STATUS ( STAT_GEEK, "%s - input Rgn size = %zu\n", __func__, ib . s );
681 if ( ib . s <= ( sizeof iv + ( SHA_256_BITS / 8 ) ) )
682 {
683 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcData, rcInsufficient );
684 break;
685 }
686
687 /* we can now know the size needed for the output buffer */
688 STATUS ( STAT_PRG, "%s - setting output buffer size\n", __func__ );
689 rc = KDataBufferResize ( out,
690 ib . s - /* input buffer size */
691 sizeof iv - /* initialization vector */
692 ( SHA_256_BITS / 8 ) /* SHA-256-HMAC */
693 );
694 if ( rc != 0 )
695 break;
696 STATUS ( STAT_GEEK, "%s - size set to %lu bytes:\n", __func__, out -> elem_count );
697 STATUS ( STAT_GEEK, "%s - remaining size = %zu\n", __func__, ib . s );
698 STATUS ( STAT_GEEK, "%s - iv size = %zu\n", __func__, sizeof iv );
699 STATUS ( STAT_GEEK, "%s - hmac size = %zu\n", __func__, ( SHA_256_BITS / 8 ) );
700
701 /* capture output region */
702 STATUS ( STAT_GEEK, "%s - capturing output buffer as Rgn\n", __func__ );
703 pt = KDataBufferMakeRgn ( out );
704 STATUS ( STAT_GEEK, "%s - output Rgn ptr = %p\n", __func__, pt . p );
705 STATUS ( STAT_GEEK, "%s - output Rgn size = %zu\n", __func__, pt . s );
706
707 /* capture input regions */
708 STATUS ( STAT_GEEK, "%s - capturing HMAC as Rgn\n", __func__ );
709 hmac = RgnSubRgn ( & ib, ib . s - ( SHA_256_BITS / 8 ) );
710 STATUS ( STAT_GEEK, "%s - hmac Rgn ptr = %p\n", __func__, hmac . p );
711 STATUS ( STAT_GEEK, "%s - hmac Rgn size = %zu\n", __func__, hmac . s );
712 STATUS ( STAT_GEEK, "%s - redefining input Rgn to remove HMAC\n", __func__ );
713 ib = RgnSubRgn2 ( & ib, 0, ib . s - hmac . s );
714 STATUS ( STAT_GEEK, "%s - input Rgn ptr = %p\n", __func__, ib . p );
715 STATUS ( STAT_GEEK, "%s - input Rgn size = %zu\n", __func__, ib . s );
716 STATUS ( STAT_GEEK, "%s - capturing ct Rgn\n", __func__ );
717 ct = RgnSubRgn ( & ib, sizeof iv );
718 STATUS ( STAT_GEEK, "%s - ct Rgn ptr = %p\n", __func__, ct . p );
719 STATUS ( STAT_GEEK, "%s - ct Rgn size = %zu\n", __func__, ct . s );
720
721 /* copy out the iv */
722 STATUS ( STAT_GEEK, "%s - extracting IV\n", __func__ );
723 RgnCopy ( RgnInit ( & rgn2, iv, sizeof iv ), & ib );
724 if ( rgn2 . s != sizeof iv )
725 {
726 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcData, rcInsufficient );
727 break;
728 }
729
730 /* adjust output */
731 STATUS ( STAT_PRG, "%s - adjusting output buffer to remove padding\n", __func__ );
732 pt . s -= iv [ sizeof iv - 1 ] & 0xF;
733 STATUS ( STAT_GEEK, "%s - output Rgn ptr = %p\n", __func__, pt . p );
734 STATUS ( STAT_GEEK, "%s - output Rgn size = %zu\n", __func__, pt . s );
735
736 /* initialize message digest */
737 STATUS ( STAT_PRG, "%s - initializing MD context\n", __func__ );
738 rc = DecryptStuffAdvance ( & s, ds_md );
739 if ( rc != 0 )
740 break;
741 STATUS ( STAT_PRG, "%s - setting up MD context for SHA-256\n", __func__ );
742 rc = CALL_MBEDTLS ( mbedtls_md_setup, ( & s . md,
743 vdb_mbedtls_md_info_from_type ( MBEDTLS_MD_SHA256 ), true ) );
744 if ( rc != 0 )
745 break;
746
747 /* build an HMAC key */
748 STATUS ( STAT_GEEK, "%s - capturing initial HMAC key material from iv\n", __func__ );
749 RgnCopy (
750 RgnFill ( RgnInit ( & rgn, s . digest, sizeof s . digest ), 0 ),
751 RgnInit ( & rgn2, iv, sizeof iv )
752 );
753
754 /* now convert digest into an HMAC key derived from iv and sk */
755 STATUS ( STAT_GEEK, "%s - deriving HMAC key from iv and AES key\n", __func__ );
756 for ( i = 0; i < 8 * 1024; ++ i )
757 {
758 vdb_mbedtls_md_starts ( & s . md );
759 vdb_mbedtls_md_update ( & s . md, s . digest, sizeof s . digest );
760 vdb_mbedtls_md_update ( & s . md, s . sk, sizeof s . sk );
761 vdb_mbedtls_md_finish ( & s . md, s . digest );
762 }
763
764 /* at this point, the digest has sensitive information */
765 STATUS ( STAT_GEEK, "%s - priming MD for SHA-256-HMAC\n", __func__ );
766 rc = CALL_MBEDTLS ( mbedtls_md_hmac_starts, ( & s . md,
767 s . digest, sizeof s . digest ) );
768 if ( rc != 0 )
769 break;
770
771 /* hash iv + ciphertext */
772 STATUS ( STAT_PRG, "%s - hashing iv + ciphertext\n", __func__ );
773 rc = CALL_MBEDTLS ( mbedtls_md_hmac_update, ( & s . md, ib . p, ib . s ) );
774 if ( rc != 0 )
775 break;
776
777 /* retrieve the HMAC digest, which is no longer sensitive */
778 STATUS ( STAT_GEEK, "%s - retrieving HMAC digest\n", __func__ );
779 rc = CALL_MBEDTLS ( mbedtls_md_hmac_finish, ( & s . md, s . digest ) );
780
781 /* the digest must compare */
782 STATUS ( STAT_PRG, "%s - comparing stored and calculated HMAC\n", __func__ );
783 if ( ! RgnEqual ( & hmac, RgnInit ( & rgn, s . digest, sizeof s . digest ) ) )
784 {
785 STATUS ( STAT_QA, "%s - HMAC comparison failed\n", __func__ );
786 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcData, rcCorrupt );
787 break;
788 }
789
790 /* just about there */
791 STATUS ( STAT_PRG, "%s - initializing AES context\n", __func__ );
792 rc = DecryptStuffAdvance ( & s, ds_aes );
793 if ( rc != 0 )
794 break;
795 STATUS ( STAT_PRG, "%s - binding key to AES context\n", __func__ );
796 rc = CALL_MBEDTLS ( mbedtls_aes_setkey_dec, ( & s . aes, s . sk, AES_KEY_BITS ) );
797 if ( rc != 0 )
798 break;
799
800 /* all buffers are multiples of whole blocks - do it in one pass */
801 STATUS ( STAT_PRG, "%s - AES-decrypting whole blocks of plaintext in CBC mode\n", __func__ );
802 rc = CALL_MBEDTLS ( mbedtls_aes_crypt_cbc, ( & s . aes, MBEDTLS_AES_DECRYPT,
803 ct . s, iv, ct . p, pt . p ) );
804 if ( rc != 0 )
805 break;
806
807 /* now remove the padding */
808 STATUS ( STAT_GEEK, "%s - readjusting output buffer size to final\n", __func__ );
809 STATUS ( STAT_GEEK, "%s - prior size = %lu\n", __func__, out -> elem_count );
810 STATUS ( STAT_GEEK, "%s - requested size = %zu\n", __func__, pt . s );
811 rc = KDataBufferWipeResize ( out, pt . s );
812 STATUS ( STAT_GEEK, "%s - after size = %lu\n", __func__, out -> elem_count );
813 }
814 while ( false );
815
816 DecryptStuffWhack ( & s );
817 }
818
819 /* ANY sort of an error means whack the output */
820 if ( rc != 0 )
821 KDataBufferWipeNWhack ( out );
822
823 return rc;
824 }
825
826 /* RsaAesHmacEncrypt
827 * encrypt a block of data using a random AES key, which is itself
828 * encrypted using an RSA key, and generate a SHA-256 HMAC into
829 * the provided binary output buffer.
830 *
831 * the output will be in pure binary form, lacking a header and
832 * any text-encoding such as base64 that might be needed for
833 * transmission.
834 *
835 * "out" [ IN/OUT ] - pointer to a ZEROED KDataBuffer
836 * that will receive encrypted result. must be zeroed with
837 * "memset ( & out, 0, sizeof out );" or equivalent.
838 *
839 * "in" [ IN ] and "in_bytes" [ IN ] - block of data to be encrypted
840 *
841 * "zpek" [ IN ] - NUL-terminated RSA public encryption key
842 * in PEM format. MUST be NUL-terminated.
843 */
RsaAesHmacEncrypt(KDataBuffer * out,const void * in,size_t in_bytes,const char * zpek)844 LIB_EXPORT rc_t CC RsaAesHmacEncrypt ( KDataBuffer * out,
845 const void * in, size_t in_bytes, const char * zpek )
846 {
847 rc_t rc;
848
849 /* check output parameter first */
850 if ( out == NULL )
851 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcBuffer, rcNull );
852 else
853 {
854 /* check input parameters */
855 if ( in_bytes == 0 )
856 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcBlob, rcNull );
857 else if ( in == NULL )
858 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcBlob, rcEmpty );
859 else if ( zpek == NULL )
860 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcEncryptionKey, rcNull );
861 else if ( zpek [ 0 ] == 0 )
862 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcEncryptionKey, rcEmpty );
863 else
864 {
865 /* check for ZEROED output buffer */
866 size_t i, sum;
867 for ( i = sum = 0; i < sizeof * out; ++ i )
868 sum += ( ( const unsigned char * ) out ) [ i ];
869 if ( sum != 0 )
870 rc = RC ( rcKrypto, rcBlob, rcEncrypting, rcBuffer, rcInvalid );
871 else
872 {
873 /* perform operation */
874 rc = RsaAesHmacEncryptInt ( out, in, in_bytes, zpek );
875 }
876 }
877 }
878
879 return rc;
880 }
881
882
883 /* RsaAesHmacDecrypt
884 * decrypt a block of enciphered data produced by RsaAesHmacEncrypt().
885 *
886 * "out" [ IN/OUT ] - pointer to a ZEROED KDataBuffer
887 * that will receive decrypted result. must be zeroed with
888 * "memset ( & out, 0, sizeof out );" or equivalent.
889 *
890 * "in" [ IN ] and "in_bytes" [ IN ] - block of enciphered data to be decrypted
891 *
892 * "zpdk" [ IN ] - a NUL-terminated FILE PATH to an
893 * RSA private decryption key in PEM format.
894 *
895 * "zpwd" [ IN/OUT ] and "zpwd_size" [ IN ] - a mutable buffer containing
896 * a NUL-terminated password string used to decrypt the file designated by
897 * "zpdk". "zpwd_size" should be the total size of the BUFFER, not the
898 * size of the password itself. The buffer will be wiped after first use
899 * regardless of success or failure.
900 */
RsaAesHmacDecrypt(KDataBuffer * out,const void * in,size_t in_bytes,const char * zpdk,char * zpwd,size_t zpw_size)901 LIB_EXPORT rc_t CC RsaAesHmacDecrypt ( KDataBuffer * out,
902 const void * in, size_t in_bytes, const char * zpdk,
903 char * zpwd, size_t zpw_size )
904 {
905 rc_t rc;
906
907 /* check output parameter first */
908 if ( out == NULL )
909 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcBuffer, rcNull );
910 else
911 {
912 /* check input parameters */
913 if ( in_bytes == 0 )
914 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcBlob, rcNull );
915 else if ( in == NULL )
916 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcBlob, rcEmpty );
917 else if ( zpdk == NULL )
918 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcPath, rcNull );
919 else if ( zpdk [ 0 ] == 0 )
920 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcPath, rcEmpty );
921 else if ( zpwd == NULL )
922 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcParam, rcNull );
923 else if ( zpw_size == 0 || zpwd [ 0 ] == 0 )
924 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcParam, rcEmpty );
925 else
926 {
927 /* check for ZEROED output buffer */
928 size_t i, sum;
929 for ( i = sum = 0; i < sizeof * out; ++ i )
930 sum += ( ( const unsigned char * ) out ) [ i ];
931 if ( sum != 0 )
932 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcBuffer, rcInvalid );
933 else
934 {
935 /* ensure the password is NULL-terminated within bounds */
936 for ( i = 0; i < zpw_size; ++ i )
937 {
938 if ( zpwd [ i ] == 0 )
939 break;
940 }
941 if ( i == zpw_size )
942 rc = RC ( rcKrypto, rcBlob, rcDecrypting, rcParam, rcInvalid );
943 else
944 {
945 /* perform operation */
946 rc = RsaAesHmacDecryptInt ( out, in, in_bytes, zpdk, zpwd );
947 }
948 }
949 }
950 }
951
952 /* always wipe password */
953 if ( zpwd != NULL && zpw_size != 0 )
954 {
955 /* compiler should not be in a position to optimize this away... */
956 STATUS ( STAT_QA, "%s - wiping password buffer\n", __func__ );
957 memset ( zpwd, ' ', zpw_size );
958 zpwd [ 0 ] = 0;
959 }
960
961 return rc;
962 }
963
964 /* EncryptForNCBI
965 * encrypts a block using a public RSA encryption key belonging to NCBI
966 */
967 static const char NCBI_PEK [] =
968 "-----BEGIN PUBLIC KEY-----\r\n"
969 "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArkP4ghANgXpW7UDpw+rI\r\n"
970 "ttNTJV447GsCom6MDr4CxWbS1MEPwPrvJIao/otKjMJlZv+opEDNfuu+mW5Of/iM\r\n"
971 "2gVDrgMKG8OP34HqJ9dbOfZtsaM3pJNN60TTPJbWZ5Wqd26RDj18gVY4NWj6mVGs\r\n"
972 "Z8aY4bXwg4LJVHF/6E+bMEIZcvw6wVro1AcT4mke1eqySDRYD7MqBx/GIcrI/921\r\n"
973 "siJDAfXQLW25CqVBFF2jqY2+sLcKX4ZOY0RdJ9sNNa/c2oZYuacDp9kett+UtOmH\r\n"
974 "XV99VcqeX/nIBUlAn0yAfsNnRw7NSBv1ydZxRdayLvhm5px+DQ98yRP1MrZEgmdB\r\n"
975 "SwIDAQAB\r\n"
976 "-----END PUBLIC KEY-----\r\n";
977
EncryptForNCBI(struct KDataBuffer * out,const void * in,size_t in_bytes)978 LIB_EXPORT rc_t CC EncryptForNCBI ( struct KDataBuffer * out,
979 const void * in, size_t in_bytes )
980 {
981 return RsaAesHmacEncrypt ( out, in, in_bytes, NCBI_PEK );
982 }
983