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_BCRYPT 30#include <windows.h> 31#include <bcrypt.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 48static 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 65static 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 120uint32_t av_get_random_seed(void) 121{ 122 uint32_t seed; 123 124#if HAVE_BCRYPT 125 BCRYPT_ALG_HANDLE algo_handle; 126 NTSTATUS ret = BCryptOpenAlgorithmProvider(&algo_handle, BCRYPT_RNG_ALGORITHM, 127 MS_PRIMITIVE_PROVIDER, 0); 128 if (BCRYPT_SUCCESS(ret)) { 129 NTSTATUS ret = BCryptGenRandom(algo_handle, (UCHAR*)&seed, sizeof(seed), 0); 130 BCryptCloseAlgorithmProvider(algo_handle, 0); 131 if (BCRYPT_SUCCESS(ret)) 132 return seed; 133 } 134#endif 135 136#if HAVE_ARC4RANDOM 137 return arc4random(); 138#endif 139 140 if (read_random(&seed, "/dev/urandom") == sizeof(seed)) 141 return seed; 142 if (read_random(&seed, "/dev/random") == sizeof(seed)) 143 return seed; 144 return get_generic_seed(); 145} 146