|
@@ -10,9 +10,69 @@
|
10
|
10
|
FILE_LICENCE ( GPL2_OR_LATER );
|
11
|
11
|
|
12
|
12
|
#include <stdint.h>
|
|
13
|
+#include <string.h>
|
13
|
14
|
#include <assert.h>
|
|
15
|
+#include <ipxe/api.h>
|
|
16
|
+#include <ipxe/hash_df.h>
|
|
17
|
+#include <config/entropy.h>
|
14
|
18
|
|
15
|
|
-/** min-entropy per entropy sample
|
|
19
|
+/**
|
|
20
|
+ * Calculate static inline entropy API function name
|
|
21
|
+ *
|
|
22
|
+ * @v _prefix Subsystem prefix
|
|
23
|
+ * @v _api_func API function
|
|
24
|
+ * @ret _subsys_func Subsystem API function
|
|
25
|
+ */
|
|
26
|
+#define ENTROPY_INLINE( _subsys, _api_func ) \
|
|
27
|
+ SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func )
|
|
28
|
+
|
|
29
|
+/**
|
|
30
|
+ * Provide a entropy API implementation
|
|
31
|
+ *
|
|
32
|
+ * @v _prefix Subsystem prefix
|
|
33
|
+ * @v _api_func API function
|
|
34
|
+ * @v _func Implementing function
|
|
35
|
+ */
|
|
36
|
+#define PROVIDE_ENTROPY( _subsys, _api_func, _func ) \
|
|
37
|
+ PROVIDE_SINGLE_API ( ENTROPY_PREFIX_ ## _subsys, _api_func, _func )
|
|
38
|
+
|
|
39
|
+/**
|
|
40
|
+ * Provide a static inline entropy API implementation
|
|
41
|
+ *
|
|
42
|
+ * @v _prefix Subsystem prefix
|
|
43
|
+ * @v _api_func API function
|
|
44
|
+ */
|
|
45
|
+#define PROVIDE_ENTROPY_INLINE( _subsys, _api_func ) \
|
|
46
|
+ PROVIDE_SINGLE_API_INLINE ( ENTROPY_PREFIX_ ## _subsys, _api_func )
|
|
47
|
+
|
|
48
|
+/** A noise sample */
|
|
49
|
+typedef uint8_t noise_sample_t;
|
|
50
|
+
|
|
51
|
+/** An entropy sample */
|
|
52
|
+typedef uint8_t entropy_sample_t;
|
|
53
|
+
|
|
54
|
+/* Include all architecture-independent entropy API headers */
|
|
55
|
+#include <ipxe/null_entropy.h>
|
|
56
|
+
|
|
57
|
+/* Include all architecture-dependent entropy API headers */
|
|
58
|
+#include <bits/entropy.h>
|
|
59
|
+
|
|
60
|
+/**
|
|
61
|
+ * Enable entropy gathering
|
|
62
|
+ *
|
|
63
|
+ */
|
|
64
|
+void entropy_enable ( void );
|
|
65
|
+
|
|
66
|
+/**
|
|
67
|
+ * Disable entropy gathering
|
|
68
|
+ *
|
|
69
|
+ */
|
|
70
|
+void entropy_disable ( void );
|
|
71
|
+
|
|
72
|
+/**
|
|
73
|
+ * min-entropy per sample
|
|
74
|
+ *
|
|
75
|
+ * @ret min_entropy min-entropy of each sample
|
16
|
76
|
*
|
17
|
77
|
* min-entropy is defined in ANS X9.82 Part 1-2006 Section 8.3 and in
|
18
|
78
|
* NIST SP 800-90 Appendix C.3 as
|
|
@@ -20,71 +80,125 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
20
|
80
|
* H_min = -log2 ( p_max )
|
21
|
81
|
*
|
22
|
82
|
* where p_max is the probability of the most likely sample value.
|
|
83
|
+ *
|
|
84
|
+ * This must be a compile-time constant.
|
23
|
85
|
*/
|
24
|
|
-#define MIN_ENTROPY_PER_SAMPLE 0.16
|
|
86
|
+double min_entropy_per_sample ( void );
|
25
|
87
|
|
26
|
|
-/** Length of each entropy sample (in bits) */
|
27
|
|
-#define ENTROPY_SAMPLE_LEN_BITS 12
|
|
88
|
+/**
|
|
89
|
+ * Get noise sample
|
|
90
|
+ *
|
|
91
|
+ * @ret noise Noise sample
|
|
92
|
+ * @ret rc Return status code
|
|
93
|
+ *
|
|
94
|
+ * This is the GetNoise function defined in ANS X9.82 Part 2
|
|
95
|
+ * (October 2011 Draft) Section 6.5.2.
|
|
96
|
+ */
|
|
97
|
+int get_noise ( noise_sample_t *noise );
|
|
98
|
+
|
|
99
|
+extern int get_entropy_input_tmp ( unsigned int num_samples,
|
|
100
|
+ uint8_t *tmp, size_t tmp_len );
|
28
|
101
|
|
29
|
102
|
/**
|
30
|
|
- * Calculate entropy buffer size
|
|
103
|
+ * Obtain entropy input
|
|
104
|
+ *
|
|
105
|
+ * @v min_entropy_bits Minimum amount of entropy, in bits
|
|
106
|
+ * @v data Data buffer
|
|
107
|
+ * @v min_len Minimum length of entropy input, in bytes
|
|
108
|
+ * @v max_len Maximum length of entropy input, in bytes
|
|
109
|
+ * @ret len Length of entropy input, in bytes, or negative error
|
31
|
110
|
*
|
32
|
|
- * @v entropy_bits Amount of entropy required, in bits
|
33
|
|
- * @v min_len Minimum buffer size, in bytes
|
34
|
|
- * @v max_len Maximum buffer size, in bytes
|
35
|
|
- * @ret len Buffer size, in bytes
|
|
111
|
+ * This is the implementation of the Get_entropy_input function (using
|
|
112
|
+ * an entropy source as the source of entropy input and condensing
|
|
113
|
+ * each entropy source output after each GetEntropy call) as defined
|
|
114
|
+ * in ANS X9.82 Part 4 (April 2011 Draft) Section 13.3.4.2.
|
|
115
|
+ *
|
|
116
|
+ * To minimise code size, the number of samples required is calculated
|
|
117
|
+ * at compilation time.
|
36
|
118
|
*/
|
37
|
|
-static inline __attribute__ (( const, always_inline )) size_t
|
38
|
|
-entropy_bufsize ( unsigned int entropy_bits, size_t min_len, size_t max_len ) {
|
39
|
|
- unsigned int min_len_bits;
|
|
119
|
+static inline __attribute__ (( always_inline )) int
|
|
120
|
+get_entropy_input ( unsigned int min_entropy_bits, void *data, size_t min_len,
|
|
121
|
+ size_t max_len ) {
|
|
122
|
+ size_t tmp_len = ( ( ( min_entropy_bits * 2 ) + 7 ) / 8 );
|
|
123
|
+ uint8_t tmp_buf[ tmp_len ];
|
|
124
|
+ uint8_t *tmp = ( ( tmp_len > max_len ) ? tmp_buf : data );
|
40
|
125
|
double min_samples;
|
41
|
|
- double samples;
|
42
|
|
- unsigned int samples_int;
|
43
|
|
- unsigned int len_bits;
|
44
|
|
- size_t len;
|
|
126
|
+ unsigned int num_samples;
|
|
127
|
+ unsigned int n;
|
|
128
|
+ int rc;
|
45
|
129
|
|
46
|
|
- /* Sanity check */
|
47
|
|
- linker_assert ( MIN_ENTROPY_PER_SAMPLE <= ENTROPY_SAMPLE_LEN_BITS,
|
|
130
|
+ /* Sanity checks */
|
|
131
|
+ linker_assert ( ( min_entropy_per_sample() <=
|
|
132
|
+ ( 8 * sizeof ( noise_sample_t ) ) ),
|
48
|
133
|
min_entropy_per_sample_is_impossibly_high );
|
|
134
|
+ linker_assert ( ( min_entropy_bits <= ( 8 * max_len ) ),
|
|
135
|
+ entropy_buffer_too_small );
|
49
|
136
|
|
50
|
|
- /* Calculate number of samples required to contain sufficient entropy */
|
51
|
|
- samples = ( ( entropy_bits * 1.0 ) / MIN_ENTROPY_PER_SAMPLE );
|
|
137
|
+ /* Round up minimum entropy to an integral number of bytes */
|
|
138
|
+ min_entropy_bits = ( ( min_entropy_bits + 7 ) & ~7 );
|
52
|
139
|
|
53
|
|
- /* Increase to minimum length if necessary */
|
54
|
|
- min_len_bits = ( min_len * 8 );
|
55
|
|
- min_samples = ( ( min_len_bits * 1.0 ) / ENTROPY_SAMPLE_LEN_BITS );
|
56
|
|
- if ( samples < min_samples )
|
57
|
|
- samples = min_samples;
|
|
140
|
+ /* Calculate number of samples required to contain sufficient entropy */
|
|
141
|
+ min_samples = ( ( min_entropy_bits * 1.0 ) / min_entropy_per_sample() );
|
58
|
142
|
|
59
|
143
|
/* Round up to a whole number of samples. We don't have the
|
60
|
144
|
* ceil() function available, so do the rounding by hand.
|
61
|
145
|
*/
|
62
|
|
- samples_int = samples;
|
63
|
|
- if ( samples_int < samples )
|
64
|
|
- samples_int++;
|
65
|
|
- assert ( samples_int >= samples );
|
66
|
|
-
|
67
|
|
- /* Calculate buffer length in bits */
|
68
|
|
- len_bits = ( samples_int * ENTROPY_SAMPLE_LEN_BITS );
|
69
|
|
-
|
70
|
|
- /* Calculate buffer length in bytes (rounding up) */
|
71
|
|
- len = ( ( len_bits + 7 ) / 8 );
|
72
|
|
-
|
73
|
|
- /* Check that buffer is within allowed lengths */
|
74
|
|
- linker_assert ( len >= min_len, entropy_bufsize_too_short );
|
75
|
|
- linker_assert ( len <= max_len, entropy_bufsize_too_long );
|
|
146
|
+ num_samples = min_samples;
|
|
147
|
+ if ( num_samples < min_samples )
|
|
148
|
+ num_samples++;
|
|
149
|
+ linker_assert ( ( num_samples >= min_samples ), rounding_error );
|
76
|
150
|
|
77
|
151
|
/* Floating-point operations are not allowed in iPXE since we
|
78
|
152
|
* never set up a suitable environment. Abort the build
|
79
|
|
- * unless the calculated length is a compile-time constant.
|
|
153
|
+ * unless the calculated number of samples is a compile-time
|
|
154
|
+ * constant.
|
80
|
155
|
*/
|
81
|
|
- linker_assert ( __builtin_constant_p ( len ),
|
82
|
|
- entropy_bufsize_not_constant );
|
83
|
|
-
|
84
|
|
- return len;
|
|
156
|
+ linker_assert ( __builtin_constant_p ( num_samples ),
|
|
157
|
+ num_samples_not_constant );
|
|
158
|
+
|
|
159
|
+ /* 1. If ( min_length > max_length ), then return ( FAILURE, Null ) */
|
|
160
|
+ linker_assert ( ( min_len <= max_len ), min_len_greater_than_max_len );
|
|
161
|
+
|
|
162
|
+ /* 2. n = 2 * min_entropy */
|
|
163
|
+ n = ( 2 * min_entropy_bits );
|
|
164
|
+
|
|
165
|
+ /* 3. entropy_total = 0
|
|
166
|
+ * 4. tmp = a fixed n-bit value, such as 0^n
|
|
167
|
+ * 5. While ( entropy_total < min_entropy )
|
|
168
|
+ * 5.1. ( status, entropy_bitstring, assessed_entropy )
|
|
169
|
+ * = GetEntropy()
|
|
170
|
+ * 5.2. If status indicates an error, return ( status, Null )
|
|
171
|
+ * 5.3. nonce = MakeNextNonce()
|
|
172
|
+ * 5.4. tmp = tmp XOR df ( ( nonce || entropy_bitstring ), n )
|
|
173
|
+ * 5.5. entropy_total = entropy_total + assessed_entropy
|
|
174
|
+ *
|
|
175
|
+ * (The implementation of these steps is inside the function
|
|
176
|
+ * get_entropy_input_tmp().)
|
|
177
|
+ */
|
|
178
|
+ linker_assert ( __builtin_constant_p ( tmp_len ),
|
|
179
|
+ tmp_len_not_constant );
|
|
180
|
+ linker_assert ( ( n == ( 8 * tmp_len ) ), tmp_len_mismatch );
|
|
181
|
+ if ( ( rc = get_entropy_input_tmp ( num_samples, tmp, tmp_len ) ) != 0 )
|
|
182
|
+ return rc;
|
|
183
|
+
|
|
184
|
+ /* 6. If ( n < min_length ), then tmp = tmp || 0^(min_length-n)
|
|
185
|
+ * 7. If ( n > max_length ), then tmp = df ( tmp, max_length )
|
|
186
|
+ * 8. Return ( SUCCESS, tmp )
|
|
187
|
+ */
|
|
188
|
+ if ( tmp_len < min_len ) {
|
|
189
|
+ /* (Data is already in-place.) */
|
|
190
|
+ linker_assert ( ( data == tmp ), data_not_inplace );
|
|
191
|
+ memset ( ( data + tmp_len ), 0, ( min_len - tmp_len ) );
|
|
192
|
+ return min_len;
|
|
193
|
+ } else if ( tmp_len > max_len ) {
|
|
194
|
+ linker_assert ( ( tmp == tmp_buf ), data_inplace );
|
|
195
|
+ hash_df ( tmp, tmp_len, data, max_len );
|
|
196
|
+ return max_len;
|
|
197
|
+ } else {
|
|
198
|
+ /* (Data is already in-place.) */
|
|
199
|
+ linker_assert ( ( data == tmp ), data_not_inplace );
|
|
200
|
+ return tmp_len;
|
|
201
|
+ }
|
85
|
202
|
}
|
86
|
203
|
|
87
|
|
-extern int get_entropy_input ( unsigned int entropy_bits, void *data,
|
88
|
|
- size_t min_len, size_t max_len );
|
89
|
|
-
|
90
|
204
|
#endif /* _IPXE_ENTROPY_H */
|