Skip to main content

leodos_protocols/datalink/security/sdls/
gcm.rs

1use aes_gcm::{
2    aead::{
3        generic_array::GenericArray, AeadInPlace, KeyInit,
4    },
5    Aes128Gcm, Aes256Gcm,
6};
7
8use super::{CryptoProvider, Error, SecurityAssociation};
9
10enum Cipher {
11    Aes128(Aes128Gcm),
12    Aes256(Aes256Gcm),
13}
14
15/// AES-GCM authenticated encryption provider.
16///
17/// Supports 128-bit and 256-bit keys with 12-byte nonces
18/// per CCSDS 355.0-B-2 Table 6-1. The GCM tag (16 bytes) is
19/// used as the MAC in the SDLS Security Trailer.
20pub struct AesGcmCrypto {
21    cipher: Cipher,
22}
23
24impl AesGcmCrypto {
25    /// Create a provider with a 128-bit key.
26    pub fn new_128(key: &[u8; 16]) -> Self {
27        Self {
28            cipher: Cipher::Aes128(
29                Aes128Gcm::new(key.into()),
30            ),
31        }
32    }
33
34    /// Create a provider with a 256-bit key.
35    pub fn new_256(key: &[u8; 32]) -> Self {
36        Self {
37            cipher: Cipher::Aes256(
38                Aes256Gcm::new(key.into()),
39            ),
40        }
41    }
42}
43
44impl CryptoProvider for AesGcmCrypto {
45    fn encrypt(
46        &self,
47        _sa: &SecurityAssociation,
48        iv: &[u8],
49        aad: &[u8],
50        data: &mut [u8],
51        tag_out: &mut [u8],
52    ) -> Result<usize, Error> {
53        if iv.len() != 12 {
54            return Err(Error::CryptoError);
55        }
56        let nonce = GenericArray::from_slice(iv);
57        let tag = match &self.cipher {
58            Cipher::Aes128(c) => c
59                .encrypt_in_place_detached(nonce, aad, data)
60                .map_err(|_| Error::CryptoError)?,
61            Cipher::Aes256(c) => c
62                .encrypt_in_place_detached(nonce, aad, data)
63                .map_err(|_| Error::CryptoError)?,
64        };
65        let len = tag_out.len().min(16);
66        tag_out[..len].copy_from_slice(&tag[..len]);
67        Ok(0)
68    }
69
70    fn decrypt(
71        &self,
72        _sa: &SecurityAssociation,
73        iv: &[u8],
74        aad: &[u8],
75        data: &mut [u8],
76        tag: &[u8],
77    ) -> Result<usize, Error> {
78        if iv.len() != 12 || tag.len() != 16 {
79            return Err(Error::CryptoError);
80        }
81        let nonce = GenericArray::from_slice(iv);
82        let tag_arr = GenericArray::from_slice(tag);
83        match &self.cipher {
84            Cipher::Aes128(c) => c
85                .decrypt_in_place_detached(
86                    nonce, aad, data, tag_arr,
87                )
88                .map_err(|_| Error::MacVerificationFailed)?,
89            Cipher::Aes256(c) => c
90                .decrypt_in_place_detached(
91                    nonce, aad, data, tag_arr,
92                )
93                .map_err(|_| Error::MacVerificationFailed)?,
94        };
95        Ok(0)
96    }
97
98    fn compute_mac(
99        &self,
100        _sa: &SecurityAssociation,
101        _iv: &[u8],
102        _payload: &[u8],
103        _mac_out: &mut [u8],
104    ) -> Result<(), Error> {
105        Err(Error::CryptoError)
106    }
107}