Make fipsrngdriv more pretty.
[libgcrypt.git] / tests / fipsrngdrv.c
1 /* fipsrngdrv.c  -  A driver to test the FIPS RNG.
2    Copyright (C) 2008 Free Software Foundation, Inc.
3
4    This file is part of Libgcrypt.
5   
6    Libgcrypt is free software; you can redistribute it and/or modify
7    it under the terms of the GNU Lesser General Public License as
8    published by the Free Software Foundation; either version 2.1 of
9    the License, or (at your option) any later version.
10   
11    Libgcrypt is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU Lesser General Public License for more details.
15   
16    You should have received a copy of the GNU Lesser General Public
17    License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #ifndef HAVE_W32_SYSTEM
30 # include <signal.h>
31 #endif
32
33 #include <gcrypt.h>
34
35 #define PGM "fipsrngdrv"
36
37 #define my_isascii(c) (!((c) & 0x80))
38 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
39 #define hexdigitp(a) (digitp (a)                     \
40                       || (*(a) >= 'A' && *(a) <= 'F')  \
41                       || (*(a) >= 'a' && *(a) <= 'f'))
42 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
43                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
44 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
45
46
47 static void
48 die (const char *format, ...)
49 {
50   va_list arg_ptr;
51
52   va_start (arg_ptr, format);
53   fputs (PGM ": ", stderr);
54   vfprintf (stderr, format, arg_ptr);
55   va_end (arg_ptr);
56   exit (1);
57 }
58
59
60 /* Convert STRING consisting of hex characters into its binary
61    representation and store that at BUFFER.  BUFFER needs to be of
62    LENGTH bytes.  The function checks that the STRING will convert
63    exactly to LENGTH bytes. The string is delimited by either end of
64    string or a white space character.  The function returns -1 on
65    error or the length of the parsed string.  */
66 static int
67 hex2bin (const char *string, void *buffer, size_t length)
68 {
69   int i;
70   const char *s = string;
71
72   for (i=0; i < length; )
73     {
74       if (!hexdigitp (s) || !hexdigitp (s+1))
75         return -1;           /* Invalid hex digits. */
76       ((unsigned char*)buffer)[i++] = xtoi_2 (s);
77       s += 2;
78     }
79   if (*s && (!my_isascii (*s) || !isspace (*s)) )
80     return -1;             /* Not followed by Nul or white space.  */
81   if (i != length)
82     return -1;             /* Not of expected length.  */
83   if (*s)
84     s++; /* Skip the delimiter. */
85   return s - string;
86 }
87
88
89
90
91 static gcry_error_t
92 init_external_test (void **r_context, 
93                     unsigned int flags,
94                     const void *key, size_t keylen,
95                     const void *seed, size_t seedlen,
96                     const void *dt, size_t dtlen)
97 {
98   return gcry_control (58, 
99                        r_context, flags,
100                        key, keylen,
101                        seed, seedlen,
102                        dt, dtlen);
103 }
104
105 static gcry_error_t
106 run_external_test (void *context, void *buffer, size_t buflen)
107 {
108   return gcry_control (59, context, buffer, buflen);
109 }
110
111 static void
112 deinit_external_test (void *context)
113 {
114   gcry_control (60, context);
115 }
116
117
118 static void
119 print_buffer (const unsigned char *buffer, size_t length)
120 {
121   while (length--)
122     printf ("%02X", *buffer++);
123 }
124
125
126 int
127 main (int argc, char **argv)
128 {
129   int last_argc = -1;
130   int verbose = 0;
131   int binary = 0;
132   int loop = 0;
133   int progress = 0;
134   unsigned char key[16];
135   unsigned char seed[16];
136   unsigned char dt[16];
137   void *context;
138   gpg_error_t err;
139   unsigned char buffer[16];
140
141   if (argc)
142     { argc--; argv++; }
143
144   while (argc && last_argc != argc )
145     {
146       last_argc = argc;
147       if (!strcmp (*argv, "--"))
148         {
149           argc--; argv++;
150           break;
151         }
152       else if (!strcmp (*argv, "--help"))
153         {
154           fputs ("usage: " PGM 
155                  " [--verbose] [--binary] [--loop] [--progress] KEY V DT\n",
156                  stdout);
157           exit (0);
158         }
159       else if (!strcmp (*argv, "--verbose"))
160         {
161           verbose++;
162           argc--; argv++;
163         }
164       else if (!strcmp (*argv, "--binary"))
165         {
166           binary = 1;
167           argc--; argv++;
168         }
169       else if (!strcmp (*argv, "--loop"))
170         {
171           loop = 1;
172           argc--; argv++;
173         }
174       else if (!strcmp (*argv, "--progress"))
175         {
176           progress = 1;
177           argc--; argv++;
178         }
179     }          
180   
181   if (!argc)
182     {
183       memcpy (key,  "1234567890123456", 16);
184       memcpy (seed, "abcdefghijklmnop", 16);
185       memcpy (dt,   "XXXXXXXXXXXXXXXX", 16);
186     }
187   else if (argc == 3)
188     {
189       if (    hex2bin (argv[0], key, 16) < 0
190            || hex2bin (argv[1], seed, 16) < 0
191            || hex2bin (argv[2], dt, 16) < 0 )
192         die ("args are not 32 hex digits each\n");
193     }
194   else
195     die ("invalid usage (try --help)\n");
196
197 #ifndef HAVE_W32_SYSTEM
198   if (loop)
199     signal (SIGPIPE, SIG_IGN);
200 #endif
201
202   if (verbose)
203     fputs (PGM ": started\n", stderr);
204
205   gcry_control (GCRYCTL_SET_VERBOSITY, (int)verbose);
206   gcry_control (GCRYCTL_FORCE_FIPS_MODE, 0);
207   if (!gcry_check_version ("1.4.3"))
208     die ("version mismatch\n");
209   gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
210   gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
211
212   err = init_external_test (&context, 0, key, 16, seed, 16, dt, 16);
213   if (err)
214     die ("init external test failed: %s\n", gpg_strerror (err));
215
216   do 
217     {
218       int writerr = 0;
219
220       err = run_external_test (context, buffer, sizeof buffer);
221       if (err)
222         die ("run external test failed: %s\n", gpg_strerror (err));
223       if (binary)
224         {
225           if (fwrite (buffer, 16, 1, stdout) != 1)
226             writerr = 1;
227           else
228             fflush (stdout);
229         }
230       else
231         {
232           print_buffer (buffer, sizeof buffer);
233           if (putchar ('\n') == EOF)
234             writerr = 1;
235         }
236       if (writerr)
237         {
238 #ifndef HAVE_W32_SYSTEM
239           if (loop && errno == EPIPE)
240             break;
241 #endif
242           die ("writing output failed: %s\n", strerror (errno));
243         }
244
245       if (progress)
246         {
247           putc ('.', stderr);
248           fflush (stderr);
249         }
250     }
251   while (loop);
252
253   if (progress)
254     putc ('\n', stderr);
255
256   deinit_external_test (context);
257
258   if (verbose)
259     fputs (PGM ": ready\n", stderr);
260
261   return 0;
262 }
263