blob: e22da3d07f543be5f53c039ae39d0405b8ffe53d [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19#include <rdr/RandomStream.h>
20#include <rdr/Exception.h>
Pierre Ossmane9e7da92016-04-20 09:38:06 +020021#include <rfb/LogWriter.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000022#include <time.h>
23#include <stdlib.h>
24#ifndef WIN32
25#include <unistd.h>
26#include <errno.h>
27#else
28#define getpid() GetCurrentProcessId()
29#ifndef RFB_HAVE_WINCRYPT
30#pragma message(" NOTE: Not building WinCrypt-based RandomStream")
31#endif
32#endif
33
Pierre Ossmane9e7da92016-04-20 09:38:06 +020034static rfb::LogWriter vlog("RandomStream");
35
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000036using namespace rdr;
37
38const int DEFAULT_BUF_LEN = 256;
39
40unsigned int RandomStream::seed;
41
42RandomStream::RandomStream()
43 : offset(0)
44{
45 ptr = end = start = new U8[DEFAULT_BUF_LEN];
46
47#ifdef RFB_HAVE_WINCRYPT
48 provider = 0;
49 if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, 0)) {
Pierre Ossman5c23b9e2015-03-03 16:26:03 +010050 if (GetLastError() == (DWORD)NTE_BAD_KEYSET) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000051 if (!CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
Pierre Ossmane9e7da92016-04-20 09:38:06 +020052 vlog.error("unable to create keyset");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000053 provider = 0;
54 }
55 } else {
Pierre Ossmane9e7da92016-04-20 09:38:06 +020056 vlog.error("unable to acquire context");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000057 provider = 0;
58 }
59 }
60 if (!provider) {
61#else
62#ifndef WIN32
63 fp = fopen("/dev/urandom", "r");
64 if (!fp)
65 fp = fopen("/dev/random", "r");
66 if (!fp) {
67#else
68 {
69#endif
70#endif
Pierre Ossmane9e7da92016-04-20 09:38:06 +020071 vlog.error("no OS supplied random source - using rand()");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000072 seed += (unsigned int) time(0) + getpid() + getpid() * 987654 + rand();
73 srand(seed);
74 }
75}
76
77RandomStream::~RandomStream() {
78 delete [] start;
79
80#ifdef RFB_HAVE_WINCRYPT
81 if (provider)
82 CryptReleaseContext(provider, 0);
83#endif
84#ifndef WIN32
85 if (fp) fclose(fp);
86#endif
87}
88
89int RandomStream::pos() {
90 return offset + ptr - start;
91}
92
93int RandomStream::overrun(int itemSize, int nItems, bool wait) {
94 if (itemSize > DEFAULT_BUF_LEN)
95 throw Exception("RandomStream overrun: max itemSize exceeded");
96
97 if (end - ptr != 0)
98 memmove(start, ptr, end - ptr);
99
100 end -= ptr - start;
101 offset += ptr - start;
102 ptr = start;
103
104 int length = start + DEFAULT_BUF_LEN - end;
105
106#ifdef RFB_HAVE_WINCRYPT
107 if (provider) {
108 if (!CryptGenRandom(provider, length, (U8*)end))
109 throw rdr::SystemException("unable to CryptGenRandom", GetLastError());
110 end += length;
111 } else {
112#else
113#ifndef WIN32
114 if (fp) {
115 int n = fread((U8*)end, length, 1, fp);
116 if (n != 1)
117 throw rdr::SystemException("reading /dev/urandom or /dev/random failed",
118 errno);
119 end += length;
120 } else {
121#else
122 {
123#endif
124#endif
125 for (int i=0; i<length; i++)
126 *(U8*)end++ = (int) (256.0*rand()/(RAND_MAX+1.0));
127 }
128
129 if (itemSize * nItems > end - ptr)
130 nItems = (end - ptr) / itemSize;
131
132 return nItems;
133}