Use the time period instead of the timestamp

This commit is contained in:
Rodolphe Bréard 2024-03-09 11:49:40 +01:00
parent 4e40314c67
commit 9e3cfc2fd6
3 changed files with 40 additions and 33 deletions

View file

@ -17,9 +17,9 @@ pub(crate) struct EncryptedData {
fn generate_aad( fn generate_aad(
key_context: &KeyContext, key_context: &KeyContext,
data_context: &[impl AsRef<[u8]>], data_context: &[impl AsRef<[u8]>],
ts: Option<u64>, time_period: Option<u64>,
) -> String { ) -> String {
let key_context_canon = canonicalize(&key_context.get_value(ts)); let key_context_canon = canonicalize(&key_context.get_value(time_period));
let data_context_canon = canonicalize(data_context); let data_context_canon = canonicalize(data_context);
join_canonicalized_str(&key_context_canon, &data_context_canon) join_canonicalized_str(&key_context_canon, &data_context_canon)
} }
@ -30,17 +30,18 @@ pub fn encrypt(
data: impl AsRef<[u8]>, data: impl AsRef<[u8]>,
data_context: &[impl AsRef<[u8]>], data_context: &[impl AsRef<[u8]>],
) -> Result<String> { ) -> Result<String> {
let ts = if key_context.is_periodic() { let tp = if key_context.is_periodic() {
Some(SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs()) let ts = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
key_context.get_time_period(ts)
} else { } else {
None None
}; };
let ikm = ikml.get_latest_ikm()?; let ikm = ikml.get_latest_ikm()?;
let key = derive_key(ikm, key_context, ts); let key = derive_key(ikm, key_context, tp);
let aad = generate_aad(key_context, data_context, ts); let aad = generate_aad(key_context, data_context, tp);
let encryption_function = ikm.scheme.get_encryption(); let encryption_function = ikm.scheme.get_encryption();
let encrypted_data = encryption_function(&key, data.as_ref(), &aad)?; let encrypted_data = encryption_function(&key, data.as_ref(), &aad)?;
Ok(storage::encode_cipher(ikm.id, &encrypted_data, ts)) Ok(storage::encode_cipher(ikm.id, &encrypted_data, tp))
} }
pub fn decrypt( pub fn decrypt(
@ -49,10 +50,10 @@ pub fn decrypt(
stored_data: &str, stored_data: &str,
data_context: &[impl AsRef<[u8]>], data_context: &[impl AsRef<[u8]>],
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
let (ikm_id, encrypted_data, ts) = storage::decode_cipher(stored_data)?; let (ikm_id, encrypted_data, tp) = storage::decode_cipher(stored_data)?;
let ikm = ikml.get_ikm_by_id(ikm_id)?; let ikm = ikml.get_ikm_by_id(ikm_id)?;
let key = derive_key(ikm, key_context, ts); let key = derive_key(ikm, key_context, tp);
let aad = generate_aad(key_context, data_context, ts); let aad = generate_aad(key_context, data_context, tp);
let decryption_function = ikm.scheme.get_decryption(); let decryption_function = ikm.scheme.get_decryption();
decryption_function(&key, &encrypted_data, &aad) decryption_function(&key, &encrypted_data, &aad)
} }

View file

@ -9,16 +9,18 @@ pub struct KeyContext {
} }
impl KeyContext { impl KeyContext {
pub(crate) fn get_value(&self, ts: Option<u64>) -> Vec<Vec<u8>> { pub(crate) fn get_value(&self, time_period: Option<u64>) -> Vec<Vec<u8>> {
let mut ret: Vec<Vec<u8>> = self.ctx.iter().map(|s| s.as_bytes().to_vec()).collect(); let mut ret: Vec<Vec<u8>> = self.ctx.iter().map(|s| s.as_bytes().to_vec()).collect();
if let Some(p) = self.periodicity { if let Some(tp) = time_period {
let ts = ts.unwrap_or(0); ret.push(tp.to_le_bytes().to_vec());
let c = ts % p;
ret.push(c.to_le_bytes().to_vec());
} }
ret ret
} }
pub(crate) fn get_time_period(&self, timestamp: u64) -> Option<u64> {
self.periodicity.map(|p| timestamp / p)
}
pub(crate) fn is_periodic(&self) -> bool { pub(crate) fn is_periodic(&self) -> bool {
self.periodicity.is_some() self.periodicity.is_some()
} }
@ -33,8 +35,12 @@ impl<const N: usize> From<[&str; N]> for KeyContext {
} }
} }
pub(crate) fn derive_key(ikm: &InputKeyMaterial, ctx: &KeyContext, ts: Option<u64>) -> Vec<u8> { pub(crate) fn derive_key(
let key_context = canonicalize(&ctx.get_value(ts)); ikm: &InputKeyMaterial,
ctx: &KeyContext,
time_period: Option<u64>,
) -> Vec<u8> {
let key_context = canonicalize(&ctx.get_value(time_period));
let kdf = ikm.scheme.get_kdf(); let kdf = ikm.scheme.get_kdf();
kdf(&key_context, &ikm.content) kdf(&key_context, &ikm.content)
} }

View file

