1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Service Runtime. Secure RNG implementation.
9 : */
10 :
11 : #include <string.h>
12 :
13 : #include <unistd.h>
14 : #include <sys/types.h>
15 : #include <sys/stat.h>
16 : #include <fcntl.h>
17 :
18 : #include "native_client/src/shared/platform/nacl_check.h"
19 : #include "native_client/src/shared/platform/nacl_log.h"
20 : #include "native_client/src/shared/platform/nacl_secure_random.h"
21 :
22 : #ifndef NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE
23 : # define NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE "/dev/urandom"
24 : #endif
25 :
26 : static struct NaClSecureRngIfVtbl const kNaClSecureRngVtbl;
27 :
28 : /* use -1 to ensure a fast failure if module initializer is not called */
29 : static int urandom_d = -1;
30 :
31 : #define SANDBOXED_INITIALIZATION (!defined(NACL_STANDALONE))
32 :
33 : #if SANDBOXED_INITIALIZATION
34 :
35 : # include "base/rand_util_c.h"
36 :
37 : void NaClSecureRngModuleInit(void) {
38 : urandom_d = dup(GetUrandomFD());
39 : }
40 :
41 : #else
42 :
43 45 : void NaClSecureRngModuleInit(void) {
44 45 : urandom_d = open(NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE, O_RDONLY, 0);
45 45 : if (-1 == urandom_d) {
46 0 : NaClLog(LOG_FATAL, "Cannot open system random source %s\n",
47 : NACL_SECURE_RANDOM_SYSTEM_RANDOM_SOURCE);
48 : }
49 45 : }
50 :
51 : #endif /* !SANDBOXED_INITIALIZATION */
52 :
53 29 : void NaClSecureRngModuleFini(void) {
54 29 : (void) close(urandom_d);
55 29 : urandom_d = -1;
56 29 : }
57 :
58 : #if USE_CRYPTO
59 :
60 : static int NaClSecureRngCtorCommon(struct NaClSecureRng *self,
61 66 : unsigned char *key) {
62 66 : self->base.vtbl = &kNaClSecureRngVtbl;
63 66 : AES_set_encrypt_key(key, AES_BLOCK_SIZE * 8, &self->expanded_key);
64 66 : memset(self->counter, 0, sizeof self->counter);
65 66 : self->nvalid = 0;
66 :
67 66 : memset(key, 0, AES_BLOCK_SIZE);
68 66 : return 1;
69 : }
70 :
71 65 : int NaClSecureRngCtor(struct NaClSecureRng *self) {
72 : unsigned char key[AES_BLOCK_SIZE];
73 :
74 65 : self->base.vtbl = NULL;
75 : /*
76 : * Windows version should get seed bytes from CryptoAPI's
77 : * CryptGenRandom. Whether we want to use that as seed as here, or
78 : * as the generator for everything depends on how expensive it is
79 : * (and whether it matters for our usage).
80 : */
81 :
82 65 : VCHECK(-1 != urandom_d,
83 : ("NaClSecureRngCtor: random descriptor invalid;"
84 : " module initialization failed?\n"));
85 65 : if (sizeof key != read(urandom_d, key, sizeof key)) {
86 0 : return 0;
87 : }
88 65 : return NaClSecureRngCtorCommon(self, key);
89 : }
90 :
91 : int NaClSecureRngTestingCtor(struct NaClSecureRng *self,
92 : uint8_t *seed_material,
93 1 : size_t seed_bytes) {
94 : unsigned char key[AES_BLOCK_SIZE];
95 :
96 1 : self->base.vtbl = NULL;
97 1 : memset(key, 0, sizeof key);
98 1 : memcpy(key, seed_material, seed_bytes > sizeof key ? sizeof key : seed_bytes);
99 1 : return NaClSecureRngCtorCommon(self, key);
100 : }
101 :
102 31 : static void NaClSecureRngDtor(struct NaClSecureRngIf *self) {
103 31 : memset(self, 0, sizeof(struct NaClSecureRng));
104 : /* self->base.vtbl = NULL; */
105 31 : }
106 :
107 182994 : static void NaClSecureRngCycle(struct NaClSecureRng *self) {
108 : int ix;
109 :
110 182994 : AES_encrypt(self->counter, self->randbytes, &self->expanded_key);
111 182994 : self->nvalid = NACL_RANDOM_EXPOSE_BYTES;
112 : /*
113 : * odometric counter, low probability of carry, and byte order
114 : * independent as opposed to loading as words, incrementing, and
115 : * storing back, etc.
116 : *
117 : * counter value v = \sum_{i=0}{AES_BLOCK_SIZE-1} self->counter[i] * 256^{i}
118 : */
119 183710 : for (ix = 0; ix < AES_BLOCK_SIZE; ++ix) {
120 183710 : if (0 != ++self->counter[ix]) {
121 182994 : break;
122 : }
123 : }
124 182994 : }
125 :
126 1463940 : static uint8_t NaClSecureRngGenByte(struct NaClSecureRngIf *vself) {
127 1463940 : struct NaClSecureRng *self = (struct NaClSecureRng *) vself;
128 :
129 1463940 : if (self->nvalid <= 0) {
130 182994 : NaClSecureRngCycle(self);
131 : }
132 : /*
133 : * 0 < self->nvalid <= NACL_RANDOM_EXPOSE_BYTES <= AES_BLOCK_SIZE
134 : */
135 1463940 : return (char) self->randbytes[--self->nvalid];
136 : }
137 :
138 : #else
139 :
140 : int NaClSecureRngCtor(struct NaClSecureRng *self) {
141 : self->base.vtbl = &kNaClSecureRngVtbl;
142 : self->nvalid = 0;
143 : return 1;
144 : }
145 :
146 : int NaClSecureRngTestingCtor(struct NaClSecureRng *self,
147 : uint8_t *seed_material,
148 : size_t seed_bytes) {
149 : UNREFERENCED_PARAMETER(self);
150 : UNREFERENCED_PARAMETER(seed_material);
151 : UNREFERENCED_PARAMETER(seed_bytes);
152 : return 0;
153 : }
154 :
155 : static void NaClSecureRngDtor(struct NaClSecureRngIf *vself) {
156 : vself->vtbl = NULL;
157 : return;
158 : }
159 :
160 : static void NaClSecureRngFilbuf(struct NaClSecureRng *self) {
161 : VCHECK(-1 != urandom_d,
162 : ("NaClSecureRngCtor: random descriptor invalid;"
163 : " module initialization failed?\n"));
164 : self->nvalid = read(urandom_d, self->buf, sizeof self->buf);
165 : if (self->nvalid <= 0) {
166 : NaClLog(LOG_FATAL, "NaClSecureRngFilbuf failed, read returned %d\n",
167 : self->nvalid);
168 : }
169 : }
170 :
171 : static uint8_t NaClSecureRngGenByte(struct NaClSecureRngIf *vself) {
172 : struct NaClSecureRng *self = (struct NaClSecureRng *) vself;
173 :
174 : if (0 > self->nvalid) {
175 : NaClLog(LOG_FATAL,
176 : "NaClSecureRngGenByte: illegal buffer state, nvalid = %d\n",
177 : self->nvalid);
178 : }
179 : if (0 == self->nvalid) {
180 : NaClSecureRngFilbuf(self);
181 : }
182 : /* 0 < self->nvalid <= sizeof self->buf */
183 : return self->buf[--self->nvalid];
184 : }
185 :
186 : #endif
187 :
188 : static struct NaClSecureRngIfVtbl const kNaClSecureRngVtbl = {
189 : NaClSecureRngDtor,
190 : NaClSecureRngGenByte,
191 : NaClSecureRngDefaultGenUint32,
192 : NaClSecureRngDefaultGenBytes,
193 : NaClSecureRngDefaultUniform,
194 : };
|