1/*
2 * random.c
3 * Copyright (C) 2015, Broadcom Corporation
4 * All Rights Reserved.
5 *
6 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
7 * the contents of this file may not be disclosed to third parties, copied
8 * or duplicated in any form, in whole or in part, without the prior
9 * written permission of Broadcom Corporation.
10 *
11 * $Id: random.c 241182 2011-02-17 21:50:03Z $
12 */
13#include <stdio.h>
14#if defined(__linux__)
15#include <stdlib.h>
16#include <unistd.h>
17#include <string.h>
18#include <signal.h>
19#include <errno.h>
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <sys/ioctl.h>
23#include <netinet/in.h>
24#include <net/if.h>
25#include <fcntl.h>
26#include <linux/if_packet.h>
27#elif (defined(__ECOS) || defined(TARGETOS_nucleus))
28#include <stdlib.h>
29#elif WIN32
30#include <stdio.h>
31#include <windows.h>
32#include <Wincrypt.h>
33#endif /* __linux__ */
34
35#include <assert.h>
36#include <typedefs.h>
37#include <bcmcrypto/bn.h>
38
39#if defined(__linux__)
40void linux_random(uint8 *rand, int len);
41#elif WIN32
42void windows_random(uint8 *rand, int len);
43#elif (defined(__ECOS) || defined(TARGETOS_nucleus))
44void generic_random(uint8* rand, int len);
45#elif defined(TARGETOS_symbian)
46void generic_random(uint8* rand, int len);
47#endif /* __linux__ */
48
49void RAND_bytes(unsigned char *buf, int num)
50{
51#if defined(__linux__)
52	linux_random(buf, num);
53#elif WIN32
54	windows_random(buf, num);
55#elif (defined(__ECOS) || defined(TARGETOS_nucleus))
56	generic_random(buf, num);
57#elif defined(TARGETOS_symbian)
58	generic_random(buf, num);
59#endif /* __linux__ */
60}
61
62#if defined(__linux__)
63void RAND_linux_init()
64{
65	BN_register_RAND(linux_random);
66}
67
68#ifndef	RANDOM_READ_TRY_MAX
69#define RANDOM_READ_TRY_MAX	10
70#endif
71
72void linux_random(uint8 *rand, int len)
73{
74	static int dev_random_fd = -1;
75	int status;
76	int i;
77
78	if (dev_random_fd == -1)
79		dev_random_fd = open("/dev/urandom", O_RDONLY|O_NONBLOCK);
80
81	assert(dev_random_fd != -1);
82
83	for (i = 0; i < RANDOM_READ_TRY_MAX; i++) {
84		status = read(dev_random_fd, rand, len);
85		if (status == -1) {
86			if (errno == EINTR)
87				continue;
88
89			assert(status != -1);
90		}
91
92		return;
93	}
94
95	assert(i != RANDOM_READ_TRY_MAX);
96}
97#elif __ECOS
98void RAND_ecos_init()
99{
100	BN_register_RAND(generic_random);
101}
102
103#elif WIN32
104void RAND_windows_init()
105{
106	BN_register_RAND(windows_random);
107}
108
109void windows_random(uint8 *rand, int len)
110{
111	/* Declare and initialize variables */
112
113	HCRYPTPROV hCryptProv = NULL;
114	LPCSTR UserName = "{56E9D11F-76B8-42fa-8645-76980E4E8648}";
115
116	/*
117	Attempt to acquire a context and a key
118	container. The context will use the default CSP
119	for the RSA_FULL provider type. DwFlags is set to 0
120	to attempt to open an existing key container.
121	*/
122	if (CryptAcquireContext(&hCryptProv,
123		UserName,
124		NULL,
125		PROV_RSA_FULL,
126		0))
127	{
128		/* do nothing */
129	}
130	else
131	{
132		/*
133		An error occurred in acquiring the context. This could mean
134		that the key container requested does not exist. In this case,
135		the function can be called again to attempt to create a new key
136		container. Error codes are defined in winerror.h.
137		*/
138		if (GetLastError() == NTE_BAD_KEYSET)
139		{
140			if (!CryptAcquireContext(&hCryptProv,
141				UserName,
142				NULL,
143				PROV_RSA_FULL,
144				CRYPT_NEWKEYSET))
145			{
146				printf("Could not create a new key container.\n");
147			}
148		}
149		else
150		{
151			printf("A cryptographic service handle could not be acquired.\n");
152		}
153	}
154
155	if (hCryptProv)
156	{
157		/* Generate a random initialization vector. */
158		if (!CryptGenRandom(hCryptProv, len, rand))
159		{
160			printf("Error during CryptGenRandom.\n");
161		}
162		if (!CryptReleaseContext(hCryptProv, 0))
163			printf("Failed CryptReleaseContext\n");
164	}
165	return;
166}
167#elif TARGETOS_nucleus
168void RAND_generic_init()
169{
170	BN_register_RAND(generic_random);
171}
172#elif TARGETOS_symbian
173void RAND_generic_init()
174{
175	BN_register_RAND(generic_random);
176}
177#endif /* __linux__ */
178
179#if (defined(__ECOS) || defined(TARGETOS_nucleus) || defined(TARGETOS_symbian))
180void
181generic_random(uint8 * random, int len)
182{
183	int tlen = len;
184	while (tlen--) {
185		*random = (uint8)rand();
186		*random++;
187	}
188	return;
189}
190#endif
191