@ -32,7 +32,7 @@ pub(crate) fn encode_ikm_list(ikml: &InputKeyMaterialList) -> Result<String> {
pub(crate) fn encode_cipher( pub(crate) fn encode_cipher(
ikm_id: IkmId, ikm_id: IkmId,
encrypted_data: &EncryptedData, encrypted_data: &EncryptedData,
ts: Option<u64>, time_period: Option<u64>,
) -> String { ) -> String {
let mut ret = String::new(); let mut ret = String::new();
ret += &encode_data(&ikm_id.to_le_bytes()); ret += &encode_data(&ikm_id.to_le_bytes());
@ -40,9 +40,9 @@ pub(crate) fn encode_cipher(
ret += &encode_data(&encrypted_data.nonce); ret += &encode_data(&encrypted_data.nonce);
ret += STORAGE_SEPARATOR; ret += STORAGE_SEPARATOR;
ret += &encode_data(&encrypted_data.ciphertext); ret += &encode_data(&encrypted_data.ciphertext);
if let Some(ts) = ts { if let Some(time_period) = time_period {
ret += STORAGE_SEPARATOR; ret += STORAGE_SEPARATOR;
ret += &encode_data(&ts.to_le_bytes()); ret += &encode_data(&time_period.to_le_bytes());
} }
ret ret
} }
@ -68,15 +68,15 @@ pub(crate) fn decode_ikm_list(data: &str) -> Result<InputKeyMaterialList> {
pub(crate) fn decode_cipher(data: &str) -> Result<(IkmId, EncryptedData, Option<u64>)> { pub(crate) fn decode_cipher(data: &str) -> Result<(IkmId, EncryptedData, Option<u64>)> {
let mut v: Vec<&str> = data.split(STORAGE_SEPARATOR).collect(); let mut v: Vec<&str> = data.split(STORAGE_SEPARATOR).collect();
let ts = if v.len() == NB_PARTS + 1 { let time_period = if v.len() == NB_PARTS + 1 {
match v.pop() { match v.pop() {
Some(ts_raw) => { Some(tp_raw) => {
let ts_raw = decode_data(ts_raw)?; let tp_raw = decode_data(tp_raw)?;
let ts_raw: [u8; 8] = ts_raw let tp_raw: [u8; 8] = tp_raw
.clone() .clone()
.try_into() .try_into()
.map_err(|_| Error::ParsingEncodedDataInvalidTimestamp(ts_raw))?; .map_err(|_| Error::ParsingEncodedDataInvalidTimestamp(tp_raw))?;
Some(u64::from_le_bytes(ts_raw)) Some(u64::from_le_bytes(tp_raw))
} }
None => None, None => None,
} }
@ -96,7 +96,7 @@ pub(crate) fn decode_cipher(data: &str) -> Result<(IkmId, EncryptedData, Option<
nonce: decode_data(v[1])?, nonce: decode_data(v[1])?,
ciphertext: decode_data(v[2])?, ciphertext: decode_data(v[2])?,
}; };
Ok((id, encrypted_data, ts)) Ok((id, encrypted_data, time_period))
} }
#[cfg(test)] #[cfg(test)]
@ -130,11 +130,11 @@ mod tests {
fn decode() { fn decode() {
let res = super::decode_cipher(TEST_STR); let res = super::decode_cipher(TEST_STR);
assert!(res.is_ok(), "res: {res:?}"); assert!(res.is_ok(), "res: {res:?}");
let (id, data, ts) = res.unwrap(); let (id, data, tp) = res.unwrap();
assert_eq!(id, TEST_IKM_ID); assert_eq!(id, TEST_IKM_ID);
assert_eq!(data.nonce, TEST_NONCE); assert_eq!(data.nonce, TEST_NONCE);
assert_eq!(data.ciphertext, TEST_CIPHERTEXT); assert_eq!(data.ciphertext, TEST_CIPHERTEXT);
assert_eq!(ts, None); assert_eq!(tp, None);
} }
#[test] #[test]
@ -144,17 +144,17 @@ mod tests {
ciphertext: TEST_CIPHERTEXT.into(), ciphertext: TEST_CIPHERTEXT.into(),
}; };
let s = super::encode_cipher(TEST_IKM_ID, &data, None); let s = super::encode_cipher(TEST_IKM_ID, &data, None);
let (id, decoded_data, ts) = super::decode_cipher(&s).unwrap(); let (id, decoded_data, tp) = super::decode_cipher(&s).unwrap();
assert_eq!(id, TEST_IKM_ID); assert_eq!(id, TEST_IKM_ID);
assert_eq!(decoded_data.nonce, data.nonce); assert_eq!(decoded_data.nonce, data.nonce);
assert_eq!(decoded_data.ciphertext, data.ciphertext); assert_eq!(decoded_data.ciphertext, data.ciphertext);
assert_eq!(ts, None); assert_eq!(tp, None);
} }
#[test] #[test]
fn decode_encode() { fn decode_encode() {
let (id, data, ts) = super::decode_cipher(TEST_STR).unwrap(); let (id, data, tp) = super::decode_cipher(TEST_STR).unwrap();
let s = super::encode_cipher(id, &data, ts); let s = super::encode_cipher(id, &data, tp);
assert_eq!(&s, TEST_STR); assert_eq!(&s, TEST_STR);
} }
} }