Allow to encrypt at a specific timestamp

This commit is contained in:
Rodolphe Bréard 2024-04-07 12:22:04 +02:00
parent fd7dccddea
commit 224171c6d5
3 changed files with 63 additions and 16 deletions

View file

@ -15,6 +15,7 @@ categories = ["cryptography"]
default = ["encryption", "ikm-management"] default = ["encryption", "ikm-management"]
encryption = [] encryption = []
ikm-management = [] ikm-management = []
encrypt-at = []
[dependencies] [dependencies]
aes-gcm = { version = "0.10.3", default-features = false, features = ["std", "aes"] } aes-gcm = { version = "0.10.3", default-features = false, features = ["std", "aes"] }

View file

@ -40,14 +40,35 @@ impl<'a> Coffio<'a> {
key_context: &KeyContext, key_context: &KeyContext,
data_context: &DataContext, data_context: &DataContext,
data: impl AsRef<[u8]>, data: impl AsRef<[u8]>,
) -> Result<String> {
self.process_encrypt_at(key_context, data_context, data, SystemTime::now())
}
#[cfg(feature = "encrypt-at")]
pub fn encrypt_at(
&self,
key_context: &KeyContext,
data_context: &DataContext,
data: impl AsRef<[u8]>,
encryption_time: SystemTime,
) -> Result<String> {
self.process_encrypt_at(key_context, data_context, data, encryption_time)
}
fn process_encrypt_at(
&self,
key_context: &KeyContext,
data_context: &DataContext,
data: impl AsRef<[u8]>,
encryption_time: SystemTime,
) -> Result<String> { ) -> Result<String> {
let tp = if key_context.is_periodic() { let tp = if key_context.is_periodic() {
let ts = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs(); let ts = encryption_time.duration_since(UNIX_EPOCH)?.as_secs();
key_context.get_time_period(ts) key_context.get_time_period(ts)
} else { } else {
None None
}; };
let ikm = self.ikm_list.get_latest_ikm()?; let ikm = self.ikm_list.get_latest_ikm(encryption_time)?;
let key = derive_key(ikm, key_context, tp); let key = derive_key(ikm, key_context, tp);
let gen_nonce_function = ikm.scheme.get_gen_nonce(); let gen_nonce_function = ikm.scheme.get_gen_nonce();
let nonce = gen_nonce_function()?; let nonce = gen_nonce_function()?;

View file

@ -238,12 +238,15 @@ impl InputKeyMaterialList {
} }
#[cfg(any(test, feature = "encryption"))] #[cfg(any(test, feature = "encryption"))]
pub(crate) fn get_latest_ikm(&self) -> Result<&InputKeyMaterial> { pub(crate) fn get_latest_ikm(&self, encryption_time: SystemTime) -> Result<&InputKeyMaterial> {
let now = SystemTime::now();
self.ikm_lst self.ikm_lst
.iter() .iter()
.rev() .rev()
.find(|&ikm| !ikm.is_revoked && ikm.not_before < now && ikm.not_after > now) .find(|&ikm| {
!ikm.is_revoked
&& ikm.not_before < encryption_time
&& ikm.not_after > encryption_time
})
.ok_or(Error::IkmNoneAvailable) .ok_or(Error::IkmNoneAvailable)
} }
@ -474,15 +477,15 @@ mod ikm_management {
let _ = lst.add_ikm(); let _ = lst.add_ikm();
let _ = lst.add_ikm(); let _ = lst.add_ikm();
let latest_ikm = lst.get_latest_ikm().unwrap(); let latest_ikm = lst.get_latest_ikm(SystemTime::now()).unwrap();
assert_eq!(latest_ikm.id, 2); assert_eq!(latest_ikm.id, 2);
lst.delete_ikm(2); lst.delete_ikm(2);
let latest_ikm = lst.get_latest_ikm().unwrap(); let latest_ikm = lst.get_latest_ikm(SystemTime::now()).unwrap();
assert_eq!(latest_ikm.id, 1); assert_eq!(latest_ikm.id, 1);
lst.delete_ikm(1); lst.delete_ikm(1);
let res = lst.get_latest_ikm(); let res = lst.get_latest_ikm(SystemTime::now());
assert!(res.is_err()); assert!(res.is_err());
} }
@ -492,15 +495,15 @@ mod ikm_management {
let _ = lst.add_ikm(); let _ = lst.add_ikm();
let _ = lst.add_ikm(); let _ = lst.add_ikm();
let latest_ikm = lst.get_latest_ikm().unwrap(); let latest_ikm = lst.get_latest_ikm(SystemTime::now()).unwrap();
assert_eq!(latest_ikm.id, 2); assert_eq!(latest_ikm.id, 2);
let _ = lst.revoke_ikm(2); let _ = lst.revoke_ikm(2);
let latest_ikm = lst.get_latest_ikm().unwrap(); let latest_ikm = lst.get_latest_ikm(SystemTime::now()).unwrap();
assert_eq!(latest_ikm.id, 1); assert_eq!(latest_ikm.id, 1);
let _ = lst.revoke_ikm(1); let _ = lst.revoke_ikm(1);
let res = lst.get_latest_ikm(); let res = lst.get_latest_ikm(SystemTime::now());
assert!(res.is_err()); assert!(res.is_err());
} }
@ -518,15 +521,37 @@ mod ikm_management {
} }
#[test] #[test]
fn get_latest_ikm() { fn get_latest_ikm_epoch() {
let res = InputKeyMaterialList::import(TEST_STR); let res = InputKeyMaterialList::import(TEST_STR);
assert!(res.is_ok(), "res: {res:?}"); assert!(res.is_ok(), "res: {res:?}");
let lst = res.unwrap(); let lst = res.unwrap();
let res = lst.get_latest_ikm(); let res = lst.get_latest_ikm(SystemTime::UNIX_EPOCH);
assert_eq!(res.err(), Some(Error::IkmNoneAvailable))
}
#[test]
fn get_latest_ikm_1_712_475_802() {
let ts = SystemTime::UNIX_EPOCH + Duration::from_secs(1_712_475_802);
let res = InputKeyMaterialList::import(TEST_STR);
assert!(res.is_ok(), "res: {res:?}");
let lst = res.unwrap();
let res = lst.get_latest_ikm(ts);
assert!(res.is_ok(), "res: {res:?}"); assert!(res.is_ok(), "res: {res:?}");
let ikm = res.unwrap(); let ikm = res.unwrap();
assert_eq!(ikm.id, 3); assert_eq!(ikm.id, 3);
} }
#[test]
fn get_latest_ikm_1_592_734_902() {
let ts = SystemTime::UNIX_EPOCH + Duration::from_secs(1_592_734_902);
let res = InputKeyMaterialList::import(TEST_STR);
assert!(res.is_ok(), "res: {res:?}");
let lst = res.unwrap();
let res = lst.get_latest_ikm(ts);
assert!(res.is_ok(), "res: {res:?}");
let ikm = res.unwrap();
assert_eq!(ikm.id, 2);
}
} }
#[cfg(all(test, feature = "encryption", feature = "ikm-management"))] #[cfg(all(test, feature = "encryption", feature = "ikm-management"))]
@ -540,7 +565,7 @@ mod encryption {
let _ = lst.add_ikm(); let _ = lst.add_ikm();
let (not_before, not_after) = get_default_time_period(); let (not_before, not_after) = get_default_time_period();
let _ = lst.add_custom_ikm(Scheme::XChaCha20Poly1305WithBlake3, not_before, not_after); let _ = lst.add_custom_ikm(Scheme::XChaCha20Poly1305WithBlake3, not_before, not_after);
let res = lst.get_latest_ikm(); let res = lst.get_latest_ikm(SystemTime::now());
assert!(res.is_ok(), "res: {res:?}"); assert!(res.is_ok(), "res: {res:?}");
let latest_ikm = res.unwrap(); let latest_ikm = res.unwrap();
assert_eq!(latest_ikm.id, 3); assert_eq!(latest_ikm.id, 3);
@ -555,7 +580,7 @@ mod encryption {
let _ = lst.add_ikm(); let _ = lst.add_ikm();
let (not_before, not_after) = get_default_time_period(); let (not_before, not_after) = get_default_time_period();
let _ = lst.add_custom_ikm(Scheme::Aes128GcmWithSha256, not_before, not_after); let _ = lst.add_custom_ikm(Scheme::Aes128GcmWithSha256, not_before, not_after);
let res = lst.get_latest_ikm(); let res = lst.get_latest_ikm(SystemTime::now());
assert!(res.is_ok(), "res: {res:?}"); assert!(res.is_ok(), "res: {res:?}");
let latest_ikm = res.unwrap(); let latest_ikm = res.unwrap();
assert_eq!(latest_ikm.id, 3); assert_eq!(latest_ikm.id, 3);
@ -566,7 +591,7 @@ mod encryption {
#[test] #[test]
fn get_latest_ikm_empty() { fn get_latest_ikm_empty() {
let lst = InputKeyMaterialList::new(); let lst = InputKeyMaterialList::new();
let res = lst.get_latest_ikm(); let res = lst.get_latest_ikm(SystemTime::now());
assert!(res.is_err()); assert!(res.is_err());
} }