Skip to main content

wlan_rsn/
nonce.rs

1// Copyright 2018 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::prf;
6use bytes::{BufMut, BytesMut};
7use fuchsia_sync::Mutex;
8
9use ieee80211::MacAddr;
10use num::bigint::BigUint;
11use rand::RngExt as _;
12use rand::rand_core::UnwrapErr;
13use rand::rngs::SysRng;
14use std::sync::Arc;
15
16pub type Nonce = [u8; 32];
17
18/// Thread-safe nonce generator.
19/// According to IEEE Std 802.11-2016, 12.7.5 each STA should be configured with an initial,
20/// cryptographic-quality random counter at system boot up time.
21#[derive(Debug)]
22pub struct NonceReader {
23    key_counter: Mutex<BigUint>,
24}
25
26impl NonceReader {
27    pub fn new(sta_addr: &MacAddr) -> Result<Arc<NonceReader>, anyhow::Error> {
28        // Write time and STA's address to buffer for PRF-256.
29        // It's unclear whether or not using PRF has any significant cryptographic advantage.
30        // For the time being, follow IEEE's recommendation for nonce generation.
31        // IEEE Std 802.11-2016, 12.7.5 recommends using a time in NTP format.
32        // Fuchsia has no support for NTP yet; instead use a regular timestamp.
33        // TODO(https://fxbug.dev/42124853): Use time in NTP format once Fuchsia added support.
34        let mut buf = BytesMut::with_capacity(14);
35        let epoch_nanos = zx::MonotonicInstant::get().into_nanos();
36        buf.put_i64_le(epoch_nanos);
37        buf.put_slice(sta_addr.as_slice());
38        let k = UnwrapErr(SysRng).random::<[u8; 32]>();
39        let init = prf::prf(&k[..], "Init Counter", &buf[..], 8 * std::mem::size_of_val(&k))?;
40        Ok(Arc::new(NonceReader { key_counter: Mutex::new(BigUint::from_bytes_le(&init[..])) }))
41    }
42
43    pub fn next(&self) -> Nonce {
44        let mut counter = self.key_counter.lock();
45        *counter += 1u8;
46
47        // Expand nonce if it's less than 32 bytes.
48        let mut result = (*counter).to_bytes_le();
49        result.resize(32, 0);
50        let mut nonce = Nonce::default();
51        nonce.copy_from_slice(&result[..]);
52        nonce
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use super::*;
59
60    #[test]
61    fn test_next_nonce() {
62        let addr = MacAddr::from([1, 2, 3, 4, 5, 6]);
63        let rdr = NonceReader::new(&addr).expect("error creating NonceReader");
64        let mut previous_nonce = rdr.next();
65        for _ in 0..300 {
66            let nonce = rdr.next();
67            let nonce_int = BigUint::from_bytes_le(&nonce[..]);
68            let previous_nonce_int = BigUint::from_bytes_le(&previous_nonce[..]);
69            assert_eq!(nonce_int.gt(&previous_nonce_int), true);
70
71            previous_nonce = nonce;
72        }
73    }
74}