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_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 <string.h> 34#include "avassert.h" 35#include "internal.h" 36#include "intreadwrite.h" 37#include "timer.h" 38#include "random_seed.h" 39#include "sha.h" 40 41#ifndef TEST 42#define TEST 0 43#endif 44 45static int read_random(uint32_t *dst, const char *file) 46{ 47#if HAVE_UNISTD_H 48 int fd = avpriv_open(file, O_RDONLY); 49 int err = -1; 50 51 if (fd == -1) 52 return -1; 53 err = read(fd, dst, sizeof(*dst)); 54 close(fd); 55 56 return err; 57#else 58 return -1; 59#endif 60} 61 62static uint32_t get_generic_seed(void) 63{ 64 uint8_t tmp[120]; 65 struct AVSHA *sha = (void*)tmp; 66 clock_t last_t = 0; 67 static uint64_t i = 0; 68 static uint32_t buffer[512] = { 0 }; 69 unsigned char digest[20]; 70 uint64_t last_i = i; 71 72 av_assert0(sizeof(tmp) >= av_sha_size); 73 74 if(TEST){ 75 memset(buffer, 0, sizeof(buffer)); 76 last_i = i = 0; 77 }else{ 78#ifdef AV_READ_TIME 79 buffer[13] ^= AV_READ_TIME(); 80 buffer[41] ^= AV_READ_TIME()>>32; 81#endif 82 } 83 84 for (;;) { 85 clock_t t = clock(); 86 87 if (last_t == t) { 88 buffer[i & 511]++; 89 } else { 90 buffer[++i & 511] += (t - last_t) % 3294638521U; 91 if (last_i && i - last_i > 4 || i - last_i > 64 || TEST && i - last_i > 8) 92 break; 93 } 94 last_t = t; 95 } 96 97 if(TEST) 98 buffer[0] = buffer[1] = 0; 99 100 av_sha_init(sha, 160); 101 av_sha_update(sha, (const uint8_t *)buffer, sizeof(buffer)); 102 av_sha_final(sha, digest); 103 return AV_RB32(digest) + AV_RB32(digest + 16); 104} 105 106uint32_t av_get_random_seed(void) 107{ 108 uint32_t seed; 109 110#if HAVE_CRYPTGENRANDOM 111 HCRYPTPROV provider; 112 if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, 113 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { 114 BOOL ret = CryptGenRandom(provider, sizeof(seed), (PBYTE) &seed); 115 CryptReleaseContext(provider, 0); 116 if (ret) 117 return seed; 118 } 119#endif 120 121 if (read_random(&seed, "/dev/urandom") == sizeof(seed)) 122 return seed; 123 if (read_random(&seed, "/dev/random") == sizeof(seed)) 124 return seed; 125 return get_generic_seed(); 126} 127 128#if TEST 129#undef printf 130#define N 256 131#include <stdio.h> 132 133int main(void) 134{ 135 int i, j, retry; 136 uint32_t seeds[N]; 137 138 for (retry=0; retry<3; retry++){ 139 for (i=0; i<N; i++){ 140 seeds[i] = av_get_random_seed(); 141 for (j=0; j<i; j++) 142 if (seeds[j] == seeds[i]) 143 goto retry; 144 } 145 printf("seeds OK\n"); 146 return 0; 147 retry:; 148 } 149 printf("FAIL at %d with %X\n", j, seeds[j]); 150 return 1; 151} 152#endif 153