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