summaryrefslogtreecommitdiff
path: root/plugins/MirOTR/Libgcrypt/random/random-fips.c
blob: 2667e71fd87d8c45600d5489ddf45dcac73d7dea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
/* random-fips.c - FIPS style random number generator
 * Copyright (C) 2008  Free Software Foundation, Inc.
 *
 * This file is part of Libgcrypt.
 *
 * Libgcrypt is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * Libgcrypt is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

/*
   The core of this deterministic random number generator is
   implemented according to the document "NIST-Recommended Random
   Number Generator Based on ANSI X9.31 Appendix A.2.4 Using the 3-Key
   Triple DES and AES Algorithms" (2005-01-31).  This implementation
   uses the AES variant.

   There are 3 random context which map to the different levels of
   random quality:

   Generator                Seed and Key        Kernel entropy (init/reseed)
   ------------------------------------------------------------
   GCRY_VERY_STRONG_RANDOM  /dev/random         256/128 bits
   GCRY_STRONG_RANDOM       /dev/random         256/128 bits
   gcry_create_nonce        GCRY_STRONG_RANDOM  n/a

   All random generators return their data in 128 bit blocks.  If the
   caller requested less bits, the extra bits are not used.  The key
   for each generator is only set once at the first time a generator
   is used.  The seed value is set with the key and again after 1000
   (SEED_TTL) output blocks; the re-seeding is disabled in test mode.

   The GCRY_VERY_STRONG_RANDOM and GCRY_STRONG_RANDOM generators are
   keyed and seeded from the /dev/random device.  Thus these
   generators may block until the kernel has collected enough entropy.

   The gcry_create_nonce generator is keyed and seeded from the
   GCRY_STRONG_RANDOM generator.  It may also block if the
   GCRY_STRONG_RANDOM generator has not yet been used before and thus
   gets initialized on the first use by gcry_create_nonce.  This
   special treatment is justified by the weaker requirements for a
   nonce generator and to save precious kernel entropy for use by the
   real random generators.

 */

#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_GETTIMEOFDAY
#include <sys/time.h>
#endif

#include "g10lib.h"
#include "random.h"
#include "rand-internal.h"
#include "ath.h"

/* This is the lock we use to serialize access to this RNG.  The extra
   integer variable is only used to check the locking state; that is,
   it is not meant to be thread-safe but merely as a failsafe feature
   to assert proper locking.  */
static ath_mutex_t fips_rng_lock = ATH_MUTEX_INITIALIZER;
static int fips_rng_is_locked;


/* The required size for the temporary buffer of the x931_aes_driver
   function and the buffer itself which will be allocated in secure
   memory.  This needs to be global variable for proper initialization
   and to allow shutting down the RNG without leaking memory.  May
   only be used while holding the FIPS_RNG_LOCK.

   This variable is also used to avoid duplicate initialization.  */
#define TEMPVALUE_FOR_X931_AES_DRIVER_SIZE 48
static unsigned char *tempvalue_for_x931_aes_driver;


/* After having retrieved this number of blocks from the RNG, we want
   to do a reseeding.  */
#define SEED_TTL 1000


/* The length of the key we use:  16 bytes (128 bit) for AES128.  */
#define X931_AES_KEYLEN  16
/* A global buffer used to communicate between the x931_generate_key
   and x931_generate_seed functions and the entropy_collect_cb
   function.  It may only be used by these functions. */
static unsigned char *entropy_collect_buffer;  /* Buffer.  */
static size_t entropy_collect_buffer_len;      /* Used length.  */
static size_t entropy_collect_buffer_size;     /* Allocated length.  */


/* This random context type is used to track properties of one random
   generator. Thee context are usually allocated in secure memory so
   that the seed value is well protected.  There are a couble of guard
   fields to help detecting applications accidently overwriting parts
   of the memory. */
struct rng_context
{
  unsigned char guard_0[1];

  /* The handle of the cipher used by the RNG.  If this one is not
     NULL a cipher handle along with a random key has been
     established.  */
  gcry_cipher_hd_t cipher_hd;

  /* If this flag is true, the SEED_V buffer below carries a valid
     seed.  */
  int is_seeded:1;

  /* The very first block generated is used to compare the result
     against the last result.  This flag indicates that such a block
     is available.  */
  int compare_value_valid:1;

  /* A counter used to trigger re-seeding.  */
  unsigned int use_counter;

  unsigned char guard_1[1];

  /* The buffer containing the seed value V.  */
  unsigned char seed_V[16];

  unsigned char guard_2[1];

  /* The last result from the x931_aes fucntion.  Only valid if
     compare_value_valid is set.  */
  unsigned char compare_value[16];

  unsigned char guard_3[1];

