xref: /reactos/dll/3rdparty/mbedtls/havege.c (revision 218e2596)
1 /**
2  *  \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion
3  *
4  *  Copyright The Mbed TLS Contributors
5  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6  *
7  *  This file is provided under the Apache License 2.0, or the
8  *  GNU General Public License v2.0 or later.
9  *
10  *  **********
11  *  Apache License 2.0:
12  *
13  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
14  *  not use this file except in compliance with the License.
15  *  You may obtain a copy of the License at
16  *
17  *  http://www.apache.org/licenses/LICENSE-2.0
18  *
19  *  Unless required by applicable law or agreed to in writing, software
20  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
21  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  *  See the License for the specific language governing permissions and
23  *  limitations under the License.
24  *
25  *  **********
26  *
27  *  **********
28  *  GNU General Public License v2.0 or later:
29  *
30  *  This program is free software; you can redistribute it and/or modify
31  *  it under the terms of the GNU General Public License as published by
32  *  the Free Software Foundation; either version 2 of the License, or
33  *  (at your option) any later version.
34  *
35  *  This program is distributed in the hope that it will be useful,
36  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
37  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
38  *  GNU General Public License for more details.
39  *
40  *  You should have received a copy of the GNU General Public License along
41  *  with this program; if not, write to the Free Software Foundation, Inc.,
42  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
43  *
44  *  **********
45  */
46 /*
47  *  The HAVEGE RNG was designed by Andre Seznec in 2002.
48  *
49  *  http://www.irisa.fr/caps/projects/hipsor/publi.php
50  *
51  *  Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr
52  */
53 
54 #if !defined(MBEDTLS_CONFIG_FILE)
55 #include "mbedtls/config.h"
56 #else
57 #include MBEDTLS_CONFIG_FILE
58 #endif
59 
60 #if defined(MBEDTLS_HAVEGE_C)
61 
62 #include "mbedtls/havege.h"
63 #include "mbedtls/timing.h"
64 
65 #include <limits.h>
66 #include <string.h>
67 
68 /* If int isn't capable of storing 2^32 distinct values, the code of this
69  * module may cause a processor trap or a miscalculation. If int is more
70  * than 32 bits, the code may not calculate the intended values. */
71 #if INT_MIN + 1 != -0x7fffffff
72 #error "The HAVEGE module requires int to be exactly 32 bits, with INT_MIN = -2^31."
73 #endif
74 #if UINT_MAX != 0xffffffff
75 #error "The HAVEGE module requires unsigned to be exactly 32 bits."
76 #endif
77 
78 /* Implementation that should never be optimized out by the compiler */
79 static void mbedtls_zeroize( void *v, size_t n ) {
80     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
81 }
82 
83 /* ------------------------------------------------------------------------
84  * On average, one iteration accesses two 8-word blocks in the havege WALK
85  * table, and generates 16 words in the RES array.
86  *
87  * The data read in the WALK table is updated and permuted after each use.
88  * The result of the hardware clock counter read is used  for this update.
89  *
90  * 25 conditional tests are present.  The conditional tests are grouped in
91  * two nested  groups of 12 conditional tests and 1 test that controls the
92  * permutation; on average, there should be 6 tests executed and 3 of them
93  * should be mispredicted.
94  * ------------------------------------------------------------------------
95  */
96 
97 #define SWAP(X,Y) { unsigned *T = (X); (X) = (Y); (Y) = T; }
98 
99 #define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
100 #define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1;
101 
102 #define TST1_LEAVE U1++; }
103 #define TST2_LEAVE U2++; }
104 
105 #define ONE_ITERATION                                   \
106                                                         \
107     PTEST = PT1 >> 20;                                  \
108                                                         \
109     TST1_ENTER  TST1_ENTER  TST1_ENTER  TST1_ENTER      \
110     TST1_ENTER  TST1_ENTER  TST1_ENTER  TST1_ENTER      \
111     TST1_ENTER  TST1_ENTER  TST1_ENTER  TST1_ENTER      \
112                                                         \
113     TST1_LEAVE  TST1_LEAVE  TST1_LEAVE  TST1_LEAVE      \
114     TST1_LEAVE  TST1_LEAVE  TST1_LEAVE  TST1_LEAVE      \
115     TST1_LEAVE  TST1_LEAVE  TST1_LEAVE  TST1_LEAVE      \
116                                                         \
117     PTX = (PT1 >> 18) & 7;                              \
118     PT1 &= 0x1FFF;                                      \
119     PT2 &= 0x1FFF;                                      \
120     CLK = (unsigned) mbedtls_timing_hardclock();        \
121                                                         \
122     i = 0;                                              \
123     A = &WALK[PT1    ]; RES[i++] ^= *A;                 \
124     B = &WALK[PT2    ]; RES[i++] ^= *B;                 \
125     C = &WALK[PT1 ^ 1]; RES[i++] ^= *C;                 \
126     D = &WALK[PT2 ^ 4]; RES[i++] ^= *D;                 \
127                                                         \
128     IN = (*A >> (1)) ^ (*A << (31)) ^ CLK;              \
129     *A = (*B >> (2)) ^ (*B << (30)) ^ CLK;              \
130     *B = IN ^ U1;                                       \
131     *C = (*C >> (3)) ^ (*C << (29)) ^ CLK;              \
132     *D = (*D >> (4)) ^ (*D << (28)) ^ CLK;              \
133                                                         \
134     A = &WALK[PT1 ^ 2]; RES[i++] ^= *A;                 \
135     B = &WALK[PT2 ^ 2]; RES[i++] ^= *B;                 \
136     C = &WALK[PT1 ^ 3]; RES[i++] ^= *C;                 \
137     D = &WALK[PT2 ^ 6]; RES[i++] ^= *D;                 \
138                                                         \
139     if( PTEST & 1 ) SWAP( A, C );                       \
140                                                         \
141     IN = (*A >> (5)) ^ (*A << (27)) ^ CLK;              \
142     *A = (*B >> (6)) ^ (*B << (26)) ^ CLK;              \
143     *B = IN; CLK = (unsigned) mbedtls_timing_hardclock(); \
144     *C = (*C >> (7)) ^ (*C << (25)) ^ CLK;              \
145     *D = (*D >> (8)) ^ (*D << (24)) ^ CLK;              \
146                                                         \
147     A = &WALK[PT1 ^ 4];                                 \
148     B = &WALK[PT2 ^ 1];                                 \
149                                                         \
150     PTEST = PT2 >> 1;                                   \
151                                                         \
152     PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]);   \
153     PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8);  \
154     PTY = (PT2 >> 10) & 7;                              \
155                                                         \
156     TST2_ENTER  TST2_ENTER  TST2_ENTER  TST2_ENTER      \
157     TST2_ENTER  TST2_ENTER  TST2_ENTER  TST2_ENTER      \
158     TST2_ENTER  TST2_ENTER  TST2_ENTER  TST2_ENTER      \
159                                                         \
160     TST2_LEAVE  TST2_LEAVE  TST2_LEAVE  TST2_LEAVE      \
161     TST2_LEAVE  TST2_LEAVE  TST2_LEAVE  TST2_LEAVE      \
162     TST2_LEAVE  TST2_LEAVE  TST2_LEAVE  TST2_LEAVE      \
163                                                         \
164     C = &WALK[PT1 ^ 5];                                 \
165     D = &WALK[PT2 ^ 5];                                 \
166                                                         \
167     RES[i++] ^= *A;                                     \
168     RES[i++] ^= *B;                                     \
169     RES[i++] ^= *C;                                     \
170     RES[i++] ^= *D;                                     \
171                                                         \
172     IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK;             \
173     *A = (*B >> (10)) ^ (*B << (22)) ^ CLK;             \
174     *B = IN ^ U2;                                       \
175     *C = (*C >> (11)) ^ (*C << (21)) ^ CLK;             \
176     *D = (*D >> (12)) ^ (*D << (20)) ^ CLK;             \
177                                                         \
178     A = &WALK[PT1 ^ 6]; RES[i++] ^= *A;                 \
179     B = &WALK[PT2 ^ 3]; RES[i++] ^= *B;                 \
180     C = &WALK[PT1 ^ 7]; RES[i++] ^= *C;                 \
181     D = &WALK[PT2 ^ 7]; RES[i++] ^= *D;                 \
182                                                         \
183     IN = (*A >> (13)) ^ (*A << (19)) ^ CLK;             \
184     *A = (*B >> (14)) ^ (*B << (18)) ^ CLK;             \
185     *B = IN;                                            \
186     *C = (*C >> (15)) ^ (*C << (17)) ^ CLK;             \
187     *D = (*D >> (16)) ^ (*D << (16)) ^ CLK;             \
188                                                         \
189     PT1 = ( RES[( i - 8 ) ^ PTX] ^                      \
190             WALK[PT1 ^ PTX ^ 7] ) & (~1);               \
191     PT1 ^= (PT2 ^ 0x10) & 0x10;                         \
192                                                         \
193     for( n++, i = 0; i < 16; i++ )                      \
194         POOL[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i];
195 
196 /*
197  * Entropy gathering function
198  */
199 static void havege_fill( mbedtls_havege_state *hs )
200 {
201     unsigned i, n = 0;
202     unsigned  U1,  U2, *A, *B, *C, *D;
203     unsigned PT1, PT2, *WALK, *POOL, RES[16];
204     unsigned PTX, PTY, CLK, PTEST, IN;
205 
206     WALK = (unsigned *) hs->WALK;
207     POOL = (unsigned *) hs->pool;
208     PT1  = hs->PT1;
209     PT2  = hs->PT2;
210 
211     PTX  = U1 = 0;
212     PTY  = U2 = 0;
213 
214     (void)PTX;
215 
216     memset( RES, 0, sizeof( RES ) );
217 
218     while( n < MBEDTLS_HAVEGE_COLLECT_SIZE * 4 )
219     {
220         ONE_ITERATION
221         ONE_ITERATION
222         ONE_ITERATION
223         ONE_ITERATION
224     }
225 
226     hs->PT1 = PT1;
227     hs->PT2 = PT2;
228 
229     hs->offset[0] = 0;
230     hs->offset[1] = MBEDTLS_HAVEGE_COLLECT_SIZE / 2;
231 }
232 
233 /*
234  * HAVEGE initialization
235  */
236 void mbedtls_havege_init( mbedtls_havege_state *hs )
237 {
238     memset( hs, 0, sizeof( mbedtls_havege_state ) );
239 
240     havege_fill( hs );
241 }
242 
243 void mbedtls_havege_free( mbedtls_havege_state *hs )
244 {
245     if( hs == NULL )
246         return;
247 
248     mbedtls_zeroize( hs, sizeof( mbedtls_havege_state ) );
249 }
250 
251 /*
252  * HAVEGE rand function
253  */
254 int mbedtls_havege_random( void *p_rng, unsigned char *buf, size_t len )
255 {
256     int val;
257     size_t use_len;
258     mbedtls_havege_state *hs = (mbedtls_havege_state *) p_rng;
259     unsigned char *p = buf;
260 
261     while( len > 0 )
262     {
263         use_len = len;
264         if( use_len > sizeof(int) )
265             use_len = sizeof(int);
266 
267         if( hs->offset[1] >= MBEDTLS_HAVEGE_COLLECT_SIZE )
268             havege_fill( hs );
269 
270         val  = hs->pool[hs->offset[0]++];
271         val ^= hs->pool[hs->offset[1]++];
272 
273         memcpy( p, &val, use_len );
274 
275         len -= use_len;
276         p += use_len;
277     }
278 
279     return( 0 );
280 }
281 
282 #endif /* MBEDTLS_HAVEGE_C */
283