2 * Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com>
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
36 #include <openssl/rand.h>
43 #include "file_open.h"
45 #include "intreadwrite.h"
47 #include "random_seed.h"
54 static int read_random(uint8_t *dst
, size_t len
, const char *file
)
57 FILE *fp
= avpriv_fopen_utf8(file
, "r");
61 return AVERROR_UNKNOWN
;
62 setvbuf(fp
, NULL
, _IONBF
, 0);
63 err
= fread(dst
, 1, len
, fp
);
67 return AVERROR_UNKNOWN
;
71 return AVERROR(ENOSYS
);
75 static uint32_t get_generic_seed(void)
78 struct AVSHA
*sha
= (void*)tmp
;
82 static uint64_t i
= 0;
83 static uint32_t buffer
[512] = { 0 };
84 unsigned char digest
[20];
86 int repeats
[3] = { 0 };
88 av_assert0(sizeof(tmp
) >= av_sha_size
);
91 memset(buffer
, 0, sizeof(buffer
));
95 buffer
[13] ^= AV_READ_TIME();
96 buffer
[41] ^= AV_READ_TIME()>>32;
102 int incremented_i
= 0;
103 int cur_td
= t
- last_t
;
104 if (last_t
+ 2*last_td
+ (CLOCKS_PER_SEC
> 1000) < t
) {
105 // If the timer incremented by more than 2*last_td at once,
106 // we may e.g. have had a context switch. If the timer resolution
107 // is high (CLOCKS_PER_SEC > 1000), require that the timer
108 // incremented by more than 1. If the timer resolution is low,
109 // it is enough that the timer incremented at all.
110 buffer
[++i
& 511] += cur_td
% 3294638521U;
112 } else if (t
!= last_t
&& repeats
[0] > 0 && repeats
[1] > 0 &&
113 repeats
[2] > 0 && repeats
[0] != repeats
[1] &&
114 repeats
[0] != repeats
[2]) {
115 // If the timer resolution is high, and we get the same timer
116 // value multiple times, use variances in the number of repeats
117 // of each timer value as entropy. If we get a different number of
118 // repeats than the last two unique cases, count that as entropy
119 // and proceed to the next index.
120 buffer
[++i
& 511] += (repeats
[0] + repeats
[1] + repeats
[2]) % 3294638521U;
123 buffer
[i
& 511] = 1664525*buffer
[i
& 511] + 1013904223 + (cur_td
% 3294638521U);
125 if (incremented_i
&& (t
- init_t
) >= CLOCKS_PER_SEC
>>5) {
126 if (last_i
&& i
- last_i
> 4 || i
- last_i
> 64 || TEST
&& i
- last_i
> 8)
132 // If we got a new unique number of repeats, update the history.
133 if (repeats
[0] != repeats
[1]) {
134 repeats
[2] = repeats
[1];
135 repeats
[1] = repeats
[0];
146 buffer
[0] = buffer
[1] = 0;
149 buffer
[111] += AV_READ_TIME();
153 av_sha_init(sha
, 160);
154 av_sha_update(sha
, (const uint8_t *)buffer
, sizeof(buffer
));
155 av_sha_final(sha
, digest
);
156 return AV_RB32(digest
) + AV_RB32(digest
+ 16);
159 int av_random_bytes(uint8_t* buf
, size_t len
)
164 BCRYPT_ALG_HANDLE algo_handle
;
165 NTSTATUS ret
= BCryptOpenAlgorithmProvider(&algo_handle
, BCRYPT_RNG_ALGORITHM
,
166 MS_PRIMITIVE_PROVIDER
, 0);
167 if (BCRYPT_SUCCESS(ret
)) {
168 NTSTATUS ret
= BCryptGenRandom(algo_handle
, (PUCHAR
)buf
, len
, 0);
169 BCryptCloseAlgorithmProvider(algo_handle
, 0);
170 if (BCRYPT_SUCCESS(ret
))
175 #if HAVE_ARC4RANDOM_BUF
176 arc4random_buf(buf
, len
);
180 err
= read_random(buf
, len
, "/dev/urandom");
185 gcry_randomize(buf
, len
, GCRY_VERY_STRONG_RANDOM
);
188 if (RAND_bytes(buf
, len
) == 1)
190 return AVERROR_EXTERNAL
;
196 uint32_t av_get_random_seed(void)
200 if (av_random_bytes((uint8_t *)&seed
, sizeof(seed
)) < 0)
201 return get_generic_seed();