  /* The external test may want to suppress the duplicate bock check.
     This is done if the this flag is set.  */
  unsigned char test_no_dup_check;
  /* To implement a KAT we need to provide a know DT value.  To
     accomplish this the x931_get_dt function checks whether this
     field is not NULL and then uses the 16 bytes at this address for
     the DT value.  However the last 4 bytes are replaced by the
     value of field TEST_DT_COUNTER which will be incremented after
     each invocation of x931_get_dt. We use a pointer and not a buffer
     because there is no need to put this value into secure memory.  */
  const unsigned char *test_dt_ptr;
  u32 test_dt_counter;

  /* We need to keep track of the process which did the initialization
     so that we can detect a fork.  The volatile modifier is required
     so that the compiler does not optimize it away in case the getpid
     function is badly attributed.  */ 
  pid_t key_init_pid;
  pid_t seed_init_pid;
};
typedef struct rng_context *rng_context_t;


/* The random context used for the nonce generator.  May only be used
   while holding the FIPS_RNG_LOCK.  */
static rng_context_t nonce_context;
/* The random context used for the standard random generator.  May
   only be used while holding the FIPS_RNG_LOCK.  */
static rng_context_t std_rng_context;
/* The random context used for the very strong random generator.  May
   only be used while holding the FIPS_RNG_LOCK.  */
static rng_context_t strong_rng_context;


/* --- Local prototypes ---  */
static void x931_reseed (rng_context_t rng_ctx);
static void get_random (void *buffer, size_t length, rng_context_t rng_ctx);




/* --- Functions  --- */

/* Basic initialization is required to initialize mutexes and
   do a few checks on the implementation.  */
static void
basic_initialization (void)
{
  static int initialized;
  int my_errno;

  if (!initialized)
    return;
  initialized = 1;

  my_errno = ath_mutex_init (&fips_rng_lock);
  if (my_errno)
    log_fatal ("failed to create the RNG lock: %s\n", strerror (my_errno));
  fips_rng_is_locked = 0;
      
  /* Make sure that we are still using the values we have
     traditionally used for the random levels.  */
  gcry_assert (GCRY_WEAK_RANDOM == 0 
               && GCRY_STRONG_RANDOM == 1
               && GCRY_VERY_STRONG_RANDOM == 2);

}


/* Acquire the fips_rng_lock.  */
static void
lock_rng (void)
{
  int my_errno;

  my_errno = ath_mutex_lock (&fips_rng_lock);
  if (my_errno)
    log_fatal ("failed to acquire the RNG lock: %s\n", strerror (my_errno));
  fips_rng_is_locked = 1;
}


/* Release the fips_rng_lock.  */
static void
unlock_rng (void)
{
  int my_errno;

  fips_rng_is_locked = 0;
  my_errno = ath_mutex_unlock (&fips_rng_lock);
  if (my_errno)
    log_fatal ("failed to release the RNG lock: %s\n", strerror (my_errno));
}

static void
setup_guards (rng_context_t rng_ctx)
{
  /* Set the guards to some arbitrary values.  */
  rng_ctx->guard_0[0] = 17;
  rng_ctx->guard_1[0] = 42;
  rng_ctx->guard_2[0] = 137;
  rng_ctx->guard_3[0] = 252;
}

static void
check_guards (rng_context_t rng_ctx)
{
  if ( rng_ctx->guard_0[0] != 17
       || rng_ctx->guard_1[0] != 42
       || rng_ctx->guard_2[0] != 137
       || rng_ctx->guard_3[0] != 252 )
    log_fatal ("memory corruption detected in RNG context %p\n", rng_ctx);
}


/* Get the DT vector for use with the core PRNG function.  Buffer
   needs to be provided by the caller with a size of at least LENGTH
   bytes. RNG_CTX needs to be passed to allow for a KAT.  The 16 byte
   timestamp we construct is made up the real time and three counters:

   Buffer:       00112233445566778899AABBCCDDEEFF
                 !--+---!!-+-!!+!!--+---!!--+---!     
   seconds ---------/      |   |    |       |
   microseconds -----------/   |    |       |
   counter2 -------------------/    |       |
   counter1 ------------------------/       |
   counter0 --------------------------------/

   Counter 2 is just 12 bits wide and used to track fractions of
   milliseconds whereas counters 1 and 0 are combined to a free
   running 64 bit counter.  */
