Parse the stored encrypted data
This commit is contained in:
parent
9df9fa6bf5
commit
16d4e19617
2 changed files with 75 additions and 12 deletions
|
@ -14,6 +14,10 @@ pub enum Error {
|
||||||
ParsingInvalidLength(usize),
|
ParsingInvalidLength(usize),
|
||||||
#[error("parsing error: {0}: unknown scheme")]
|
#[error("parsing error: {0}: unknown scheme")]
|
||||||
ParsingUnknownScheme(u32),
|
ParsingUnknownScheme(u32),
|
||||||
|
#[error("parsing error: encoded data: invalid IKM id: {0:?}")]
|
||||||
|
ParsingEncodedDataInvalidIkmId(Vec<u8>),
|
||||||
|
#[error("parsing error: encoded data: invalid number of parts: got {1} instead of {0}")]
|
||||||
|
ParsingEncodedDataInvalidPartLen(usize, usize),
|
||||||
#[error("unable to generate random values: {0}")]
|
#[error("unable to generate random values: {0}")]
|
||||||
RandomSourceError(getrandom::Error),
|
RandomSourceError(getrandom::Error),
|
||||||
#[error("system time error: {0}")]
|
#[error("system time error: {0}")]
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
use crate::encryption::EncryptedData;
|
use crate::encryption::EncryptedData;
|
||||||
use crate::Error;
|
use crate::error::{Error, Result};
|
||||||
use base64ct::{Base64UrlUnpadded, Encoding};
|
use base64ct::{Base64UrlUnpadded, Encoding};
|
||||||
|
|
||||||
const STORAGE_SEPARATOR: &str = ":";
|
const STORAGE_SEPARATOR: &str = ":";
|
||||||
|
const NB_PARTS: usize = 3;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn encode_data(data: &[u8]) -> String {
|
fn encode_data(data: &[u8]) -> String {
|
||||||
Base64UrlUnpadded::encode_string(data)
|
Base64UrlUnpadded::encode_string(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn decode_data(s: &str) -> Result<Vec<u8>> {
|
||||||
|
Ok(Base64UrlUnpadded::decode_vec(s)?)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn encode(ikm_id: u32, encrypted_data: &EncryptedData) -> String {
|
pub(crate) fn encode(ikm_id: u32, encrypted_data: &EncryptedData) -> 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());
|
||||||
|
@ -19,24 +25,77 @@ pub(crate) fn encode(ikm_id: u32, encrypted_data: &EncryptedData) -> String {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn decode(data: &str) -> Result<(u32, EncryptedData)> {
|
||||||
|
let v: Vec<&str> = data.split(STORAGE_SEPARATOR).collect();
|
||||||
|
if v.len() != NB_PARTS {
|
||||||
|
return Err(Error::ParsingEncodedDataInvalidPartLen(NB_PARTS, v.len()));
|
||||||
|
}
|
||||||
|
let id_raw = decode_data(v[0])?;
|
||||||
|
let id_raw: [u8; 4] = id_raw
|
||||||
|
.clone()
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| Error::ParsingEncodedDataInvalidIkmId(id_raw))?;
|
||||||
|
let id = u32::from_le_bytes(id_raw);
|
||||||
|
let encrypted_data = EncryptedData {
|
||||||
|
nonce: decode_data(v[1])?,
|
||||||
|
ciphertext: decode_data(v[2])?,
|
||||||
|
};
|
||||||
|
Ok((id, encrypted_data))
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::storage::EncryptedData;
|
use crate::storage::EncryptedData;
|
||||||
|
|
||||||
|
const TEST_STR: &str = "KgAAAA:a5SpjAoqhvuI9n3GPhDKuotqoLbf7_Fb:TI24Wr_g-ZV7_X1oHqVKak9iRlQSneYVOMWB-3Lp-hFHKfxfnY-zR_bN";
|
||||||
|
const TEST_IKM_ID: u32 = 42;
|
||||||
|
const TEST_NONCE: &'static [u8] = &[
|
||||||
|
0x6b, 0x94, 0xa9, 0x8c, 0x0a, 0x2a, 0x86, 0xfb, 0x88, 0xf6, 0x7d, 0xc6, 0x3e, 0x10, 0xca,
|
||||||
|
0xba, 0x8b, 0x6a, 0xa0, 0xb6, 0xdf, 0xef, 0xf1, 0x5b,
|
||||||
|
];
|
||||||
|
const TEST_CIPHERTEXT: &'static [u8] = &[
|
||||||
|
0x4c, 0x8d, 0xb8, 0x5a, 0xbf, 0xe0, 0xf9, 0x95, 0x7b, 0xfd, 0x7d, 0x68, 0x1e, 0xa5, 0x4a,
|
||||||
|
0x6a, 0x4f, 0x62, 0x46, 0x54, 0x12, 0x9d, 0xe6, 0x15, 0x38, 0xc5, 0x81, 0xfb, 0x72, 0xe9,
|
||||||
|
0xfa, 0x11, 0x47, 0x29, 0xfc, 0x5f, 0x9d, 0x8f, 0xb3, 0x47, 0xf6, 0xcd,
|
||||||
|
];
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encode() {
|
fn encode() {
|
||||||
let data = EncryptedData {
|
let data = EncryptedData {
|
||||||
nonce: vec![
|
nonce: TEST_NONCE.into(),
|
||||||
0x6b, 0x94, 0xa9, 0x8c, 0x0a, 0x2a, 0x86, 0xfb, 0x88, 0xf6, 0x7d, 0xc6, 0x3e, 0x10,
|
ciphertext: TEST_CIPHERTEXT.into(),
|
||||||
0xca, 0xba, 0x8b, 0x6a, 0xa0, 0xb6, 0xdf, 0xef, 0xf1, 0x5b,
|
|
||||||
],
|
|
||||||
ciphertext: vec![
|
|
||||||
0x4c, 0x8d, 0xb8, 0x5a, 0xbf, 0xe0, 0xf9, 0x95, 0x7b, 0xfd, 0x7d, 0x68, 0x1e, 0xa5,
|
|
||||||
0x4a, 0x6a, 0x4f, 0x62, 0x46, 0x54, 0x12, 0x9d, 0xe6, 0x15, 0x38, 0xc5, 0x81, 0xfb,
|
|
||||||
0x72, 0xe9, 0xfa, 0x11, 0x47, 0x29, 0xfc, 0x5f, 0x9d, 0x8f, 0xb3, 0x47, 0xf6, 0xcd,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
let s = super::encode(42, &data);
|
let s = super::encode(TEST_IKM_ID, &data);
|
||||||
assert_eq!(&s, "KgAAAA:a5SpjAoqhvuI9n3GPhDKuotqoLbf7_Fb:TI24Wr_g-ZV7_X1oHqVKak9iRlQSneYVOMWB-3Lp-hFHKfxfnY-zR_bN");
|
assert_eq!(&s, TEST_STR);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode() {
|
||||||
|
let res = super::decode(TEST_STR);
|
||||||
|
assert!(res.is_ok());
|
||||||
|
let (id, data) = res.unwrap();
|
||||||
|
assert_eq!(id, TEST_IKM_ID);
|
||||||
|
assert_eq!(data.nonce, TEST_NONCE);
|
||||||
|
assert_eq!(data.ciphertext, TEST_CIPHERTEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn encode_decode() {
|
||||||
|
let data = EncryptedData {
|
||||||
|
nonce: TEST_NONCE.into(),
|
||||||
|
ciphertext: TEST_CIPHERTEXT.into(),
|
||||||
|
};
|
||||||
|
let s = super::encode(TEST_IKM_ID, &data);
|
||||||
|
let (id, decoded_data) = super::decode(TEST_STR).unwrap();
|
||||||
|
assert_eq!(id, TEST_IKM_ID);
|
||||||
|
assert_eq!(decoded_data.nonce, data.nonce);
|
||||||
|
assert_eq!(decoded_data.ciphertext, data.ciphertext);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn decode_encode() {
|
||||||
|
let (id, data) = super::decode(TEST_STR).unwrap();
|
||||||
|
let s = super::encode(id, &data);
|
||||||
|
assert_eq!(&s, TEST_STR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue