00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022
00023 #if HAVE_UNISTD_H
00024 #include <unistd.h>
00025 #endif
00026 #if HAVE_CRYPTGENRANDOM
00027 #include <windows.h>
00028 #include <wincrypt.h>
00029 #endif
00030 #include <fcntl.h>
00031 #include <math.h>
00032 #include <time.h>
00033 #include <string.h>
00034 #include "avassert.h"
00035 #include "timer.h"
00036 #include "random_seed.h"
00037 #include "sha.h"
00038 #include "intreadwrite.h"
00039
00040 #ifndef TEST
00041 #define TEST 0
00042 #endif
00043
00044 static int read_random(uint32_t *dst, const char *file)
00045 {
00046 #if HAVE_UNISTD_H
00047 int fd = open(file, O_RDONLY);
00048 int err = -1;
00049
00050 if (fd == -1)
00051 return -1;
00052 err = read(fd, dst, sizeof(*dst));
00053 close(fd);
00054
00055 return err;
00056 #else
00057 return -1;
00058 #endif
00059 }
00060
00061 static uint32_t get_generic_seed(void)
00062 {
00063 uint8_t tmp[120];
00064 struct AVSHA *sha = (void*)tmp;
00065 clock_t last_t = 0;
00066 static uint64_t i = 0;
00067 static uint32_t buffer[512] = {0};
00068 unsigned char digest[20];
00069 uint64_t last_i = i;
00070
00071 av_assert0(sizeof(tmp) >= av_sha_size);
00072
00073 if(TEST){
00074 memset(buffer, 0, sizeof(buffer));
00075 last_i = i = 0;
00076 }else{
00077 #ifdef AV_READ_TIME
00078 buffer[13] ^= AV_READ_TIME();
00079 buffer[41] ^= AV_READ_TIME()>>32;
00080 #endif
00081 }
00082
00083 for (;;) {
00084 clock_t t = clock();
00085
00086 if(last_t == t){
00087 buffer[i&511]++;
00088 }else{
00089 buffer[++i&511]+= (t-last_t) % 3294638521U;
00090 if(last_i && i-last_i > 4 || i-last_i > 64 || TEST && i-last_i > 8)
00091 break;
00092 }
00093 last_t = t;
00094 }
00095
00096 if(TEST)
00097 buffer[0] = buffer[1] = 0;
00098
00099 av_sha_init(sha, 160);
00100 av_sha_update(sha, (uint8_t*)buffer, sizeof(buffer));
00101 av_sha_final(sha, digest);
00102 return AV_RB32(digest) + AV_RB32(digest+16);
00103 }
00104
00105 uint32_t av_get_random_seed(void)
00106 {
00107 uint32_t seed;
00108
00109 #if HAVE_CRYPTGENRANDOM
00110 HCRYPTPROV provider;
00111 if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL,
00112 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
00113 BOOL ret = CryptGenRandom(provider, sizeof(seed), (PBYTE) &seed);
00114 CryptReleaseContext(provider, 0);
00115 if (ret)
00116 return seed;
00117 }
00118 #endif
00119
00120 if (read_random(&seed, "/dev/urandom") == sizeof(seed))
00121 return seed;
00122 if (read_random(&seed, "/dev/random") == sizeof(seed))
00123 return seed;
00124 return get_generic_seed();
00125 }
00126
00127 #if TEST
00128 #undef printf
00129 #define N 256
00130 #include <stdio.h>
00131
00132 int main(void)
00133 {
00134 int i, j, retry;
00135 uint32_t seeds[N];
00136
00137 for (retry=0; retry<3; retry++){
00138 for (i=0; i<N; i++){
00139 seeds[i] = av_get_random_seed();
00140 for (j=0; j<i; j++)
00141 if (seeds[j] == seeds[i])
00142 goto retry;
00143 }
00144 printf("seeds OK\n");
00145 return 0;
00146 retry:;
00147 }
00148 printf("FAIL at %d with %X\n", j, seeds[j]);
00149 return 1;
00150 }
00151 #endif