static void 
x931_get_dt (unsigned char *buffer, size_t length, rng_context_t rng_ctx)
{
  gcry_assert (length == 16); /* This length is required for use with AES.  */
  gcry_assert (fips_rng_is_locked);

  /* If the random context indicates that a test DT should be used,
     take the DT value from the context.  For safety reasons we do
     this only if the context is not one of the regular contexts.  */
  if (rng_ctx->test_dt_ptr 
      && rng_ctx != nonce_context
      && rng_ctx != std_rng_context
      && rng_ctx != strong_rng_context)
    {
      memcpy (buffer, rng_ctx->test_dt_ptr, 16);
      buffer[12] = (rng_ctx->test_dt_counter >> 24);
      buffer[13] = (rng_ctx->test_dt_counter >> 16);
      buffer[14] = (rng_ctx->test_dt_counter >> 8);
      buffer[15] = rng_ctx->test_dt_counter;
      rng_ctx->test_dt_counter++;
      return;
    }


#if HAVE_GETTIMEOFDAY
  {
    static u32 last_sec, last_usec;
    static u32 counter1, counter0;
    static u16 counter2;
    
    unsigned int usec;
    struct timeval tv;

    if (!last_sec)
      {
        /* This is the very first time we are called: Set the counters
           to an not so easy predictable value to avoid always
           starting at 0.  Not really needed but it doesn't harm.  */
        counter1 = (u32)getpid ();
#ifndef HAVE_W32_SYSTEM
        counter0 = (u32)getppid ();
#endif
      }


    if (gettimeofday (&tv, NULL))
      log_fatal ("gettimeofday() failed: %s\n", strerror (errno));

    /* The microseconds part is always less than 1 millon (0x0f4240).
       Thus we don't care about the MSB and in addition shift it to
       the left by 4 bits.  */
    usec = tv.tv_usec;
    usec <<= 4;
    /* If we got the same time as by the last invocation, bump up
       counter2 and save the time for the next invocation.  */
    if (tv.tv_sec == last_sec && usec == last_usec)
      {
        counter2++;
        counter2 &= 0x0fff;
      }
    else
      {
        counter2 = 0;
        last_sec = tv.tv_sec;
        last_usec = usec;
      }
    /* Fill the buffer with the timestamp.  */
    buffer[0] = ((tv.tv_sec >> 24) & 0xff);
    buffer[1] = ((tv.tv_sec >> 16) & 0xff);
    buffer[2] = ((tv.tv_sec >> 8) & 0xff);
    buffer[3] = (tv.tv_sec & 0xff);
    buffer[4] = ((usec >> 16) & 0xff);
    buffer[5] = ((usec >> 8) & 0xff);
    buffer[6] = ((usec & 0xf0) | ((counter2 >> 8) & 0x0f));
    buffer[7] = (counter2 & 0xff);
    /* Add the free running counter.  */
    buffer[8]  = ((counter1 >> 24) & 0xff);
    buffer[9]  = ((counter1 >> 16) & 0xff);
    buffer[10] = ((counter1 >> 8) & 0xff); 
    buffer[11] = ((counter1) & 0xff);
    buffer[12] = ((counter0 >> 24) & 0xff);
    buffer[13] = ((counter0 >> 16) & 0xff);
    buffer[14] = ((counter0 >> 8) & 0xff); 
    buffer[15] = ((counter0) & 0xff);
    /* Bump up that counter.  */
    if (!++counter0)
      ++counter1;
  }
#else
  log_fatal ("gettimeofday() not available on this system\n");
#endif

  /* log_printhex ("x931_get_dt: ", buffer, 16); */
}


/* XOR the buffers A and B which are each of LENGTH bytes and store
   the result at R.  R needs to be provided by the caller with a size
   of at least LENGTH bytes.  */
static void
xor_buffer (unsigned char *r, 
            const unsigned char *a, const unsigned char *b, size_t length)
{
  for ( ; length; length--, a++, b++, r++)
    *r = (*a ^ *b);
}


/* Encrypt LENGTH bytes of INPUT to OUTPUT using KEY.  LENGTH
   needs to be 16. */
static void
encrypt_aes (gcry_cipher_hd_t key, 
             unsigned char *output, const unsigned char *input, size_t length)
{
  gpg_error_t err;

  gcry_assert (length == 16);

  err = gcry_cipher_encrypt (key, output, length, input, length);
  if (err)
    log_fatal ("AES encryption in RNG failed: %s\n", gcry_strerror (err));
}


/* The core ANSI X9.31, Appendix A.2.4 function using AES.  The caller
   needs to pass a 16 byte buffer for the result, the 16 byte
   datetime_DT value and the 16 byte seed value V.  The caller also
   needs to pass an appropriate KEY and make sure to pass a valid
   seed_V.  The caller also needs to provide two 16 bytes buffer for
   intermediate results, they may be reused by the caller later.

   On return the result is stored at RESULT_R and the SEED_V is
   updated.  May only be used while holding the lock.  */
static void
x931_aes (unsigned char result_R[16], 
          unsigned char datetime_DT[16], unsigned char seed_V[16],
          gcry_cipher_hd_t key,
          unsigned char intermediate_I[16], unsigned char temp_xor[16])
{
  /* Let ede*X(Y) represent the AES encryption of Y under the key *X.

     Let V be a 128-bit seed value which is also kept secret, and XOR
     be the exclusive-or operator. Let DT be a date/time vector which
     is updated on each iteration. I is a intermediate value. 

     I = ede*K(DT)  */
  encrypt_aes (key, intermediate_I, datetime_DT, 16);

  /* R = ede*K(I XOR V) */
  xor_buffer (temp_xor, intermediate_I, seed_V, 16);
  encrypt_aes (key, result_R, temp_xor, 16);

  /* V = ede*K(R XOR I).  */
  xor_buffer (temp_xor, result_R, intermediate_I, 16);
  encrypt_aes (key, seed_V, temp_xor, 16);

  /* Zero out temporary values.  */
  wipememory (intermediate_I, 16);
  wipememory (temp_xor, 16);
}


