forked from artyom-beilis/cppcms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathurandom.cpp
More file actions
129 lines (111 loc) · 2.93 KB
/
urandom.cpp
File metadata and controls
129 lines (111 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2008-2012 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// See accompanying file COPYING.TXT file for licensing details.
//
///////////////////////////////////////////////////////////////////////////////
#define CPPCMS_SOURCE
#include <cppcms/urandom.h>
#include <cppcms/cppcms_error.h>
#ifdef CPPCMS_WIN_NATIVE
#include <sstream>
#include <booster/thread.h>
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include "windows.h"
#include "wincrypt.h"
namespace cppcms {
class urandom_device_impl {
public:
urandom_device_impl() {
if(CryptAcquireContext(&provider_,0,0,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT))
return;
if(GetLastError() == (DWORD)(NTE_BAD_KEYSET)) {
if(CryptAcquireContext(&provider_,0,0,PROV_RSA_FULL,CRYPT_NEWKEYSET))
return;
}
std::ostringstream ss;
ss<<"CryptAcquireContext failed with code 0x"<<std::hex<<GetLastError();
throw cppcms_error(ss.str());
}
~urandom_device_impl()
{
CryptReleaseContext(provider_,0);
}
void generate(void *ptr,unsigned len)
{
if(CryptGenRandom(provider_,len,static_cast<BYTE *>(ptr)))
return;
std::ostringstream ss;
ss<<"CryptGenRandom failed with code 0x"<<std::hex<<GetLastError();
throw cppcms_error(ss.str());
}
private:
HCRYPTPROV provider_;
};
booster::thread_specific_ptr<urandom_device_impl> urandom_device_impl_ptr;
struct urandom_device::_data {};
urandom_device::urandom_device()
{
}
urandom_device::~urandom_device()
{
}
void urandom_device::generate(void *ptr,unsigned len)
{
if(!urandom_device_impl_ptr.get())
urandom_device_impl_ptr.reset(new urandom_device_impl());
urandom_device_impl_ptr->generate(ptr,len);
}
} // cppcms
#else
#ifndef CPPCMS_WIN32
#include "daemonize.h"
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
namespace cppcms {
struct urandom_device::_data {};
urandom_device::urandom_device()
{
}
urandom_device::~urandom_device()
{
}
void urandom_device::generate(void *ptr,unsigned len)
{
if(len == 0)
return;
int n = 0;
#ifndef CPPCMS_WIN32
if(impl::daemonizer::global_urandom_fd!=-1) {
n = read(impl::daemonizer::global_urandom_fd,ptr,len);
}
else
#endif
{
int fd = open("/dev/urandom",O_RDONLY);
if(!fd)
throw cppcms_error("Failed to open /dev/urandom");
while(len > 0) {
n = read(fd,ptr,len);
if(n < 0 && errno == EINTR)
continue;
if(n <= 0)
break;
ptr = static_cast<char *>(ptr) + n;
len -= n;
}
close(fd);
}
if(len > 0) {
throw cppcms_error("Failed to read /dev/urandom");
}
}
}
#endif