lib3mf_core/crypto/
encryption.rs

1use crate::error::{Lib3mfError, Result};
2use aes_gcm::{
3    Aes256Gcm, Key, Nonce,
4    aead::{Aead, KeyInit},
5};
6use rand::RngCore;
7
8/// Encrypts data using AES-256-GCM.
9/// Returns (ciphertext, nonce, tag) combined or separate?
10/// 3MF Spec: Content Encryption usually has IV/Nonce separately or prepended.
11/// "The Key used is the Content Encryption Key (CEK)."
12/// "The Algorithm is AES-256-GCM."
13/// Nonce is 12 bytes (96 bits).
14/// Tag is 16 bytes (128 bits).
15/// Output usually: Nonce + Ciphertext (which includes Tag usually in Rust implementation?)
16/// Rust `aes-gcm` crate returns `ciphertext + tag`.
17pub fn encrypt_aes256gcm(key: &[u8], plaintext: &[u8]) -> Result<(Vec<u8>, Vec<u8>)> {
18    if key.len() != 32 {
19        return Err(Lib3mfError::Validation(
20            "Invalid key length for AES-256-GCM".to_string(),
21        ));
22    }
23
24    let key = Key::<Aes256Gcm>::from_slice(key);
25    let cipher = Aes256Gcm::new(key);
26
27    // Generate random 96-bit nonce
28    let mut nonce_bytes = [0u8; 12];
29    rand::rngs::OsRng.fill_bytes(&mut nonce_bytes);
30    let nonce = Nonce::from_slice(&nonce_bytes);
31
32    let ciphertext = cipher
33        .encrypt(nonce, plaintext)
34        .map_err(|e| Lib3mfError::EncryptionError(format!("Encryption failed: {}", e)))?;
35
36    Ok((ciphertext, nonce_bytes.to_vec()))
37}
38
39/// Decrypts data using AES-256-GCM.
40/// Input: ciphertext (including tag), key, nonce.
41pub fn decrypt_aes256gcm(key: &[u8], nonce: &[u8], ciphertext: &[u8]) -> Result<Vec<u8>> {
42    if key.len() != 32 {
43        return Err(Lib3mfError::Validation(
44            "Invalid key length for AES-256-GCM".to_string(),
45        ));
46    }
47    if nonce.len() != 12 {
48        return Err(Lib3mfError::Validation(
49            "Invalid nonce length for AES-256-GCM".to_string(),
50        ));
51    }
52
53    let key = Key::<Aes256Gcm>::from_slice(key);
54    let cipher = Aes256Gcm::new(key);
55    let nonce = Nonce::from_slice(nonce);
56
57    let plaintext = cipher
58        .decrypt(nonce, ciphertext)
59        .map_err(|e| Lib3mfError::EncryptionError(format!("Decryption failed: {}", e)))?;
60
61    Ok(plaintext)
62}