blob: bb3770af4830c0cb5bf7fd8de34145bae6edd3ea [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 crate::crypto_utils::prf;
use bytes::{BufMut, BytesMut};
use failure::{self, bail};
use num::bigint::{BigUint, RandBigInt};
use rand::OsRng;
use std::sync::{Arc, Mutex};
use time;
pub type Nonce = [u8; 32];
/// Thread-safe nonce generator.
/// According to IEEE Std 802.11-2016, 12.7.5 each STA should be configured with an initial,
/// cryptographic-quality 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<Arc<NonceReader>, failure::Error> {
// Write time and STA's address to buffer for PRF-256.
// It's unclear whether or not using PRF has any significant cryptographic advantage.
// For the time being, follow IEEE's recommendation for nonce generation.
// 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(Arc::new(NonceReader { key_counter: Mutex::new(BigUint::from_bytes_le(&init[..])) }))
}
pub fn next(&self) -> Result<Nonce, failure::Error> {
match self.key_counter.lock() {
Err(_) => bail!("NonceReader's 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);
let mut nonce = Nonce::default();
nonce.copy_from_slice(&result[..]);
Ok(nonce)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_next_nonce() {
let addr: [u8; 6] = [1, 2, 3, 4, 5, 6];
let 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;
}
}
}