blob: d1c9a3f7046d7efada2e11194819e113ab0f6bb7
1 | /* |
2 | * Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com> |
3 | * |
4 | * This file is part of FFmpeg. |
5 | * |
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. |
10 | * |
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. |
15 | * |
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 |
19 | */ |
20 | |
21 | #include "config.h" |
22 | |
23 | #if HAVE_UNISTD_H |
24 | #include <unistd.h> |
25 | #endif |
26 | #if HAVE_IO_H |
27 | #include <io.h> |
28 | #endif |
29 | #if HAVE_CRYPTGENRANDOM |
30 | #include <windows.h> |
31 | #include <wincrypt.h> |
32 | #endif |
33 | #include <fcntl.h> |
34 | #include <math.h> |
35 | #include <time.h> |
36 | #include <string.h> |
37 | #include "avassert.h" |
38 | #include "internal.h" |
39 | #include "intreadwrite.h" |
40 | #include "timer.h" |
41 | #include "random_seed.h" |
42 | #include "sha.h" |
43 | |
44 | #ifndef TEST |
45 | #define TEST 0 |
46 | #endif |
47 | |
48 | static int read_random(uint32_t *dst, const char *file) |
49 | { |
50 | #if HAVE_UNISTD_H |
51 | int fd = avpriv_open(file, O_RDONLY); |
52 | int err = -1; |
53 | |
54 | if (fd == -1) |
55 | return -1; |
56 | err = read(fd, dst, sizeof(*dst)); |
57 | close(fd); |
58 | |
59 | return err; |
60 | #else |
61 | return -1; |
62 | #endif |
63 | } |
64 | |
65 | static uint32_t get_generic_seed(void) |
66 | { |
67 | uint64_t tmp[120/8]; |
68 | struct AVSHA *sha = (void*)tmp; |
69 | clock_t last_t = 0; |
70 | clock_t last_td = 0; |
71 | clock_t init_t = 0; |
72 | static uint64_t i = 0; |
73 | static uint32_t buffer[512] = { 0 }; |
74 | unsigned char digest[20]; |
75 | uint64_t last_i = i; |
76 | |
77 | av_assert0(sizeof(tmp) >= av_sha_size); |
78 | |
79 | if(TEST){ |
80 | memset(buffer, 0, sizeof(buffer)); |
81 | last_i = i = 0; |
82 | }else{ |
83 | #ifdef AV_READ_TIME |
84 | buffer[13] ^= AV_READ_TIME(); |
85 | buffer[41] ^= AV_READ_TIME()>>32; |
86 | #endif |
87 | } |
88 | |
89 | for (;;) { |
90 | clock_t t = clock(); |
91 | if (last_t + 2*last_td + (CLOCKS_PER_SEC > 1000) >= t) { |
92 | last_td = t - last_t; |
93 | buffer[i & 511] = 1664525*buffer[i & 511] + 1013904223 + (last_td % 3294638521U); |
94 | } else { |
95 | last_td = t - last_t; |
96 | buffer[++i & 511] += last_td % 3294638521U; |
97 | if ((t - init_t) >= CLOCKS_PER_SEC>>5) |
98 | if (last_i && i - last_i > 4 || i - last_i > 64 || TEST && i - last_i > 8) |
99 | break; |
100 | } |
101 | last_t = t; |
102 | if (!init_t) |
103 | init_t = t; |
104 | } |
105 | |
106 | if(TEST) { |
107 | buffer[0] = buffer[1] = 0; |
108 | } else { |
109 | #ifdef AV_READ_TIME |
110 | buffer[111] += AV_READ_TIME(); |
111 | #endif |
112 | } |
113 | |
114 | av_sha_init(sha, 160); |
115 | av_sha_update(sha, (const uint8_t *)buffer, sizeof(buffer)); |
116 | av_sha_final(sha, digest); |
117 | return AV_RB32(digest) + AV_RB32(digest + 16); |
118 | } |
119 | |
120 | uint32_t av_get_random_seed(void) |
121 | { |
122 | uint32_t seed; |
123 | |
124 | #if HAVE_CRYPTGENRANDOM |
125 | HCRYPTPROV provider; |
126 | if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, |
127 | CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { |
128 | BOOL ret = CryptGenRandom(provider, sizeof(seed), (PBYTE) &seed); |
129 | CryptReleaseContext(provider, 0); |
130 | if (ret) |
131 | return seed; |
132 | } |
133 | #endif |
134 | |
135 | #if HAVE_ARC4RANDOM |
136 | return arc4random(); |
137 | #endif |
138 | |
139 | if (read_random(&seed, "/dev/urandom") == sizeof(seed)) |
140 | return seed; |
141 | if (read_random(&seed, "/dev/random") == sizeof(seed)) |
142 | return seed; |
143 | return get_generic_seed(); |
144 | } |
145 |