Implement decryption

This commit is contained in:
Rodolphe Bréard 2024-02-25 13:40:19 +01:00
parent 9a60461266
commit 85d0ee7e31
2 changed files with 64 additions and 8 deletions

View file

@ -5,6 +5,7 @@ use crate::{storage, InputKeyMaterialList};
use chacha20poly1305::aead::{Aead, KeyInit, Payload}; use chacha20poly1305::aead::{Aead, KeyInit, Payload};
use chacha20poly1305::{Key, XChaCha20Poly1305, XNonce}; use chacha20poly1305::{Key, XChaCha20Poly1305, XNonce};
pub(crate) type DecryptionFunction = dyn Fn(&[u8], &EncryptedData, &str) -> Result<Vec<u8>>;
pub(crate) type EncryptionFunction = dyn Fn(&[u8], &[u8], &str) -> Result<EncryptedData>; pub(crate) type EncryptionFunction = dyn Fn(&[u8], &[u8], &str) -> Result<EncryptedData>;
pub(crate) struct EncryptedData { pub(crate) struct EncryptedData {
@ -12,6 +13,13 @@ pub(crate) struct EncryptedData {
pub(crate) ciphertext: Vec<u8>, pub(crate) ciphertext: Vec<u8>,
} }
#[inline]
fn generate_aad(key_context: &[&str], data_context: &[impl AsRef<[u8]>]) -> String {
let key_context_canon = canonicalize(key_context);
let data_context_canon = canonicalize(data_context);
join_canonicalized_str(&key_context_canon, &data_context_canon)
}
pub fn encrypt( pub fn encrypt(
ikml: &InputKeyMaterialList, ikml: &InputKeyMaterialList,
key_context: &[&str], key_context: &[&str],
@ -23,9 +31,7 @@ pub fn encrypt(
let key = derive_key(ikm, key_context); let key = derive_key(ikm, key_context);
// Generate the AAD // Generate the AAD
let key_context_canon = canonicalize(key_context); let aad = generate_aad(key_context, data_context);
let data_context_canon = canonicalize(data_context);
let aad = join_canonicalized_str(&key_context_canon, &data_context_canon);
// Encrypt // Encrypt
let encryption_function = ikm.scheme.get_encryption(); let encryption_function = ikm.scheme.get_encryption();
@ -68,10 +74,42 @@ pub(crate) fn xchacha20poly1305_encrypt(
pub fn decrypt( pub fn decrypt(
ikml: &InputKeyMaterialList, ikml: &InputKeyMaterialList,
key_context: &[&str], key_context: &[&str],
data: impl AsRef<[u8]>, stored_data: &str,
data_context: &[impl AsRef<[u8]>], data_context: &[impl AsRef<[u8]>],
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
unimplemented!("decrypt"); // Retreive the IKM and the encrypted data
let (ikm_id, encrypted_data) = storage::decode(stored_data)?;
let ikm = ikml.get_ikm_by_id(ikm_id)?;
// Derive the key
let key = derive_key(ikm, key_context);
// Generate the AAD
let aad = generate_aad(key_context, data_context);
// Decrypt
let decryption_function = ikm.scheme.get_decryption();
decryption_function(&key, &encrypted_data, &aad)
}
pub(crate) fn xchacha20poly1305_decrypt(
key: &[u8],
encrypted_data: &EncryptedData,
aad: &str,
) -> Result<Vec<u8>> {
// Adapt the key and the nonce
let key = Key::from_slice(key);
let nonce = XNonce::from_slice(&encrypted_data.nonce);
// Prepare the payload
let payload = Payload {
msg: &encrypted_data.ciphertext,
aad: aad.as_bytes(),
};
// Decrypt the payload
let cipher = XChaCha20Poly1305::new(key);
Ok(cipher.decrypt(nonce, payload)?)
} }
#[cfg(test)] #[cfg(test)]
@ -92,6 +130,7 @@ mod tests {
#[test] #[test]
fn encrypt_decrypt_no_context() { fn encrypt_decrypt_no_context() {
// Encrypt
let lst = get_ikm_lst(); let lst = get_ikm_lst();
let res = encrypt(&lst, &[], TEST_DATA, EMPTY_DATA_CTX); let res = encrypt(&lst, &[], TEST_DATA, EMPTY_DATA_CTX);
assert!(res.is_ok()); assert!(res.is_ok());
@ -99,11 +138,16 @@ mod tests {
assert!(ciphertext.starts_with("AQAAAA:")); assert!(ciphertext.starts_with("AQAAAA:"));
assert_eq!(ciphertext.len(), 98); assert_eq!(ciphertext.len(), 98);
// TODO: decrypt // Decrypt
let res = decrypt(&lst, &[], &ciphertext, EMPTY_DATA_CTX);
assert!(res.is_ok());
let plaintext = res.unwrap();
assert_eq!(plaintext, TEST_DATA);
} }
#[test] #[test]
fn encrypt_decrypt_with_context() { fn encrypt_decrypt_with_context() {
// Encrypt
let lst = get_ikm_lst(); let lst = get_ikm_lst();
let res = encrypt(&lst, TEST_KEY_CTX, TEST_DATA, TEST_DATA_CTX); let res = encrypt(&lst, TEST_KEY_CTX, TEST_DATA, TEST_DATA_CTX);
assert!(res.is_ok()); assert!(res.is_ok());
@ -111,6 +155,10 @@ mod tests {
assert!(ciphertext.starts_with("AQAAAA:")); assert!(ciphertext.starts_with("AQAAAA:"));
assert_eq!(ciphertext.len(), 98); assert_eq!(ciphertext.len(), 98);
// TODO: decrypt // Decrypt
let res = decrypt(&lst, TEST_KEY_CTX, &ciphertext, TEST_DATA_CTX);
assert!(res.is_ok());
let plaintext = res.unwrap();
assert_eq!(plaintext, TEST_DATA);
} }
} }

View file

@ -1,4 +1,4 @@
use crate::encryption::EncryptionFunction; use crate::encryption::{DecryptionFunction, EncryptionFunction};
use crate::kdf::KdfFunction; use crate::kdf::KdfFunction;
use crate::Error; use crate::Error;
@ -16,6 +16,14 @@ impl Scheme {
} }
} }
pub(crate) fn get_decryption(&self) -> Box<DecryptionFunction> {
match self {
Scheme::XChaCha20Poly1305WithBlake3 => {
Box::new(crate::encryption::xchacha20poly1305_decrypt)
}
}
}
pub(crate) fn get_encryption(&self) -> Box<EncryptionFunction> { pub(crate) fn get_encryption(&self) -> Box<EncryptionFunction> {
match self { match self {
Scheme::XChaCha20Poly1305WithBlake3 => { Scheme::XChaCha20Poly1305WithBlake3 => {