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