blob: a29efcd3a49545270da605bb436d1803e59a3c6a [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use bytes::{BufMut, BytesMut};
use crypto_utils::prf;
use failure;
use num::bigint::{BigUint, RandBigInt};
use rand::OsRng;
use std::sync::Mutex;
use time;
// Thread-safe nonce generator.
// According to IEEE Std 802.11-2016, 12.7.5 each STA should be configured with an initial, random
// counter at system boot up time.
#[derive(Debug)]
pub struct NonceReader {
key_counter: Mutex<BigUint>,
}
impl NonceReader {
pub fn new(sta_addr: &[u8]) -> Result<NonceReader, failure::Error> {
// Write time and STA's address to buffer for PRF-256.
// IEEE Std 802.11-2016, 12.7.5 recommends using a time in NTP format.
// Fuchsia has no support for NTP yet; instead use a regular timestamp.
// TODO(NET-430): Use time in NTP format once Fuchsia added support.
let mut buf = BytesMut::with_capacity(14);
buf.put_u64_le(time::precise_time_ns());
buf.put_slice(sta_addr);
let k = OsRng::new()?.gen_biguint(256).to_bytes_le();
let init = prf(&k[..], "Init Counter", &buf[..], 256)?;
Ok(NonceReader {
key_counter: Mutex::new(BigUint::from_bytes_le(&init[..])),
})
}
pub fn next(&mut self) -> Result<Vec<u8>, failure::Error> {
match self.key_counter.lock() {
Err(_) => bail!("NonceReader lock is poisoned"),
Ok(mut counter) => {
*counter += 1u8;
// Expand nonce if it's less than 32 bytes.
let mut result = (*counter).to_bytes_le();
result.resize(32, 0);
Ok(result)
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_next_nonce() {
let addr: [u8; 6] = [1, 2, 3, 4, 5, 6];
let mut rdr = NonceReader::new(&addr[..]).expect("error creating NonceReader");
let mut previous_nonce = rdr.next().expect("error generating nonce");
for _ in 0..300 {
let nonce = rdr.next().expect("error generating nonce");
let nonce_int = BigUint::from_bytes_le(&nonce[..]);
let previous_nonce_int = BigUint::from_bytes_le(&previous_nonce[..]);
assert_eq!(nonce_int.gt(&previous_nonce_int), true);
previous_nonce = nonce;
}
}
}