mirror of
https://gitlab.com/veilid/veilid.git
synced 2024-12-24 23:09:25 -05:00
encryption checkpoint
This commit is contained in:
parent
fd7257e9bf
commit
5760096fcb
@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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>;
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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()) };
|
||||
|
@ -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| {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user