xref: /src/crypto/openssl/apps/rand.c (revision f25b8c9fb4f58cf61adb47d7570abe7caa6d385d)
1 /*
2  * Copyright 1998-2025 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the Apache License 2.0 (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9 
10 #include "apps.h"
11 #include "progs.h"
12 
13 #include <ctype.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #include <openssl/bio.h>
18 #include <openssl/err.h>
19 #include <openssl/rand.h>
20 
21 typedef enum OPTION_choice {
22     OPT_COMMON,
23     OPT_OUT,
24     OPT_ENGINE,
25     OPT_BASE64,
26     OPT_HEX,
27     OPT_R_ENUM,
28     OPT_PROV_ENUM
29 } OPTION_CHOICE;
30 
31 const OPTIONS rand_options[] = {
32     { OPT_HELP_STR, 1, '-', "Usage: %s [options] num[K|M|G|T]\n" },
33 
34     OPT_SECTION("General"),
35     { "help", OPT_HELP, '-', "Display this summary" },
36 #ifndef OPENSSL_NO_ENGINE
37     { "engine", OPT_ENGINE, 's', "Use engine, possibly a hardware device" },
38 #endif
39 
40     OPT_SECTION("Output"),
41     { "out", OPT_OUT, '>', "Output file" },
42     { "base64", OPT_BASE64, '-', "Base64 encode output" },
43     { "hex", OPT_HEX, '-', "Hex encode output" },
44 
45     OPT_R_OPTIONS,
46     OPT_PROV_OPTIONS,
47 
48     OPT_PARAMETERS(),
49     { "num", 0, 0, "Number of bytes to generate" },
50     { NULL }
51 };
52 
rand_main(int argc,char ** argv)53 int rand_main(int argc, char **argv)
54 {
55     ENGINE *e = NULL;
56     BIO *out = NULL;
57     char *outfile = NULL, *prog;
58     OPTION_CHOICE o;
59     int format = FORMAT_BINARY, r, i, ret = 1;
60     size_t buflen = (1 << 16); /* max rand chunk size is 2^16 bytes */
61     long num = -1;
62     uint64_t scaled_num = 0;
63     uint8_t *buf = NULL;
64 
65     prog = opt_init(argc, argv, rand_options);
66     while ((o = opt_next()) != OPT_EOF) {
67         switch (o) {
68         case OPT_EOF:
69         case OPT_ERR:
70         opthelp:
71             BIO_printf(bio_err, "%s: Use -help for summary.\n", prog);
72             goto end;
73         case OPT_HELP:
74             opt_help(rand_options);
75             ret = 0;
76             goto end;
77         case OPT_OUT:
78             outfile = opt_arg();
79             break;
80         case OPT_ENGINE:
81             e = setup_engine(opt_arg(), 0);
82             break;
83         case OPT_R_CASES:
84             if (!opt_rand(o))
85                 goto end;
86             break;
87         case OPT_BASE64:
88             format = FORMAT_BASE64;
89             break;
90         case OPT_HEX:
91             format = FORMAT_TEXT;
92             break;
93         case OPT_PROV_CASES:
94             if (!opt_provider(o))
95                 goto end;
96             break;
97         }
98     }
99 
100     /* Optional argument is number of bytes to generate. */
101     argc = opt_num_rest();
102     argv = opt_rest();
103     if (argc == 1) {
104         int factoridx = 0;
105         int shift = 0;
106 
107         /*
108          * special case for requesting the max allowed
109          * number of random bytes to be generated
110          */
111         if (!strcmp(argv[0], "max")) {
112             /*
113              * 2^61 bytes is the limit of random output
114              * per drbg instantiation
115              */
116             scaled_num = UINT64_MAX >> 3;
117         } else {
118             /*
119              * iterate over the value and check to see if there are
120              * any non-numerical chars
121              * A non digit suffix indicates we need to shift the
122              * number of requested bytes by a factor of:
123              * K = 1024^1 (1 << (10 * 1))
124              * M = 1024^2 (1 << (10 * 2))
125              * G = 1024^3 (1 << (10 * 3))
126              * T = 1024^4 (1 << (10 * 4))
127              * which can be achieved by bit-shifting the number
128              */
129             while (argv[0][factoridx]) {
130                 if (!isdigit((int)(argv[0][factoridx]))) {
131                     switch (argv[0][factoridx]) {
132                     case 'K':
133                         shift = 10;
134                         break;
135                     case 'M':
136                         shift = 20;
137                         break;
138                     case 'G':
139                         shift = 30;
140                         break;
141                     case 'T':
142                         shift = 40;
143                         break;
144                     default:
145                         BIO_printf(bio_err, "Invalid size suffix %s\n",
146                             &argv[0][factoridx]);
147                         goto opthelp;
148                     }
149                     break;
150                 }
151                 factoridx++;
152             }
153 
154             if (shift != 0 && strlen(&argv[0][factoridx]) != 1) {
155                 BIO_printf(bio_err, "Invalid size suffix %s\n",
156                     &argv[0][factoridx]);
157                 goto opthelp;
158             }
159         }
160         /* Remove the suffix from the arg so that opt_long works */
161         if (shift != 0)
162             argv[0][factoridx] = '\0';
163 
164         if ((scaled_num == 0) && (!opt_long(argv[0], &num) || num <= 0))
165             goto opthelp;
166 
167         if (shift != 0) {
168             /* check for overflow */
169             if ((UINT64_MAX >> shift) < (size_t)num) {
170                 BIO_printf(bio_err, "%lu bytes with suffix overflows\n",
171                     num);
172                 goto opthelp;
173             }
174             scaled_num = num << shift;
175             if (scaled_num > (UINT64_MAX >> 3)) {
176                 BIO_printf(bio_err, "Request exceeds max allowed output\n");
177                 goto opthelp;
178             }
179         } else {
180             if (scaled_num == 0)
181                 scaled_num = num;
182         }
183     } else if (!opt_check_rest_arg(NULL)) {
184         goto opthelp;
185     }
186 
187     if (!app_RAND_load())
188         goto end;
189 
190     out = bio_open_default(outfile, 'w', format);
191     if (out == NULL)
192         goto end;
193 
194     if (format == FORMAT_BASE64) {
195         BIO *b64 = BIO_new(BIO_f_base64());
196         if (b64 == NULL)
197             goto end;
198         out = BIO_push(b64, out);
199     }
200 
201     buf = app_malloc(buflen, "buffer for output file");
202     while (scaled_num > 0) {
203         int chunk;
204 
205         chunk = scaled_num > buflen ? (int)buflen : (int)scaled_num;
206         r = RAND_bytes_ex(app_get0_libctx(), buf, chunk, 0);
207         if (r <= 0)
208             goto end;
209         if (format != FORMAT_TEXT) {
210             if (BIO_write(out, buf, chunk) != chunk)
211                 goto end;
212         } else {
213             for (i = 0; i < chunk; i++)
214                 if (BIO_printf(out, "%02x", buf[i]) != 2)
215                     goto end;
216         }
217         scaled_num -= chunk;
218     }
219     if (format == FORMAT_TEXT)
220         BIO_puts(out, "\n");
221     if (BIO_flush(out) <= 0)
222         goto end;
223 
224     ret = 0;
225 
226 end:
227     if (ret != 0)
228         ERR_print_errors(bio_err);
229     OPENSSL_free(buf);
230     release_engine(e);
231     BIO_free_all(out);
232     return ret;
233 }
234