// Copyright 2012 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #include "rust_globals.h" #include "rust_rng.h" #include "rust_util.h" size_t rng_seed_size() { randctx rctx; return sizeof(rctx.randrsl); } // Initialization helpers for ISAAC RNG void rng_gen_seed(rust_kernel* kernel, uint8_t* dest, size_t size) { #ifdef __WIN32__ HCRYPTPROV hProv; kernel->win32_require (_T("CryptAcquireContext"), CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT|CRYPT_SILENT)); kernel->win32_require (_T("CryptGenRandom"), CryptGenRandom(hProv, size, (BYTE*) dest)); kernel->win32_require (_T("CryptReleaseContext"), CryptReleaseContext(hProv, 0)); #else int fd = open("/dev/urandom", O_RDONLY); if (fd == -1) kernel->fatal("error opening /dev/urandom: %s", strerror(errno)); size_t amount = 0; do { ssize_t ret = read(fd, dest+amount, size-amount); if (ret < 0) kernel->fatal("error reading /dev/urandom: %s", strerror(errno)); else if (ret == 0) kernel->fatal("somehow hit eof reading from /dev/urandom"); amount += (size_t)ret; } while (amount < size); int ret = close(fd); // FIXME #3697: Why does this fail sometimes? if (ret != 0) kernel->log(log_warn, "error closing /dev/urandom: %s", strerror(errno)); #endif } static void isaac_init(rust_kernel *kernel, randctx *rctx, uint8_t* user_seed, size_t seed_len) { memset(rctx, 0, sizeof(randctx)); char *env_seed = kernel->env->rust_seed; if (user_seed != NULL) { // ignore bytes after the required length if (seed_len > sizeof(rctx->randrsl)) { seed_len = sizeof(rctx->randrsl); } memcpy(&rctx->randrsl, user_seed, seed_len); } else if (env_seed != NULL) { ub4 seed = (ub4) atoi(env_seed); for (size_t i = 0; i < RANDSIZ; i ++) { memcpy(&rctx->randrsl[i], &seed, sizeof(ub4)); seed = (seed + 0x7ed55d16) + (seed << 12); } } else { rng_gen_seed(kernel, (uint8_t*)&rctx->randrsl, sizeof(rctx->randrsl)); } randinit(rctx, 1); } void rng_init(rust_kernel* kernel, rust_rng* rng, uint8_t *user_seed, size_t seed_len) { isaac_init(kernel, &rng->rctx, user_seed, seed_len); rng->reseedable = !user_seed && !kernel->env->rust_seed; } static void rng_maybe_reseed(rust_kernel* kernel, rust_rng* rng) { // If this RNG has generated more than 32KB of random data and was not // seeded by the user or RUST_SEED, then we should reseed now. const size_t RESEED_THRESHOLD = 32 * 1024; size_t bytes_generated = rng->rctx.randc * sizeof(ub4); if (bytes_generated < RESEED_THRESHOLD || !rng->reseedable) { return; } rng_gen_seed(kernel, (uint8_t*)rng->rctx.randrsl, sizeof(rng->rctx.randrsl)); randinit(&rng->rctx, 1); } uint32_t rng_gen_u32(rust_kernel* kernel, rust_rng* rng) { uint32_t x = isaac_rand(&rng->rctx); rng_maybe_reseed(kernel, rng); return x; } // // Local Variables: // mode: C++ // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: //