/* The high level driver to x931_aes.  This one does the required
   tests and calls the core function until the entire buffer has been
   filled.  OUTPUT is a caller provided buffer of LENGTH bytes to
   receive the random, RNG_CTX is the context of the RNG.  The context
   must be properly initialized.  Returns 0 on success. */
static int
x931_aes_driver (unsigned char *output, size_t length, rng_context_t rng_ctx)
{
  unsigned char datetime_DT[16];
  unsigned char *intermediate_I, *temp_buffer, *result_buffer;
  size_t nbytes;

  gcry_assert (fips_rng_is_locked);
  gcry_assert (rng_ctx->cipher_hd);
  gcry_assert (rng_ctx->is_seeded);

  gcry_assert (tempvalue_for_x931_aes_driver);
  gcry_assert (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE == 48);
  intermediate_I = tempvalue_for_x931_aes_driver;
  temp_buffer    = tempvalue_for_x931_aes_driver + 16;
  result_buffer  = tempvalue_for_x931_aes_driver + 32;

  while (length)
    {
      /* Unless we are running with a test context, we require a new
         seed after some time.  */
      if (!rng_ctx->test_dt_ptr && rng_ctx->use_counter > SEED_TTL)
        {
          x931_reseed (rng_ctx);
          rng_ctx->use_counter = 0;
        }

      /* Due to the design of the RNG, we always receive 16 bytes (128
         bit) of random even if we require less.  The extra bytes
         returned are not used.  Intheory we could save them for the
         next invocation, but that would make the control flow harder
         to read.  */
      nbytes = length < 16? length : 16;

      x931_get_dt (datetime_DT, 16, rng_ctx);
      x931_aes (result_buffer,
                datetime_DT, rng_ctx->seed_V, rng_ctx->cipher_hd,
                intermediate_I, temp_buffer);
      rng_ctx->use_counter++;

      if (rng_ctx->test_no_dup_check
          && rng_ctx->test_dt_ptr
          && rng_ctx != nonce_context
          && rng_ctx != std_rng_context
          && rng_ctx != strong_rng_context)
        {
          /* This is a test context which does not want the duplicate
             block check. */
        }
      else
        {
          /* Do a basic check on the output to avoid a stuck generator.  */
          if (!rng_ctx->compare_value_valid)
            {
              /* First time used, only save the result.  */
              memcpy (rng_ctx->compare_value, result_buffer, 16);
              rng_ctx->compare_value_valid = 1;
              continue;
            }
          if (!memcmp (rng_ctx->compare_value, result_buffer, 16))
            {
              /* Ooops, we received the same 128 bit block - that should
                 in theory never happen.  The FIPS requirement says that
                 we need to put ourself into the error state in such
                 case.  */
              fips_signal_error ("duplicate 128 bit block returned by RNG");
              return -1;
            }
          memcpy (rng_ctx->compare_value, result_buffer, 16);
        }
      
      /* Append to outbut.  */
      memcpy (output, result_buffer, nbytes);
      wipememory (result_buffer, 16);
      output += nbytes;
      length -= nbytes;
    }

  return 0;
}


/* Callback for x931_generate_key. Note that this callback uses the
   global ENTROPY_COLLECT_BUFFER which has been setup by get_entropy.
   ORIGIN is not used but required due to the design of entropy
   gathering module. */
static void
entropy_collect_cb (const void *buffer, size_t length,
                    enum random_origins origin)
{
  const unsigned char *p = buffer;

  (void)origin;

  gcry_assert (fips_rng_is_locked);
  gcry_assert (entropy_collect_buffer);

  /* Note that we need to protect against gatherers returning more
     than the requested bytes (e.g. rndw32).  */
  while (length-- && entropy_collect_buffer_len < entropy_collect_buffer_size)
    {
      entropy_collect_buffer[entropy_collect_buffer_len++] ^= *p++;
    }
}


/* Get NBYTES of entropy from the kernel device.  The callers needs to
   free the returned buffer.  The function either succeeds or
   terminates the process in case of a fatal error. */
