2 * Copyright (c) 2007, Cameron Rich
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
9 * * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 * * Neither the name of the axTLS project nor the names of its contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 * Some misc. routines to help things out
39 #include "crypto_misc.h"
40 #ifdef CONFIG_WIN32_USE_CRYPTO_LIB
45 static int rng_fd = -1;
46 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
47 static HCRYPTPROV gCryptProv;
50 #if (!defined(CONFIG_USE_DEV_URANDOM) && !defined(CONFIG_WIN32_USE_CRYPTO_LIB))
51 static uint64_t rng_num;
54 static int rng_ref_count;
55 const char * const unsupported_str = "Error: Feature not supported\n";
57 #ifndef CONFIG_SSL_SKELETON_MODE
59 * Retrieve a file and put it into memory
60 * @return The size of the file, or -1 on failure.
62 int get_file(const char *filename, uint8_t **buf)
67 FILE *stream = fopen(filename, "rb");
71 #ifdef CONFIG_SSL_FULL_MODE
72 printf("file '%s' does not exist\n", filename); TTY_FLUSH();
77 /* Win CE doesn't support stat() */
78 fseek(stream, 0, SEEK_END);
79 filesize = ftell(stream);
80 *buf = (uint8_t *)malloc(filesize);
81 fseek(stream, 0, SEEK_SET);
85 bytes_read = fread(*buf+total_bytes, 1, filesize-total_bytes, stream);
86 total_bytes += bytes_read;
87 } while (total_bytes < filesize && bytes_read > 0);
95 * Initialise the Random Number Generator engine.
96 * - On Win32 use the platform SDK's crypto engine.
97 * - On Linux use /dev/urandom
98 * - If none of these work then use a custom RNG.
100 EXP_FUNC void STDCALL RNG_initialize(const uint8_t *seed_buf, int size)
102 if (rng_ref_count == 0)
104 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
105 rng_fd = ax_open("/dev/urandom", O_RDONLY);
106 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
107 if (!CryptAcquireContext(&gCryptProv,
108 NULL, NULL, PROV_RSA_FULL, 0))
110 if (GetLastError() == NTE_BAD_KEYSET &&
111 !CryptAcquireContext(&gCryptProv,
117 printf("CryptoLib: %x\n", unsupported_str, GetLastError());
122 /* help seed with the user's private key - this is a number that
123 should be hard to find, due to the fact that it relies on knowing
127 for (i = 0; i < size/(int)sizeof(uint64_t); i++)
128 rng_num ^= *((uint64_t *)&seed_buf[i*sizeof(uint64_t)]);
130 srand((long)&seed_buf); /* use the stack ptr as another rnd seed */
138 * Terminate the RNG engine.
140 EXP_FUNC void STDCALL RNG_terminate(void)
142 if (--rng_ref_count == 0)
146 #elif defined(CONFIG_WIN32_USE_CRYPTO_LIB)
147 CryptReleaseContext(gCryptProv, 0);
153 * Set a series of bytes with a random number. Individual bytes can be 0
155 EXP_FUNC void STDCALL get_random(int num_rand_bytes, uint8_t *rand_data)
157 #if !defined(WIN32) && defined(CONFIG_USE_DEV_URANDOM)
158 /* use the Linux default */
159 read(rng_fd, rand_data, num_rand_bytes); /* read from /dev/urandom */
160 #elif defined(WIN32) && defined(CONFIG_WIN32_USE_CRYPTO_LIB)
161 /* use Microsoft Crypto Libraries */
162 CryptGenRandom(gCryptProv, num_rand_bytes, rand_data);
163 #else /* nothing else to use, so use a custom RNG */
164 /* The method we use when we've got nothing better. Use RC4, time
165 and a couple of random seeds to generate a random sequence */
168 uint64_t big_num1, big_num2;
170 gettimeofday(&tv, NULL); /* yes I know we shouldn't do this */
172 /* all numbers by themselves are pretty simple, but combined should
174 big_num1 = (uint64_t)tv.tv_sec*(tv.tv_usec+1);
175 big_num2 = (uint64_t)rand()*big_num1;
178 memcpy(rand_data, &big_num1, sizeof(uint64_t));
179 if (num_rand_bytes > sizeof(uint64_t))
180 memcpy(&rand_data[8], &big_num2, sizeof(uint64_t));
182 if (num_rand_bytes > 16)
184 /* clear rest of data */
185 memset(&rand_data[16], 0, num_rand_bytes-16);
188 RC4_setup(&rng_ctx, rand_data, 16); /* use as a key */
189 RC4_crypt(&rng_ctx, rand_data, rand_data, num_rand_bytes);
191 /* use last 8 bytes for next time */
192 memcpy(&rng_num, &rand_data[num_rand_bytes-8], sizeof(uint64_t));
197 * Set a series of bytes with a random number. Individual bytes are not zero.
199 void get_random_NZ(int num_rand_bytes, uint8_t *rand_data)
202 get_random(num_rand_bytes, rand_data);
204 for (i = 0; i < num_rand_bytes; i++)
206 while (rand_data[i] == 0) /* can't be 0 */
207 rand_data[i] = (uint8_t)(rand());
212 * Some useful diagnostic routines
214 #if defined(CONFIG_SSL_FULL_MODE) || defined(CONFIG_DEBUG)
218 static void print_hex_init(int finish)
224 static void print_hex(uint8_t hex)
233 printf("%02x ", hex);
238 else if (column >= 16)
244 if (++hex_index >= hex_finish && column > 0)
251 * Spit out a blob of data for diagnostics. The data is is a nice column format
254 * @param format [in] The string (with possible embedded format characters)
255 * @param size [in] The number of numbers to print
256 * @param data [in] The start of data to use
257 * @param ... [in] Any additional arguments
259 EXP_FUNC void STDCALL print_blob(const char *format,
260 const uint8_t *data, int size, ...)
267 sprintf(tmp, "%s\n", format);
269 print_hex_init(size);
270 for (i = 0; i < size; i++)
279 /* VC6.0 doesn't handle variadic macros */
280 EXP_FUNC void STDCALL print_blob(const char *format, const unsigned char *data,
284 #if defined(CONFIG_SSL_HAS_PEM) || defined(CONFIG_HTTP_HAS_AUTHORIZATION)
285 /* base64 to binary lookup table */
286 static const uint8_t map[128] =
288 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
289 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
290 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
291 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63,
292 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
293 255, 254, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6,
294 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
295 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255,
296 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36,
297 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
298 49, 50, 51, 255, 255, 255, 255, 255
301 EXP_FUNC int STDCALL base64_decode(const char *in, int len,
302 uint8_t *out, int *outlen)
309 for (x = y = z = t = 0; x < len; x++)
311 if ((c = map[in[x]&0x7F]) == 0xff)
314 if (c == 254) /* this is the end... */
321 else if (g != 3) /* only allow = at end */
328 out[z++] = (uint8_t)((t>>16)&255);
331 out[z++] = (uint8_t)((t>>8)&255);
334 out[z++] = (uint8_t)(t&255);
348 #ifdef CONFIG_SSL_FULL_MODE
350 printf("Error: Invalid base64\n"); TTY_FLUSH();