encryption checkpoint

This commit is contained in:
John Smith 2023-05-24 00:05:27 +01:00
parent fd7257e9bf
commit 5760096fcb
8 changed files with 150 additions and 30 deletions

View File

@ -256,6 +256,20 @@ macro_rules! byte_array_type {
})
}
}
impl core::ops::Deref for $name {
type Target = [u8; $size];
fn deref(&self) -> &Self::Target {
&self.bytes
}
}
impl core::ops::DerefMut for $name {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.bytes
}
}
};
}

View File

@ -97,27 +97,27 @@ pub trait CryptoSystem {
// NoAuth Encrypt/Decrypt
fn crypt_in_place_no_auth(
&self,
body: &mut Vec<u8>,
nonce: &Nonce,
body: &mut [u8],
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
);
fn crypt_b2b_no_auth(
&self,
in_buf: &[u8],
out_buf: &mut [u8],
nonce: &Nonce,
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
);
fn crypt_no_auth_aligned_8(
&self,
body: &[u8],
nonce: &Nonce,
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
) -> Vec<u8>;
fn crypt_no_auth_unaligned(
&self,
body: &[u8],
nonce: &Nonce,
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
) -> Vec<u8>;
}

View File

@ -183,8 +183,11 @@ impl Envelope {
let dh_secret = vcrypto.cached_dh(&self.sender_id, node_id_secret)?;
// Decrypt message without authentication
let body =
vcrypto.crypt_no_auth_aligned_8(&data[0x6A..data.len() - 64], &self.nonce, &dh_secret);
let body = vcrypto.crypt_no_auth_aligned_8(
&data[0x6A..data.len() - 64],
&self.nonce.bytes,
&dh_secret,
);
Ok(body)
}
@ -227,7 +230,7 @@ impl Envelope {
data[0x4A..0x6A].copy_from_slice(&self.recipient_id.bytes);
// Encrypt and authenticate message
let encrypted_body = vcrypto.crypt_no_auth_unaligned(body, &self.nonce, &dh_secret);
let encrypted_body = vcrypto.crypt_no_auth_unaligned(body, &self.nonce.bytes, &dh_secret);
// Write body
if !encrypted_body.is_empty() {

View File

@ -139,6 +139,9 @@ impl Crypto {
trace!("Crypto::init");
let table_store = self.unlocked_inner.table_store.clone();
// Set crypto for table store
table_store.set_crypto(self.clone());
// Init node id from config
if let Err(e) = self
.unlocked_inner

View File

@ -82,8 +82,7 @@ impl CryptoSystem for CryptoSystemNONE {
// Generation
fn random_bytes(&self, len: u32) -> Vec<u8> {
let mut bytes = Vec::<u8>::with_capacity(len as usize);
bytes.resize(len as usize, 0u8);
let mut bytes = unsafe { unaligned_u8_vec_uninit(len as usize) };
random_bytes(bytes.as_mut());
bytes
}
@ -322,12 +321,7 @@ impl CryptoSystem for CryptoSystemNONE {
}
// NoAuth Encrypt/Decrypt
fn crypt_in_place_no_auth(
&self,
body: &mut Vec<u8>,
nonce: &Nonce,
shared_secret: &SharedSecret,
) {
fn crypt_in_place_no_auth(&self, body: &mut [u8], nonce: &Nonce, shared_secret: &SharedSecret) {
let mut blob = nonce.bytes.to_vec();
blob.extend_from_slice(&[0u8; 8]);
let blob = do_xor_32(&blob, &shared_secret.bytes);

View File

@ -76,8 +76,7 @@ impl CryptoSystem for CryptoSystemVLD0 {
// Generation
fn random_bytes(&self, len: u32) -> Vec<u8> {
let mut bytes = Vec::<u8>::with_capacity(len as usize);
bytes.resize(len as usize, 0u8);
let mut bytes = unsafe { unaligned_u8_vec_uninit(len as usize) };
random_bytes(bytes.as_mut());
bytes
}
@ -318,11 +317,11 @@ impl CryptoSystem for CryptoSystemVLD0 {
// NoAuth Encrypt/Decrypt
fn crypt_in_place_no_auth(
&self,
body: &mut Vec<u8>,
nonce: &Nonce,
body: &mut [u8],
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
) {
let mut cipher = XChaCha20::new(&shared_secret.bytes.into(), &nonce.bytes.into());
let mut cipher = XChaCha20::new(&shared_secret.bytes.into(), nonce.into());
cipher.apply_keystream(body);
}
@ -330,17 +329,17 @@ impl CryptoSystem for CryptoSystemVLD0 {
&self,
in_buf: &[u8],
out_buf: &mut [u8],
nonce: &Nonce,
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
) {
let mut cipher = XChaCha20::new(&shared_secret.bytes.into(), &nonce.bytes.into());
let mut cipher = XChaCha20::new(&shared_secret.bytes.into(), nonce.into());
cipher.apply_keystream_b2b(in_buf, out_buf).unwrap();
}
fn crypt_no_auth_aligned_8(
&self,
in_buf: &[u8],
nonce: &Nonce,
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
) -> Vec<u8> {
let mut out_buf = unsafe { aligned_8_u8_vec_uninit(in_buf.len()) };
@ -351,7 +350,7 @@ impl CryptoSystem for CryptoSystemVLD0 {
fn crypt_no_auth_unaligned(
&self,
in_buf: &[u8],
nonce: &Nonce,
nonce: &[u8; NONCE_LENGTH],
shared_secret: &SharedSecret,
) -> Vec<u8> {
let mut out_buf = unsafe { unaligned_u8_vec_uninit(in_buf.len()) };

View File

@ -10,11 +10,26 @@ cfg_if! {
}
}
struct CryptInfo {
vcrypto: CryptoSystemVersion,
key: SharedSecret,
}
impl CryptInfo {
pub fn new(crypto: Crypto, typed_key: TypedSharedSecret) -> Self {
let vcrypto = crypto.get(typed_key.kind).unwrap();
let key = typed_key.value;
Self { vcrypto, key }
}
}
pub struct TableDBUnlockedInner {
table: String,
table_store: TableStore,
crypto: Crypto,
database: Database,
encryption_key: Option<TypedSharedSecret>,
// Encryption and decryption key will be the same unless configured for an in-place migration
encrypt_info: Option<CryptInfo>,
decrypt_info: Option<CryptInfo>,
}
impl fmt::Debug for TableDBUnlockedInner {
@ -38,15 +53,22 @@ impl TableDB {
pub(super) fn new(
table: String,
table_store: TableStore,
crypto: Crypto,
database: Database,
encryption_key: Option<TypedSharedSecret>,
decryption_key: Option<TypedSharedSecret>,
) -> Self {
let encrypt_info = encryption_key.map(|ek| CryptInfo::new(crypto.clone(), ek));
let decrypt_info = dcryption_key.map(|dk| CryptInfo::new(crypto.clone(), dk));
Self {
unlocked_inner: Arc::new(TableDBUnlockedInner {
table,
table_store,
crypto,
database,
encryption_key,
encrypt_info,
decrypt_info,
}),
}
}
@ -67,8 +89,46 @@ impl TableDB {
db.num_columns().map_err(VeilidAPIError::from)
}
fn maybe_encrypt(&self, data: &[u8]) -> Vec<u8> {
if let Some(ei) = &self.unlocked_inner.encrypt_info {
let mut out = unsafe { unaligned_u8_vec_uninit(NONCE_LENGTH + data.len()) };
random_bytes(&mut out[0..NONCE_LENGTH]);
ei.vcrypto.crypt_b2b_no_auth(
data,
&mut out[NONCE_LENGTH..],
&out[0..NONCE_LENGTH],
&ei.key,
);
out
} else {
data.to_vec()
}
}
fn maybe_decrypt(&self, data: &[u8]) -> VeilidAPIResult<Vec<u8>> {
if let Some(di) = &self.unlocked_inner.decrypt_info {
if data.len() <= NONCE_LENGTH {
return Err(VeilidAPIError::internal("data too short"));
}
xxxx make decrypt
let mut out = unsafe { unaligned_u8_vec_uninit(NONCE_LENGTH + data.len()) };
random_bytes(&mut out[0..NONCE_LENGTH]);
ei.vcrypto.crypt_b2b_no_auth(
data,
&mut out[NONCE_LENGTH..],
&out[0..NONCE_LENGTH],
&ei.key,
);
out
} else {
Ok(data.to_vec())
}
}
/// Get the list of keys in a column of the TableDB
pub async fn get_keys(&self, col: u32) -> VeilidAPIResult<Vec<Box<[u8]>>> {
pub async fn get_keys(&self, col: u32) -> VeilidAPIResult<Vec<Vec<u8>>> {
let db = self.unlocked_inner.database.clone();
let mut out: Vec<Box<[u8]>> = Vec::new();
db.iter(col, None, |kv| {

View File

@ -6,6 +6,7 @@ struct TableStoreInner {
encryption_key: Option<TypedSharedSecret>,
all_table_names: HashMap<String, String>,
all_tables_db: Option<Database>,
crypto: Option<Crypto>,
}
/// Veilid Table Storage
@ -26,6 +27,7 @@ impl TableStore {
encryption_key: None,
all_table_names: HashMap::new(),
all_tables_db: None,
crypto: None,
}
}
pub(crate) fn new(config: VeilidConfig, protected_store: ProtectedStore) -> Self {
@ -41,6 +43,11 @@ impl TableStore {
}
}
pub(crate) fn set_crypto(&self, crypto: Crypto) {
let mut inner = self.inner.lock();
inner.crypto = Some(crypto);
}
// Flush internal control state
async fn flush(&self) {
let (all_table_names_value, all_tables_db) = {
@ -54,7 +61,7 @@ impl TableStore {
if let Err(e) = all_tables_db.write(dbt).await {
error!("failed to write all tables db: {}", e);
}
} xxx must from_rkyv the all_table_names
}
// Internal naming support
// Adds rename capability and ensures names of tables are totally unique and valid
@ -159,16 +166,50 @@ impl TableStore {
pub(crate) async fn init(&self) -> EyreResult<()> {
let _async_guard = self.async_lock.lock().await;
let encryption_key: Option<TypedSharedSecret> = self
// Get device encryption key from protected store
let mut encryption_key: Option<TypedSharedSecret> = self
.protected_store
.load_user_secret_rkyv("device_encryption_key")
.await?;
if let Some(encryption_key) = encryption_key {
// If encryption in current use is not the best encryption, then run table migration
let best_kind = best_crypto_kind();
if encryption_key.kind != best_kind {
// XXX: Run migration. See issue #209
}
} else {
// If we don't have an encryption key yet, then make one with the best cryptography and save it
let best_kind = best_crypto_kind();
let mut shared_secret = SharedSecret::default();
random_bytes(&mut shared_secret.bytes);
encryption_key = Some(TypedSharedSecret::new(best_kind, shared_secret));
}
// Deserialize all table names
let all_tables_db = self
.table_store_driver
.open("__veilid_all_tables", 1)
.await
.wrap_err("failed to create all tables table")?;
match all_tables_db.get(0, b"all_table_names").await {
Ok(Some(v)) => match from_rkyv::<HashMap<String, String>>(v) {
Ok(all_table_names) => {
let mut inner = self.inner.lock();
inner.all_table_names = all_table_names;
}
Err(e) => {
error!("could not deserialize __veilid_all_tables: {}", e);
}
},
Ok(None) => {
// No table names yet, that's okay
trace!("__veilid_all_tables is empty");
}
Err(e) => {
error!("could not get __veilid_all_tables: {}", e);
}
};
{
let mut inner = self.inner.lock();
@ -190,6 +231,9 @@ impl TableStore {
pub(crate) async fn terminate(&self) {
let _async_guard = self.async_lock.lock().await;
self.flush().await;
let mut inner = self.inner.lock();
if !inner.opened.is_empty() {
panic!(
@ -198,6 +242,7 @@ impl TableStore {
);
}
inner.all_tables_db = None;
inner.all_table_names.clear();
inner.encryption_key = None;
}
@ -251,8 +296,10 @@ impl TableStore {
let table_db = TableDB::new(
table_name.clone(),
self.clone(),
inner.crypto.as_ref().unwrap().clone(),
db,
inner.encryption_key.clone(),
inner.encryption_key.clone(),
);
// Keep track of opened DBs