static void *
get_entropy (size_t nbytes)
{
  void *result;
  int rc;

  gcry_assert (!entropy_collect_buffer);
  entropy_collect_buffer = gcry_xmalloc_secure (nbytes);
  entropy_collect_buffer_size = nbytes;
  entropy_collect_buffer_len = 0;

#if USE_RNDLINUX
  rc = _gcry_rndlinux_gather_random (entropy_collect_cb, 0,
                                     X931_AES_KEYLEN,
                                     GCRY_VERY_STRONG_RANDOM);
#elif USE_RNDW32
  do 
    {
      rc = _gcry_rndw32_gather_random (entropy_collect_cb, 0,
                                       X931_AES_KEYLEN,
                                       GCRY_VERY_STRONG_RANDOM);
    }
  while (rc >= 0 && entropy_collect_buffer_len < entropy_collect_buffer_size);
#else
  rc = -1;
#endif

  if (rc < 0 || entropy_collect_buffer_len != entropy_collect_buffer_size)
    {
      gcry_free (entropy_collect_buffer);
      entropy_collect_buffer = NULL;
      log_fatal ("error getting entropy data\n");
    }
  result = entropy_collect_buffer;
  entropy_collect_buffer = NULL;
  return result;
}


/* Generate a key for use with x931_aes.  The function returns a
   handle to the cipher context readily prepared for ECB encryption.
   If FOR_NONCE is true, the key is retrieved by readong random from
   the standard generator.  On error NULL is returned.  */
static gcry_cipher_hd_t
x931_generate_key (int for_nonce)
{
  gcry_cipher_hd_t hd;
  gpg_error_t err;
  void *buffer;

  gcry_assert (fips_rng_is_locked);

  /* Allocate a cipher context.  */
  err = gcry_cipher_open (&hd, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
                          GCRY_CIPHER_SECURE);
  if (err)
    {
      log_error ("error creating cipher context for RNG: %s\n",
                 gcry_strerror (err));
      return NULL;
    }

  /* Get a key from the standard RNG or from the entropy source.  */
  if (for_nonce)
    {
      buffer = gcry_xmalloc (X931_AES_KEYLEN);
      get_random (buffer, X931_AES_KEYLEN, std_rng_context);
    }
  else
    {
      buffer = get_entropy (X931_AES_KEYLEN);
    }

  /* Set the key and delete the buffer because the key is now part of
     the cipher context.  */
  err = gcry_cipher_setkey (hd, buffer, X931_AES_KEYLEN);
  wipememory (buffer, X931_AES_KEYLEN);
  gcry_free (buffer);
  if (err)
    {
      log_error ("error creating key for RNG: %s\n", gcry_strerror (err));
      gcry_cipher_close (hd);
      return NULL;
    }

  return hd;
}


/* Generate a key for use with x931_aes.  The function copies a seed
   of LENGTH bytes into SEED_BUFFER. LENGTH needs to by given as 16.  */
static void
x931_generate_seed (unsigned char *seed_buffer, size_t length)
{
  void *buffer;

  gcry_assert (fips_rng_is_locked);
  gcry_assert (length == 16);

  buffer = get_entropy (X931_AES_KEYLEN);

  memcpy (seed_buffer, buffer, X931_AES_KEYLEN);
  wipememory (buffer, X931_AES_KEYLEN);
  gcry_free (buffer);
}



/* Reseed a generator.  This is also used for the initial seeding. */
static void
x931_reseed (rng_context_t rng_ctx)
{
  gcry_assert (fips_rng_is_locked);

  if (rng_ctx == nonce_context)
    {
      /* The nonce context is special.  It will be seeded using the
         standard random generator.  */
      get_random (rng_ctx->seed_V, 16, std_rng_context);
      rng_ctx->is_seeded = 1;
      rng_ctx->seed_init_pid = getpid ();
    }
  else
    {
      /* The other two generators are seeded from /dev/random.  */
      x931_generate_seed (rng_ctx->seed_V, 16);
      rng_ctx->is_seeded = 1;
      rng_ctx->seed_init_pid = getpid ();
    }
}


/* Core random function.  This is used for both nonce and random
   generator.  The actual RNG to be used depends on the random context
   RNG_CTX passed.  Note that this function is called with the RNG not
   yet locked.  */
static void
get_random (void *buffer, size_t length, rng_context_t rng_ctx)
{
  gcry_assert (buffer);
  gcry_assert (rng_ctx);

  check_guards (rng_ctx);

  /* Initialize the cipher handle and thus setup the key if needed.  */
  if (!rng_ctx->cipher_hd)
    {
      if (rng_ctx == nonce_context)
        rng_ctx->cipher_hd = x931_generate_key (1);
      else
        rng_ctx->cipher_hd = x931_generate_key (0);
      if (!rng_ctx->cipher_hd)
        goto bailout;
      rng_ctx->key_init_pid = getpid ();
    }

  /* Initialize the seed value if needed.  */
  if (!rng_ctx->is_seeded)
    x931_reseed (rng_ctx);

  if (rng_ctx->key_init_pid != getpid ()
      || rng_ctx->seed_init_pid != getpid ())
    {
      /* We are in a child of us.  Because we have no way yet to do
         proper re-initialization (including self-checks etc), the
         only chance we have is to bail out.  Obviusly a fork/exec
         won't harm because the exec overwrites the old image. */
      fips_signal_error ("fork without proper re-initialization "
                         "detected in RNG");
      goto bailout;
    }

  if (x931_aes_driver (buffer, length, rng_ctx))
    goto bailout;

  check_guards (rng_ctx);
  return;

 bailout:
  log_fatal ("severe error getting random\n");
  /*NOTREACHED*/
}



