ockam_identity/secure_channel/
nonce.rs

1use crate::IdentityError;
2use core::fmt::{Display, Formatter};
3use ockam_core::Result;
4
5/// Nonce length for AES-GCM
6pub const AES_GCM_NONCE_LEN: usize = 12;
7
8/// Nonce length for Noise Protocol
9pub const NOISE_NONCE_LEN: usize = 8;
10
11/// Maximum possible Nonce value
12pub const MAX_NONCE: Nonce = Nonce { value: u64::MAX };
13
14/// Secure Channel Nonce
15#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Copy)]
16pub struct Nonce {
17    value: u64,
18}
19
20impl Display for Nonce {
21    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
22        write!(f, "{}", self.value)
23    }
24}
25
26impl From<u64> for Nonce {
27    fn from(value: u64) -> Self {
28        Self { value }
29    }
30}
31
32impl From<Nonce> for u64 {
33    fn from(value: Nonce) -> Self {
34        value.value
35    }
36}
37
38impl Nonce {
39    /// Constructor
40    pub fn new(value: u64) -> Self {
41        Self { value }
42    }
43
44    /// Nonce value
45    pub fn value(&self) -> u64 {
46        self.value
47    }
48
49    /// Increment nonce value (overflow is not checked)
50    pub fn increment(&mut self) -> Result<()> {
51        if self == &MAX_NONCE {
52            return Err(IdentityError::NonceOverflow)?;
53        }
54
55        self.value += 1;
56
57        Ok(())
58    }
59
60    /// We use u64 nonce since it's convenient to work with it (e.g. increment)
61    /// But we use 12-byte be format for encryption, since AES-GCM wants 12 bytes
62    pub fn to_aes_gcm_nonce(&self) -> [u8; AES_GCM_NONCE_LEN] {
63        let mut n: [u8; AES_GCM_NONCE_LEN] = [0; AES_GCM_NONCE_LEN];
64
65        n[AES_GCM_NONCE_LEN - NOISE_NONCE_LEN..].copy_from_slice(&self.to_noise_nonce());
66
67        n
68    }
69
70    /// We use u64 nonce since it's convenient to work with it (e.g. increment)
71    /// But we use 8-byte be format to send it over to the other side (according to noise spec)
72    pub fn to_noise_nonce(&self) -> [u8; NOISE_NONCE_LEN] {
73        self.value.to_be_bytes()
74    }
75}
76
77/// Restore 12-byte nonce needed for AES GCM from 8 byte that we use for noise
78impl From<[u8; NOISE_NONCE_LEN]> for Nonce {
79    fn from(value: [u8; NOISE_NONCE_LEN]) -> Self {
80        let value = u64::from_be_bytes(value);
81
82        Self { value }
83    }
84}
85
86/// Restore 12-byte nonce needed for AES GCM from 8 byte that we use for noise
87impl TryFrom<&[u8]> for Nonce {
88    type Error = IdentityError;
89
90    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
91        let bytes: [u8; NOISE_NONCE_LEN] =
92            value.try_into().map_err(|_| IdentityError::InvalidNonce)?;
93
94        Ok(bytes.into())
95    }
96}