]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/fhandler_random.cc
* Merge in cygwin-64bit-branch.
[newlib-cygwin.git] / winsup / cygwin / fhandler_random.cc
CommitLineData
e3c25c4a 1/* fhandler_random.cc: code to access /dev/random and /dev/urandom
1c0c369b 2
40afcae3 3 Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2009, 2011 Red Hat, Inc.
1c0c369b
CV
4
5 Written by Corinna Vinschen (vinschen@cygnus.com)
6
7This file is part of Cygwin.
8
9This software is a copyrighted work licensed under the terms of the
10Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11details. */
12
4c8d72de 13#include "winsup.h"
04cb518d 14#include <unistd.h>
9e2baf8d 15#include "cygerrno.h"
7ac61736 16#include "path.h"
bccd5e0d 17#include "fhandler.h"
56a19715
CF
18#include "sync.h"
19#include "dtable.h"
20#include "cygheap.h"
21#include "child_info.h"
1c0c369b
CV
22
23#define RANDOM 8
24#define URANDOM 9
25
9602ffc3 26#define PSEUDO_MULTIPLIER (6364136223846793005LL)
b0e82b74 27#define PSEUDO_SHIFTVAL (21)
9602ffc3 28
7ac61736
CF
29fhandler_dev_random::fhandler_dev_random ()
30 : fhandler_base (), crypt_prov ((HCRYPTPROV) NULL)
1c0c369b 31{
1c0c369b
CV
32}
33
34int
7ac61736 35fhandler_dev_random::open (int flags, mode_t)
1c0c369b 36{
1bc9effd 37 set_flags ((flags & ~O_TEXT) | O_BINARY);
56551a9b 38 nohandle (true);
f3ea62a8 39 set_open_status ();
04cb518d 40 dummy_offset = 0;
1c0c369b
CV
41 return 1;
42}
43
2e008fb9 44bool
9602ffc3
CV
45fhandler_dev_random::crypt_gen_random (void *ptr, size_t len)
46{
47 if (!crypt_prov
40afcae3
CV
48 && !CryptAcquireContextW (&crypt_prov, NULL, MS_DEF_PROV_W, PROV_RSA_FULL,
49 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET)
50 && !CryptAcquireContextW (&crypt_prov, NULL, MS_DEF_PROV_W, PROV_RSA_FULL,
51 CRYPT_VERIFYCONTEXT | CRYPT_MACHINE_KEYSET
52 | CRYPT_NEWKEYSET))
9602ffc3
CV
53 {
54 debug_printf ("%E = CryptAquireContext()");
2e008fb9 55 return false;
9602ffc3
CV
56 }
57 if (!CryptGenRandom (crypt_prov, len, (BYTE *)ptr))
58 {
59 debug_printf ("%E = CryptGenRandom()");
2e008fb9 60 return false;
9602ffc3 61 }
2e008fb9 62 return true;
9602ffc3
CV
63}
64
1c0c369b 65int
9602ffc3 66fhandler_dev_random::pseudo_write (const void *ptr, size_t len)
1c0c369b 67{
9602ffc3
CV
68 /* Use buffer to mess up the pseudo random number generator. */
69 for (size_t i = 0; i < len; ++i)
70 pseudo = (pseudo + ((unsigned char *)ptr)[i]) * PSEUDO_MULTIPLIER + 1;
1c0c369b
CV
71 return len;
72}
73
43c23d4b 74ssize_t __stdcall
9602ffc3 75fhandler_dev_random::write (const void *ptr, size_t len)
1c0c369b
CV
76{
77 if (!len)
78 return 0;
9602ffc3 79 if (!ptr)
1c0c369b 80 {
9602ffc3 81 set_errno (EINVAL);
1c0c369b
CV
82 return -1;
83 }
9602ffc3
CV
84
85 /* Limit len to a value <= 512 since we don't want to overact.
86 Copy to local buffer because CryptGenRandom violates const. */
87 unsigned char buf[512];
88 size_t limited_len = len <= 512 ? len : 512;
89 memcpy (buf, ptr, limited_len);
90
91 /* Mess up system entropy source. Return error if device is /dev/random. */
7ac61736 92 if (!crypt_gen_random (buf, limited_len) && dev () == FH_RANDOM)
1c0c369b
CV
93 {
94 __seterrno ();
95 return -1;
96 }
9602ffc3
CV
97 /* Mess up the pseudo random number generator. */
98 pseudo_write (buf, limited_len);
1c0c369b
CV
99 return len;
100}
101
9602ffc3
CV
102int
103fhandler_dev_random::pseudo_read (void *ptr, size_t len)
104{
105 /* Use pseudo random number generator as fallback entropy source.
106 This multiplier was obtained from Knuth, D.E., "The Art of
107 Computer Programming," Vol 2, Seminumerical Algorithms, Third
108 Edition, Addison-Wesley, 1998, p. 106 (line 26) & p. 108 */
109 for (size_t i = 0; i < len; ++i)
110 {
111 pseudo = pseudo * PSEUDO_MULTIPLIER + 1;
112 ((unsigned char *)ptr)[i] = (pseudo >> PSEUDO_SHIFTVAL) & UCHAR_MAX;
113 }
114 return len;
115}
116
8bce0d72
CF
117void __stdcall
118fhandler_dev_random::read (void *ptr, size_t& len)
9602ffc3
CV
119{
120 if (!len)
8bce0d72
CF
121 return;
122
9602ffc3
CV
123 if (!ptr)
124 {
125 set_errno (EINVAL);
6cce721b 126 len = (size_t) -1;
8bce0d72 127 return;
9602ffc3
CV
128 }
129
130 if (crypt_gen_random (ptr, len))
8bce0d72
CF
131 return;
132
9602ffc3
CV
133 /* If device is /dev/urandom, use pseudo number generator as fallback.
134 Don't do this for /dev/random since it's intended for uses that need
135 very high quality randomness. */
7ac61736 136 if (dev () == FH_URANDOM)
8bce0d72
CF
137 {
138 len = pseudo_read (ptr, len);
139 return;
140 }
9602ffc3
CV
141
142 __seterrno ();
6cce721b 143 len = (size_t) -1;
9602ffc3
CV
144}
145
61522196
CV
146off_t
147fhandler_dev_random::lseek (off_t off, int whence)
1c0c369b 148{
04cb518d
CV
149 /* As on Linux, fake being able to set an offset. The fact that neither
150 reading nor writing changes the dummy offset is also the same as on
151 Linux (tested with kernel 2.6.23). */
61522196 152 off_t new_off;
04cb518d
CV
153
154 switch (whence)
155 {
156 case SEEK_SET:
157 new_off = off;
158 break;
159 case SEEK_CUR:
160 new_off = dummy_offset + off;
161 break;
162 default:
163 set_errno (EINVAL);
61522196 164 return (off_t) -1;
04cb518d 165 }
53be6f3d
CV
166 if (new_off < 0)
167 {
168 set_errno (EINVAL);
61522196 169 return (off_t) -1;
53be6f3d 170 }
04cb518d 171 return dummy_offset = new_off;
1c0c369b
CV
172}
173
174int
2f9ae2ed 175fhandler_dev_random::close ()
1c0c369b 176{
56a19715 177 if (!have_execed && crypt_prov)
1c0c369b 178 while (!CryptReleaseContext (crypt_prov, 0)
b0e82b74 179 && GetLastError () == ERROR_BUSY)
c90e1cf1 180 Sleep (10);
1c0c369b
CV
181 return 0;
182}
183
184int
23771fa1 185fhandler_dev_random::dup (fhandler_base *child, int)
1c0c369b
CV
186{
187 fhandler_dev_random *fhr = (fhandler_dev_random *) child;
1c0c369b
CV
188 fhr->crypt_prov = (HCRYPTPROV)NULL;
189 return 0;
190}
This page took 4.707294 seconds and 5 git commands to generate.