/* --- Public Functions --- */

/* Initialize this random subsystem.  If FULL is false, this function
   merely calls the basic initialization of the module and does not do
   anything more.  Doing this is not really required but when running
   in a threaded environment we might get a race condition
   otherwise. */
void
_gcry_rngfips_initialize (int full)
{
  basic_initialization ();
  if (!full)
    return;

  /* Allocate temporary buffers.  If that buffer already exists we
     know that we are already initialized.  */
  lock_rng ();
  if (!tempvalue_for_x931_aes_driver)
    {
      tempvalue_for_x931_aes_driver
        = gcry_xmalloc_secure (TEMPVALUE_FOR_X931_AES_DRIVER_SIZE);

      /* Allocate the random contexts.  Note that we do not need to use
         secure memory for the nonce context.  */
      nonce_context = gcry_xcalloc (1, sizeof *nonce_context);
      setup_guards (nonce_context);

      std_rng_context = gcry_xcalloc_secure (1, sizeof *std_rng_context);
      setup_guards (std_rng_context);
      
      strong_rng_context = gcry_xcalloc_secure (1, sizeof *strong_rng_context);
      setup_guards (strong_rng_context);
    }
  else
    {
      /* Already initialized. Do some sanity checks.  */
      gcry_assert (!nonce_context->test_dt_ptr);
      gcry_assert (!std_rng_context->test_dt_ptr);
      gcry_assert (!strong_rng_context->test_dt_ptr);
      check_guards (nonce_context);
      check_guards (std_rng_context);
      check_guards (strong_rng_context);
    }
  unlock_rng ();
}


/* Print some statistics about the RNG.  */
void
_gcry_rngfips_dump_stats (void)
{
  /* Not yet implemented.  */
}


/* This function returns true if no real RNG is available or the
   quality of the RNG has been degraded for test purposes.  */
int
_gcry_rngfips_is_faked (void)
{
  return 0;  /* Faked random is not allowed.  */
}


/* Add BUFLEN bytes from BUF to the internal random pool.  QUALITY
   should be in the range of 0..100 to indicate the goodness of the
   entropy added, or -1 for goodness not known. */
gcry_error_t
_gcry_rngfips_add_bytes (const void *buf, size_t buflen, int quality)
{
  (void)buf;
  (void)buflen;
  (void)quality;
  return 0;  /* Not implemented. */
}   

    
/* Public function to fill the buffer with LENGTH bytes of
   cryptographically strong random bytes.  Level GCRY_WEAK_RANDOM is
   here mapped to GCRY_STRONG_RANDOM, GCRY_STRONG_RANDOM is strong
   enough for most usage, GCRY_VERY_STRONG_RANDOM is good for key
   generation stuff but may be very slow.  */
void
_gcry_rngfips_randomize (void *buffer, size_t length,
                         enum gcry_random_level level)
{
  _gcry_rngfips_initialize (1);  /* Auto-initialize if needed.  */
  
  lock_rng ();
  if (level == GCRY_VERY_STRONG_RANDOM)
    get_random (buffer, length, strong_rng_context);
  else
    get_random (buffer, length, std_rng_context);
  unlock_rng ();
}


/* Create an unpredicable nonce of LENGTH bytes in BUFFER. */
void
_gcry_rngfips_create_nonce (void *buffer, size_t length)
{
  _gcry_rngfips_initialize (1);  /* Auto-initialize if needed.  */

  lock_rng ();
  get_random (buffer, length, nonce_context);
  unlock_rng ();
}


/* Run a Know-Answer-Test using a dedicated test context.  Note that
   we can't use the samples from the NISR RNGVS document because they
   don't take the requirement to throw away the first block and use
   that for duplicate check in account.  Thus we made up our own test
   vectors. */
