1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
use RandomGen;

/// `true` iff `OsRng` supports the targeted OS.
pub const HAS_OS_RNG: bool = internal::HAS_OS_RNG;

/// `RandomGen` that sources its randomness from the operating system.
pub struct OsRng(internal::OsRng);

impl OsRng {
    /// Creates a new OS-dependent random number generator.
    pub fn new() -> OsRng {
        OsRng(internal::OsRng::new())
    }
}

impl RandomGen for OsRng {
    fn gen_u32(&mut self) -> u32 {
        self.0.gen_u32()
    }

    fn gen_u64(&mut self) -> u64 {
        self.0.gen_u64()
    }

    fn fill_buffer(&mut self, buffer: &mut [u8]) {
        self.0.fill_buffer(buffer)
    }
}

// TODO: other OS's
#[cfg(windows)]
mod internal {
    use super::*;

    pub const HAS_OS_RNG: bool = true;

    #[link(name = "advapi32")]
    extern "system" {
        fn SystemFunction036(RandomBuffer: *mut u8, RandomBufferLength: u32) -> u8;
    }

    #[derive(Debug)]
    pub struct OsRng;

    impl OsRng {
        pub fn new() -> OsRng {
            OsRng
        }
    }

    impl RandomGen for OsRng {
        fn gen_u32(&mut self) -> u32 {
            let mut buffer = [0u8; 4];
            self.fill_buffer(&mut buffer);
            unsafe { ::std::mem::transmute(buffer) }
        }

        fn gen_u64(&mut self) -> u64 {
            let mut buffer = [0u8; 8];
            self.fill_buffer(&mut buffer);
            unsafe { ::std::mem::transmute(buffer) }
        }

        fn fill_buffer(&mut self, buffer: &mut [u8]) {
            for slice in buffer.chunks_mut(::std::u32::MAX as usize) {
                let ret_val = unsafe { SystemFunction036(slice.as_mut_ptr(), slice.len() as u32) };
                if ret_val == 0 {
                    panic!(
                        "couldn't generate random bytes: {}",
                        ::std::io::Error::last_os_error()
                    );
                }
            }
        }
    }
}

#[cfg(not(windows))]
mod internal {
    use super::*;

    pub const HAS_OS_RNG: bool = false;

    #[derive(Debug)]
    pub struct OsRng;

    impl OsRng {
        pub fn new() -> OsRng {
            panic!("we don't support this OsRng for this OS yet!");
        }
    }

    impl RandomGen for OsRng {
        fn gen_u32(&mut self) -> u32 {
            panic!("we don't support this OsRng for this OS yet!");
        }

        fn gen_u64(&mut self) -> u64 {
            panic!("we don't support this OsRng for this OS yet!");
        }

        fn fill_buffer(&mut self, _buffer: &mut [u8]) {
            panic!("we don't support this OsRng for this OS yet!");
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn os_rng_works_on_supported_os() {
        if HAS_OS_RNG {
            let mut rng = OsRng::new();
            let _ = rng.gen_u32();
        }
    }

    #[test]
    #[should_panic]
    fn os_rng_panics_on_unsupported_os() {
        if HAS_OS_RNG {
            panic!();
        } else {
            let _ = OsRng::new();
        }
    }
}