sentinel_crypto/encrypt/
ascon128.rs

1use ascon_aead::{
2    aead::{Aead, KeyInit},
3    AsconAead128 as Ascon128,
4    Key,
5    Nonce,
6};
7use rand::RngCore;
8
9use crate::{encrypt_trait::EncryptionAlgorithm, error::CryptoError};
10
11/// Ascon-128 encryption implementation.
12/// Uses the Ascon authenticated encryption algorithm, designed for constrained environments.
13/// Provides excellent performance on resource-limited devices while maintaining strong security.
14///
15/// Design choice: Ascon is specifically designed for IoT and constrained environments,
16/// offering better performance than AES on systems without hardware acceleration.
17/// It provides 128-bit security and is a finalist in the NIST lightweight cryptography competition.
18pub struct Ascon128Encryptor;
19
20impl EncryptionAlgorithm for Ascon128Encryptor {
21    fn encrypt_data(data: &[u8], key: &[u8; 32]) -> Result<String, CryptoError> {
22        // Ascon128 uses 16-byte keys, so we take the first 16 bytes of the 32-byte key
23        let key_16: &[u8; 16] = key[.. 16].try_into().unwrap();
24        let cipher = Ascon128::new(Key::<Ascon128>::from_slice(key_16));
25        let mut nonce_bytes = [0u8; 16]; // Ascon uses 128-bit nonce
26        rand::rng().fill_bytes(&mut nonce_bytes);
27        let nonce = Nonce::<Ascon128>::from_slice(&nonce_bytes);
28
29        let ciphertext = cipher
30            .encrypt(nonce, data)
31            .map_err(|_| CryptoError::Encryption)?;
32        let mut result = nonce_bytes.to_vec();
33        result.extend_from_slice(&ciphertext);
34        Ok(hex::encode(result))
35    }
36
37    fn decrypt_data(encrypted_data: &str, key: &[u8; 32]) -> Result<Vec<u8>, CryptoError> {
38        let data = hex::decode(encrypted_data).map_err(|_| CryptoError::Decryption)?;
39        if data.len() < 16 {
40            return Err(CryptoError::Decryption);
41        }
42        let (nonce_bytes, ciphertext) = data.split_at(16);
43        // Ascon128 uses 16-byte keys, so we take the first 16 bytes of the 32-byte key
44        let key_16: &[u8; 16] = key[.. 16].try_into().unwrap();
45        let cipher = Ascon128::new(Key::<Ascon128>::from_slice(key_16));
46        let nonce = Nonce::<Ascon128>::from_slice(nonce_bytes);
47        cipher
48            .decrypt(nonce, ciphertext)
49            .map_err(|_| CryptoError::Decryption)
50    }
51}
52
53impl crate::encrypt_trait::private::Sealed for Ascon128Encryptor {}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn test_encrypt_decrypt() {
61        let key = [0u8; 32];
62        let data = b"Hello, world!";
63        let encrypted = Ascon128Encryptor::encrypt_data(data, &key).unwrap();
64        let decrypted = Ascon128Encryptor::decrypt_data(&encrypted, &key).unwrap();
65        assert_eq!(decrypted, data);
66    }
67
68    #[test]
69    fn test_decrypt_invalid_length() {
70        let key = [0u8; 32];
71        // Short data that decodes to less than 16 bytes
72        let short_hex = hex::encode(&[0u8; 14]); // 28 hex chars, 14 bytes
73        let result = Ascon128Encryptor::decrypt_data(&short_hex, &key);
74        assert!(result.is_err());
75    }
76}