static gcry_err_code_t
selftest_kat (selftest_report_func_t report)
{
  static struct 
  {
    const unsigned char key[16];
    const unsigned char dt[16];
    const unsigned char v[16];
    const unsigned char r[3][16];
  } tv[] =
    {
      { { 0xb9, 0xca, 0x7f, 0xd6, 0xa0, 0xf5, 0xd3, 0x42,
          0x19, 0x6d, 0x84, 0x91, 0x76, 0x1c, 0x3b, 0xbe },
        { 0x48, 0xb2, 0x82, 0x98, 0x68, 0xc2, 0x80, 0x00,
          0x00, 0x00, 0x28, 0x18, 0x00, 0x00, 0x25, 0x00 },
        { 0x52, 0x17, 0x8d, 0x29, 0xa2, 0xd5, 0x84, 0x12,
          0x9d, 0x89, 0x9a, 0x45, 0x82, 0x02, 0xf7, 0x77 },
        { { 0x42, 0x9c, 0x08, 0x3d, 0x82, 0xf4, 0x8a, 0x40,
            0x66, 0xb5, 0x49, 0x27, 0xab, 0x42, 0xc7, 0xc3 },
          { 0x0e, 0xb7, 0x61, 0x3c, 0xfe, 0xb0, 0xbe, 0x73,
            0xf7, 0x6e, 0x6d, 0x6f, 0x1d, 0xa3, 0x14, 0xfa },
          { 0xbb, 0x4b, 0xc1, 0x0e, 0xc5, 0xfb, 0xcd, 0x46,
            0xbe, 0x28, 0x61, 0xe7, 0x03, 0x2b, 0x37, 0x7d } } },
      { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
          0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
        { { 0xf7, 0x95, 0xbd, 0x4a, 0x52, 0xe2, 0x9e, 0xd7,
            0x13, 0xd3, 0x13, 0xfa, 0x20, 0xe9, 0x8d, 0xbc },
          { 0xc8, 0xd1, 0xe5, 0x11, 0x59, 0x52, 0xf7, 0xfa,
            0x37, 0x38, 0xb4, 0xc5, 0xce, 0xb2, 0xb0, 0x9a },
          { 0x0d, 0x9c, 0xc5, 0x0d, 0x16, 0xe1, 0xbc, 0xed, 
            0xcf, 0x60, 0x62, 0x09, 0x9d, 0x20, 0x83, 0x7e } } },
      { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
          0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f },
        { 0x80, 0x00, 0x81, 0x01, 0x82, 0x02, 0x83, 0x03,
          0xa0, 0x20, 0xa1, 0x21, 0xa2, 0x22, 0xa3, 0x23 },
        { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
          0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff },
        { { 0x96, 0xed, 0xcc, 0xc3, 0xdd, 0x04, 0x7f, 0x75,
            0x63, 0x19, 0x37, 0x6f, 0x15, 0x22, 0x57, 0x56 },
          { 0x7a, 0x14, 0x76, 0x77, 0x95, 0x17, 0x7e, 0xc8,
            0x92, 0xe8, 0xdd, 0x15, 0xcb, 0x1f, 0xbc, 0xb1 },
          { 0x25, 0x3e, 0x2e, 0xa2, 0x41, 0x1b, 0xdd, 0xf5, 
            0x21, 0x48, 0x41, 0x71, 0xb3, 0x8d, 0x2f, 0x4c } } }
    };
  int tvidx, ridx;
  rng_context_t test_ctx;
  gpg_error_t err;
  const char *errtxt = NULL;
  unsigned char result[16];

  gcry_assert (tempvalue_for_x931_aes_driver);

  test_ctx = gcry_xcalloc (1, sizeof *test_ctx);
  setup_guards (test_ctx);
  
  lock_rng ();

  for (tvidx=0; tvidx < DIM (tv); tvidx++)
    {
      /* Setup the key.  */
      err = gcry_cipher_open (&test_ctx->cipher_hd,
                              GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
                              GCRY_CIPHER_SECURE);
      if (err)
        {
          errtxt = "error creating cipher context for RNG";
          goto leave;
        }

      err = gcry_cipher_setkey (test_ctx->cipher_hd, tv[tvidx].key, 16);
      if (err)
        {
          errtxt = "error setting key for RNG";
          goto leave;
        }
      test_ctx->key_init_pid = getpid ();
      
      /* Setup the seed.  */
      memcpy (test_ctx->seed_V, tv[tvidx].v, 16);
      test_ctx->is_seeded = 1;
      test_ctx->seed_init_pid = getpid ();
      
      /* Setup a DT value.  */
      test_ctx->test_dt_ptr = tv[tvidx].dt;
      test_ctx->test_dt_counter = ( (tv[tvidx].dt[12] << 24) 
                                   |(tv[tvidx].dt[13] << 16)
                                   |(tv[tvidx].dt[14] << 8)
                                   |(tv[tvidx].dt[15]) );

      /* Get and compare the first three results.  */
      for (ridx=0; ridx < 3; ridx++)
        {
          /* Compute the next value.  */
          if (x931_aes_driver (result, 16, test_ctx))
            {
              errtxt = "X9.31 RNG core function failed";
              goto leave;
            }
          
          /* Compare it to the known value.  */
          if (memcmp (result, tv[tvidx].r[ridx], 16))
            {
              /* log_printhex ("x931_aes got: ", result, 16); */
              /* log_printhex ("x931_aes exp: ", tv[tvidx].r[ridx], 16); */
              errtxt = "RNG output does not match known value";
              goto leave;
            }
        }

      /* This test is actual pretty pointless because we use a local test
         context.  */
      if (test_ctx->key_init_pid != getpid ()
          || test_ctx->seed_init_pid != getpid ())
        {
          errtxt = "fork detection failed";
          goto leave;
        }

      gcry_cipher_close (test_ctx->cipher_hd);
      test_ctx->cipher_hd = NULL;
      test_ctx->is_seeded = 0;
      check_guards (test_ctx);
    }

 leave:
  unlock_rng ();
  gcry_cipher_close (test_ctx->cipher_hd);
  check_guards (test_ctx);
  gcry_free (test_ctx);
  if (report && errtxt)
    report ("random", 0, "KAT", errtxt);
  return errtxt? GPG_ERR_SELFTEST_FAILED : 0;
}


