aws_lc_rs/aead/nonce_sequence/
counter32.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0 OR ISC
3
4use crate::aead::{Nonce, NonceSequence, NONCE_LEN};
5use crate::error::Unspecified;
6use crate::iv::FixedLength;
7
8/// `Counter32` is an implementation of the `NonceSequence` trait.
9///
10/// The internal state of a `Counter32` is a 32-bit unsigned counter that
11/// increments on each call to `advance` and an optional 8-byte identifier. Counter and identifier
12/// values are used to construct each nonce.
13/// A limit can be set on the number of nonces allowed to be generated, by default this limit is
14/// `u32::MAX`.
15///
16/// See [Section 3.2 of RFC 5116](https://www.rfc-editor.org/rfc/rfc5116#section-3.2).
17#[allow(clippy::module_name_repetitions)]
18pub struct Counter32 {
19    limit: u32,
20    generated: u32,
21    identifier: [u8; 8],
22    counter: u32,
23}
24
25/// `NonceSequenceBuilder` facilitates the building of a `Counter32`.
26#[allow(clippy::module_name_repetitions)]
27pub struct Counter32Builder {
28    limit: u32,
29    identifier: [u8; 8],
30    counter: u32,
31}
32
33impl Default for Counter32Builder {
34    fn default() -> Self {
35        Counter32Builder::new()
36    }
37}
38
39impl Counter32Builder {
40    /// Constructs a `Counter32Builder` with all default values.
41    #[must_use]
42    pub fn new() -> Counter32Builder {
43        Counter32Builder {
44            limit: u32::MAX,
45            identifier: [0u8; 8],
46            counter: 0,
47        }
48    }
49
50    /// The identifier for the `Counter32` - this value helps differentiate nonce
51    /// sequences.
52    #[must_use]
53    pub fn identifier<T: Into<[u8; 8]>>(mut self, identifier: T) -> Counter32Builder {
54        self.identifier = identifier.into();
55        self
56    }
57
58    /// The starting counter value for the `Counter32`.
59    #[must_use]
60    pub fn counter(mut self, counter: u32) -> Counter32Builder {
61        self.counter = counter;
62        self
63    }
64
65    /// The limit for the number of nonces the `Counter32` can produce.
66    #[must_use]
67    pub fn limit(mut self, limit: u32) -> Counter32Builder {
68        self.limit = limit;
69        self
70    }
71
72    /// Constructs a new `Counter32` with internal identifier and counter set to the
73    /// values provided by this struct.
74    #[must_use]
75    pub fn build(self) -> Counter32 {
76        Counter32 {
77            limit: self.limit,
78            generated: 0,
79            identifier: self.identifier,
80            counter: self.counter,
81        }
82    }
83}
84
85impl Counter32 {
86    /// Provides the internal identifier.
87    #[must_use]
88    pub fn identifier(&self) -> [u8; 8] {
89        self.identifier
90    }
91
92    /// Provides the current internal counter value.
93    #[must_use]
94    pub fn counter(&self) -> u32 {
95        self.counter
96    }
97
98    /// Provides the current counter indicating how many nonces have been generated.
99    #[must_use]
100    pub fn generated(&self) -> u32 {
101        self.generated
102    }
103
104    /// Provides the limit on the number of nonces allowed to be generate.
105    #[must_use]
106    pub fn limit(&self) -> u32 {
107        self.limit
108    }
109}
110
111impl NonceSequence for Counter32 {
112    fn advance(&mut self) -> Result<Nonce, Unspecified> {
113        self.generated = self.generated.checked_add(1).ok_or(Unspecified)?;
114        if self.generated > self.limit {
115            return Err(Unspecified);
116        }
117        let counter_bytes: [u8; 4] = self.counter.to_be_bytes();
118        let mut nonce_bytes = [0u8; NONCE_LEN];
119        nonce_bytes[..8].copy_from_slice(&self.identifier);
120        nonce_bytes[8..].copy_from_slice(&counter_bytes);
121        self.counter = self.counter.wrapping_add(1);
122        Ok(Nonce(FixedLength::from(nonce_bytes)))
123    }
124}
125
126#[cfg(test)]
127mod tests {
128    use crate::aead::nonce_sequence::Counter32Builder;
129    use crate::aead::NonceSequence;
130
131    #[test]
132    fn test_counter32_identifier() {
133        let mut cns = Counter32Builder::default()
134            .identifier([0xA1, 0xB2, 0xC3, 0xD4, 0xA2, 0xB3, 0xC4, 0xD5])
135            .counter(7)
136            .build();
137        assert_eq!(0, cns.generated());
138        let nonce = cns.advance().unwrap();
139        let nonce = nonce.as_ref();
140        assert_eq!(8, cns.counter());
141        assert_eq!(
142            [0xA1, 0xB2, 0xC3, 0xD4, 0xA2, 0xB3, 0xC4, 0xD5],
143            cns.identifier()
144        );
145        assert_eq!(u32::MAX, cns.limit());
146        assert_eq!(1, cns.generated());
147        assert_eq!(
148            nonce,
149            &[0xA1, 0xB2, 0xC3, 0xD4, 0xA2, 0xB3, 0xC4, 0xD5, 0, 0, 0, 7]
150        );
151        let nonce = cns.advance().unwrap();
152        let nonce = nonce.as_ref();
153        assert_eq!(2, cns.generated());
154        assert_eq!(9, cns.counter());
155        assert_eq!(
156            [0xA1, 0xB2, 0xC3, 0xD4, 0xA2, 0xB3, 0xC4, 0xD5],
157            cns.identifier()
158        );
159        assert_eq!(
160            nonce,
161            &[0xA1, 0xB2, 0xC3, 0xD4, 0xA2, 0xB3, 0xC4, 0xD5, 0, 0, 0, 8]
162        );
163    }
164
165    #[test]
166    fn test_counter32() {
167        let mut cns = Counter32Builder::new().counter(0x_4CB0_16EA_u32).build();
168        let nonce = cns.advance().unwrap();
169        let nonce = nonce.as_ref();
170        assert_eq!(nonce, &[0, 0, 0, 0, 0, 0, 0, 0, 0x4C, 0xB0, 0x16, 0xEA]);
171        let nonce = cns.advance().unwrap();
172        let nonce = nonce.as_ref();
173        assert_eq!(nonce, &[0, 0, 0, 0, 0, 0, 0, 0, 0x4C, 0xB0, 0x16, 0xEB]);
174    }
175
176    #[test]
177    fn test_counter32_int_id() {
178        let mut cns = Counter32Builder::new()
179            .counter(0x_6A_u32)
180            .identifier(0x_7B_u64.to_be_bytes())
181            .build();
182        let nonce = cns.advance().unwrap();
183        let nonce = nonce.as_ref();
184        assert_eq!(nonce, &[0, 0, 0, 0, 0, 0, 0, 0x7B, 0, 0, 0, 0x6A]);
185        let nonce = cns.advance().unwrap();
186        let nonce = nonce.as_ref();
187        assert_eq!(nonce, &[0, 0, 0, 0, 0, 0, 0, 0x7B, 0, 0, 0, 0x6B]);
188    }
189
190    #[test]
191    fn test_counter32_limit() {
192        let mut cns = Counter32Builder::new().limit(1).build();
193        assert_eq!(1, cns.limit());
194        assert_eq!(0, cns.generated());
195        let _nonce = cns.advance().unwrap();
196        assert_eq!(1, cns.generated());
197        assert!(cns.advance().is_err());
198    }
199}