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