/* Run the self-tests.  */
gcry_error_t
_gcry_rngfips_selftest (selftest_report_func_t report)
{
  gcry_err_code_t ec;

#if defined(USE_RNDLINUX) || defined(USE_RNDW32)
  {
    char buffer[8];

    /* Do a simple test using the public interface.  This will also
       enforce full intialization of the RNG.  We need to be fully
       initialized due to the global requirement of the
       tempvalue_for_x931_aes_driver stuff. */
    gcry_randomize (buffer, sizeof buffer, GCRY_STRONG_RANDOM);
  }

  ec = selftest_kat (report);

#else /*!(USE_RNDLINUX||USE_RNDW32)*/
  report ("random", 0, "setup", "no entropy gathering module");
  ec = GPG_ERR_SELFTEST_FAILED;
#endif
  return gpg_error (ec);
}


/* Create a new test context for an external RNG test driver.  On
   success the test context is stored at R_CONTEXT; on failure NULL is
   stored at R_CONTEXT and an error code is returned.  */
gcry_err_code_t
_gcry_rngfips_init_external_test (void **r_context, unsigned int flags,
                                  const void *key, size_t keylen,
                                  const void *seed, size_t seedlen,
                                  const void *dt, size_t dtlen)
{
  gpg_error_t err;
  rng_context_t test_ctx;

  _gcry_rngfips_initialize (1);  /* Auto-initialize if needed.  */
  
  if (!r_context
      || !key  || keylen  != 16 
      || !seed || seedlen != 16
      || !dt   || dtlen   != 16 )
    return GPG_ERR_INV_ARG;

  test_ctx = gcry_calloc (1, sizeof *test_ctx + dtlen);
  if (!test_ctx)
    return gpg_err_code_from_syserror ();
  setup_guards (test_ctx);
  
  /* Setup the key.  */
  err = gcry_cipher_open (&test_ctx->cipher_hd,
                          GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB,
                          GCRY_CIPHER_SECURE);
  if (err)
    goto leave;

  err = gcry_cipher_setkey (test_ctx->cipher_hd, key, keylen);
  if (err)
    goto leave;

  test_ctx->key_init_pid = getpid ();
      
  /* Setup the seed.  */
  memcpy (test_ctx->seed_V, seed, seedlen);
  test_ctx->is_seeded = 1;
  test_ctx->seed_init_pid = getpid ();
  
  /* Setup a DT value.  Because our context structure only stores a
     pointer we copy the DT value to the extra space we allocated in
     the test_ctx and set the pointer to that address.  */
  memcpy ((unsigned char*)test_ctx + sizeof *test_ctx, dt, dtlen);
  test_ctx->test_dt_ptr = (unsigned char*)test_ctx + sizeof *test_ctx; 
  test_ctx->test_dt_counter = ( (test_ctx->test_dt_ptr[12] << 24) 
                               |(test_ctx->test_dt_ptr[13] << 16)
                               |(test_ctx->test_dt_ptr[14] << 8)
                               |(test_ctx->test_dt_ptr[15]) );

  if ( (flags & 1) )
    test_ctx->test_no_dup_check = 1;

  check_guards (test_ctx);
  /* All fine.  */
  err = 0;

 leave:
  if (err)
    {
      gcry_cipher_close (test_ctx->cipher_hd);
      gcry_free (test_ctx);
      *r_context = NULL;
    }
  else
    *r_context = test_ctx;
  return gcry_err_code (err);
}


/* Get BUFLEN bytes from the RNG using the test CONTEXT and store them
   at BUFFER.  Return 0 on success or an error code.  */
gcry_err_code_t
_gcry_rngfips_run_external_test (void *context, char *buffer, size_t buflen)
{
  rng_context_t test_ctx = context;

  if (!test_ctx || !buffer || buflen != 16)
    return GPG_ERR_INV_ARG;

  lock_rng ();
  get_random (buffer, buflen, test_ctx);
  unlock_rng ();
  return 0;
}

/* Release the test CONTEXT.  */
void
_gcry_rngfips_deinit_external_test (void *context)
{
  rng_context_t test_ctx = context;

  if (test_ctx)
    {
      gcry_cipher_close (test_ctx->cipher_hd);
      gcry_free (test_ctx);
    }
}