Line data Source code
1 : /*
2 : * Copyright (c) 2009 Baptiste Coudurier <baptiste.coudurier@gmail.com>
3 : *
4 : * This file is part of Libav.
5 : *
6 : * Libav 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 : * Libav 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 Libav; 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_CRYPTGENRANDOM
27 : #include <windows.h>
28 : #include <wincrypt.h>
29 : #endif
30 : #include <fcntl.h>
31 : #include <math.h>
32 : #include <time.h>
33 : #include "internal.h"
34 : #include "intreadwrite.h"
35 : #include "mem.h"
36 : #include "timer.h"
37 : #include "random_seed.h"
38 : #include "sha.h"
39 :
40 0 : static int read_random(uint32_t *dst, const char *file)
41 : {
42 : #if HAVE_UNISTD_H
43 0 : int fd = avpriv_open(file, O_RDONLY);
44 0 : int err = -1;
45 :
46 0 : if (fd == -1)
47 0 : return -1;
48 0 : err = read(fd, dst, sizeof(*dst));
49 0 : close(fd);
50 :
51 0 : return err;
52 : #else
53 : return -1;
54 : #endif
55 : }
56 :
57 0 : static uint32_t get_generic_seed(void)
58 : {
59 0 : struct AVSHA *sha = av_sha_alloc();
60 0 : clock_t last_t = 0;
61 : static uint64_t i = 0;
62 : static uint32_t buffer[512] = { 0 };
63 : unsigned char digest[20];
64 0 : uint64_t last_i = i;
65 :
66 0 : for (;;) {
67 0 : clock_t t = clock();
68 :
69 0 : if (last_t == t) {
70 0 : buffer[i & 511]++;
71 : } else {
72 0 : buffer[++i & 511] += (t - last_t) % 3294638521U;
73 0 : if (last_i && i - last_i > 4 || i - last_i > 64)
74 : break;
75 : }
76 0 : last_t = t;
77 : }
78 :
79 0 : if (!sha) {
80 0 : uint32_t seed = 0;
81 : int j;
82 : // Unable to allocate an sha context, just xor the buffer together
83 : // to create something hopefully unique.
84 0 : for (j = 0; j < 512; j++)
85 0 : seed ^= buffer[j];
86 0 : return seed;
87 : }
88 0 : av_sha_init(sha, 160);
89 0 : av_sha_update(sha, (const uint8_t *) buffer, sizeof(buffer));
90 0 : av_sha_final(sha, digest);
91 0 : av_free(sha);
92 0 : return AV_RB32(digest) + AV_RB32(digest + 16);
93 : }
94 :
95 0 : uint32_t av_get_random_seed(void)
96 : {
97 : uint32_t seed;
98 :
99 : #if HAVE_CRYPTGENRANDOM
100 : HCRYPTPROV provider;
101 : if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
102 : CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
103 : BOOL ret = CryptGenRandom(provider, sizeof(seed), (PBYTE) &seed);
104 : CryptReleaseContext(provider, 0);
105 : if (ret)
106 : return seed;
107 : }
108 : #endif
109 :
110 0 : if (read_random(&seed, "/dev/urandom") == sizeof(seed))
111 0 : return seed;
112 0 : if (read_random(&seed, "/dev/random") == sizeof(seed))
113 0 : return seed;
114 0 : return get_generic_seed();
115 : }
|