2023-03-13 16:14:31 -04:00
|
|
|
mod blake3digest512;
|
2023-02-07 21:44:50 -05:00
|
|
|
mod byte_array_types;
|
2023-02-11 15:54:55 -05:00
|
|
|
mod dh_cache;
|
2022-10-30 19:29:31 -04:00
|
|
|
mod envelope;
|
|
|
|
mod receipt;
|
2023-02-07 21:44:50 -05:00
|
|
|
mod types;
|
2022-10-30 19:29:31 -04:00
|
|
|
|
2023-01-29 13:13:50 -05:00
|
|
|
pub mod crypto_system;
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-none")]
|
|
|
|
pub mod none;
|
2022-10-30 19:29:31 -04:00
|
|
|
pub mod tests;
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-vld0")]
|
2023-02-07 21:44:50 -05:00
|
|
|
pub mod vld0;
|
2022-10-30 19:29:31 -04:00
|
|
|
|
2023-03-13 16:14:31 -04:00
|
|
|
pub use blake3digest512::*;
|
2023-02-07 21:44:50 -05:00
|
|
|
pub use byte_array_types::*;
|
2023-01-29 13:13:50 -05:00
|
|
|
pub use crypto_system::*;
|
2023-02-11 15:54:55 -05:00
|
|
|
pub use dh_cache::*;
|
2022-10-30 19:29:31 -04:00
|
|
|
pub use envelope::*;
|
|
|
|
pub use receipt::*;
|
2023-02-07 21:44:50 -05:00
|
|
|
pub use types::*;
|
2023-03-13 16:14:31 -04:00
|
|
|
|
|
|
|
#[cfg(feature = "enable-crypto-none")]
|
|
|
|
pub use none::*;
|
|
|
|
#[cfg(feature = "enable-crypto-vld0")]
|
2023-02-07 21:44:50 -05:00
|
|
|
pub use vld0::*;
|
2022-10-30 19:29:31 -04:00
|
|
|
|
2023-06-03 18:33:27 -04:00
|
|
|
use super::*;
|
2021-11-22 11:28:30 -05:00
|
|
|
use core::convert::TryInto;
|
2022-03-20 10:52:03 -04:00
|
|
|
use hashlink::linked_hash_map::Entry;
|
|
|
|
use hashlink::LruCache;
|
2022-11-29 19:22:33 -05:00
|
|
|
|
2023-03-13 16:14:31 -04:00
|
|
|
/// Handle to a particular cryptosystem
|
2023-01-29 13:13:50 -05:00
|
|
|
pub type CryptoSystemVersion = Arc<dyn CryptoSystem + Send + Sync>;
|
|
|
|
|
2023-03-13 16:14:31 -04:00
|
|
|
cfg_if! {
|
|
|
|
if #[cfg(all(feature = "enable-crypto-none", feature = "enable-crypto-vld0"))] {
|
|
|
|
/// Crypto kinds in order of preference, best cryptosystem is the first one, worst is the last one
|
|
|
|
pub const VALID_CRYPTO_KINDS: [CryptoKind; 2] = [CRYPTO_KIND_VLD0, CRYPTO_KIND_NONE];
|
|
|
|
}
|
|
|
|
else if #[cfg(feature = "enable-crypto-none")] {
|
|
|
|
/// Crypto kinds in order of preference, best cryptosystem is the first one, worst is the last one
|
|
|
|
pub const VALID_CRYPTO_KINDS: [CryptoKind; 1] = [CRYPTO_KIND_NONE];
|
|
|
|
}
|
|
|
|
else if #[cfg(feature = "enable-crypto-vld0")] {
|
|
|
|
/// Crypto kinds in order of preference, best cryptosystem is the first one, worst is the last one
|
|
|
|
pub const VALID_CRYPTO_KINDS: [CryptoKind; 1] = [CRYPTO_KIND_VLD0];
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
compile_error!("No crypto kinds enabled, specify an enable-crypto- feature");
|
|
|
|
}
|
|
|
|
}
|
2023-02-13 21:12:27 -05:00
|
|
|
/// Number of cryptosystem signatures to keep on structures if many are present beyond the ones we consider valid
|
|
|
|
pub const MAX_CRYPTO_KINDS: usize = 3;
|
|
|
|
/// Return the best cryptosystem kind we support
|
2023-02-11 15:54:55 -05:00
|
|
|
pub fn best_crypto_kind() -> CryptoKind {
|
|
|
|
VALID_CRYPTO_KINDS[0]
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
2023-03-13 16:14:31 -04:00
|
|
|
/// Version number of envelope format
|
2023-02-11 15:54:55 -05:00
|
|
|
pub type EnvelopeVersion = u8;
|
2023-02-15 18:18:08 -05:00
|
|
|
|
|
|
|
/// Envelope versions in order of preference, best envelope version is the first one, worst is the last one
|
2023-02-11 15:54:55 -05:00
|
|
|
pub const VALID_ENVELOPE_VERSIONS: [EnvelopeVersion; 1] = [0u8];
|
2023-02-15 18:18:08 -05:00
|
|
|
/// Number of envelope versions to keep on structures if many are present beyond the ones we consider valid
|
|
|
|
pub const MAX_ENVELOPE_VERSIONS: usize = 3;
|
|
|
|
/// Return the best envelope version we support
|
2023-02-11 15:54:55 -05:00
|
|
|
pub fn best_envelope_version() -> EnvelopeVersion {
|
|
|
|
VALID_ENVELOPE_VERSIONS[0]
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
struct CryptoInner {
|
|
|
|
dh_cache: DHCache,
|
2022-07-14 16:57:34 -04:00
|
|
|
flush_future: Option<SendPinBoxFuture<()>>,
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-vld0")]
|
2023-02-07 21:44:50 -05:00
|
|
|
crypto_vld0: Option<Arc<dyn CryptoSystem + Send + Sync>>,
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-none")]
|
|
|
|
crypto_none: Option<Arc<dyn CryptoSystem + Send + Sync>>,
|
2023-02-07 21:44:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
struct CryptoUnlockedInner {
|
|
|
|
config: VeilidConfig,
|
|
|
|
table_store: TableStore,
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:50 -05:00
|
|
|
/// Crypto factory implementation
|
2021-11-22 11:28:30 -05:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct Crypto {
|
2023-02-07 21:44:50 -05:00
|
|
|
unlocked_inner: Arc<CryptoUnlockedInner>,
|
2021-11-22 11:28:30 -05:00
|
|
|
inner: Arc<Mutex<CryptoInner>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Crypto {
|
2023-02-07 21:44:50 -05:00
|
|
|
fn new_inner() -> CryptoInner {
|
2021-11-22 11:28:30 -05:00
|
|
|
CryptoInner {
|
2022-03-20 10:52:03 -04:00
|
|
|
dh_cache: DHCache::new(DH_CACHE_SIZE),
|
2021-11-22 11:28:30 -05:00
|
|
|
flush_future: None,
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-vld0")]
|
2023-02-07 21:44:50 -05:00
|
|
|
crypto_vld0: None,
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-none")]
|
|
|
|
crypto_none: None,
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-29 19:24:57 +00:00
|
|
|
pub fn new(config: VeilidConfig, table_store: TableStore) -> Self {
|
2023-01-29 13:13:50 -05:00
|
|
|
let out = Self {
|
2023-02-07 21:44:50 -05:00
|
|
|
unlocked_inner: Arc::new(CryptoUnlockedInner {
|
|
|
|
config,
|
|
|
|
table_store,
|
|
|
|
}),
|
|
|
|
inner: Arc::new(Mutex::new(Self::new_inner())),
|
2023-01-29 13:13:50 -05:00
|
|
|
};
|
|
|
|
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-vld0")]
|
|
|
|
{
|
|
|
|
out.inner.lock().crypto_vld0 = Some(Arc::new(vld0::CryptoSystemVLD0::new(out.clone())));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "enable-crypto-none")]
|
|
|
|
{
|
|
|
|
out.inner.lock().crypto_none = Some(Arc::new(none::CryptoSystemNONE::new(out.clone())));
|
|
|
|
}
|
2023-01-29 13:13:50 -05:00
|
|
|
|
|
|
|
out
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
2023-02-13 21:12:27 -05:00
|
|
|
pub fn config(&self) -> VeilidConfig {
|
|
|
|
self.unlocked_inner.config.clone()
|
|
|
|
}
|
|
|
|
|
2022-07-10 17:36:50 -04:00
|
|
|
pub async fn init(&self) -> EyreResult<()> {
|
2021-11-22 11:28:30 -05:00
|
|
|
trace!("Crypto::init");
|
2023-02-07 21:44:50 -05:00
|
|
|
let table_store = self.unlocked_inner.table_store.clone();
|
|
|
|
// Init node id from config
|
|
|
|
if let Err(e) = self
|
|
|
|
.unlocked_inner
|
|
|
|
.config
|
2023-05-29 19:24:57 +00:00
|
|
|
.init_node_ids(self.clone(), table_store.clone())
|
2023-02-07 21:44:50 -05:00
|
|
|
.await
|
|
|
|
{
|
|
|
|
return Err(e).wrap_err("init node id failed");
|
|
|
|
}
|
2021-11-22 11:28:30 -05:00
|
|
|
|
|
|
|
// make local copy of node id for easy access
|
2023-02-07 21:44:50 -05:00
|
|
|
let mut cache_validity_key: Vec<u8> = Vec::new();
|
|
|
|
{
|
|
|
|
let c = self.unlocked_inner.config.get();
|
2023-03-03 10:55:31 -05:00
|
|
|
for ck in VALID_CRYPTO_KINDS {
|
2023-06-22 18:31:31 -04:00
|
|
|
if let Some(nid) = c.network.routing_table.node_id.get(ck) {
|
|
|
|
cache_validity_key.append(&mut nid.value.bytes.to_vec());
|
|
|
|
}
|
2023-02-07 21:44:50 -05:00
|
|
|
}
|
2022-02-06 21:18:42 -05:00
|
|
|
};
|
2021-11-22 11:28:30 -05:00
|
|
|
|
|
|
|
// load caches if they are valid for this node id
|
2023-05-29 19:24:57 +00:00
|
|
|
let mut db = table_store
|
|
|
|
.open("crypto_caches", 1)
|
|
|
|
.await
|
|
|
|
.wrap_err("failed to open crypto_caches")?;
|
|
|
|
let caches_valid = match db.load(0, b"cache_validity_key").await? {
|
2023-02-07 21:44:50 -05:00
|
|
|
Some(v) => v == cache_validity_key,
|
2021-11-22 11:28:30 -05:00
|
|
|
None => false,
|
|
|
|
};
|
|
|
|
if caches_valid {
|
2023-05-29 19:24:57 +00:00
|
|
|
if let Some(b) = db.load(0, b"dh_cache").await? {
|
2022-02-06 21:18:42 -05:00
|
|
|
let mut inner = self.inner.lock();
|
2021-11-26 11:50:49 -05:00
|
|
|
bytes_to_cache(&b, &mut inner.dh_cache);
|
|
|
|
}
|
2021-11-22 11:28:30 -05:00
|
|
|
} else {
|
|
|
|
drop(db);
|
2022-02-06 21:18:42 -05:00
|
|
|
table_store.delete("crypto_caches").await?;
|
|
|
|
db = table_store.open("crypto_caches", 1).await?;
|
2023-02-07 21:44:50 -05:00
|
|
|
db.store(0, b"cache_validity_key", &cache_validity_key)
|
|
|
|
.await?;
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Schedule flushing
|
|
|
|
let this = self.clone();
|
2022-11-26 21:37:23 -05:00
|
|
|
let flush_future = interval(60000, move || {
|
2021-11-22 11:28:30 -05:00
|
|
|
let this = this.clone();
|
|
|
|
async move {
|
|
|
|
if let Err(e) = this.flush().await {
|
|
|
|
warn!("flush failed: {}", e);
|
|
|
|
}
|
|
|
|
}
|
2022-02-06 21:18:42 -05:00
|
|
|
});
|
|
|
|
self.inner.lock().flush_future = Some(flush_future);
|
2021-11-22 11:28:30 -05:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2022-07-10 17:36:50 -04:00
|
|
|
pub async fn flush(&self) -> EyreResult<()> {
|
2021-11-22 11:28:30 -05:00
|
|
|
//trace!("Crypto::flush");
|
2023-02-07 21:44:50 -05:00
|
|
|
let cache_bytes = {
|
2021-11-22 11:28:30 -05:00
|
|
|
let inner = self.inner.lock();
|
2023-02-07 21:44:50 -05:00
|
|
|
cache_to_bytes(&inner.dh_cache)
|
2021-11-22 11:28:30 -05:00
|
|
|
};
|
|
|
|
|
2023-02-07 21:44:50 -05:00
|
|
|
let db = self
|
|
|
|
.unlocked_inner
|
|
|
|
.table_store
|
|
|
|
.open("crypto_caches", 1)
|
|
|
|
.await?;
|
2022-12-28 12:12:04 -05:00
|
|
|
db.store(0, b"dh_cache", &cache_bytes).await?;
|
2021-11-22 11:28:30 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn terminate(&self) {
|
|
|
|
trace!("Crypto::terminate");
|
|
|
|
let flush_future = self.inner.lock().flush_future.take();
|
|
|
|
if let Some(f) = flush_future {
|
|
|
|
f.await;
|
|
|
|
}
|
|
|
|
trace!("starting termination flush");
|
|
|
|
match self.flush().await {
|
|
|
|
Ok(_) => {
|
|
|
|
trace!("finished termination flush");
|
|
|
|
}
|
|
|
|
Err(e) => {
|
|
|
|
error!("failed termination flush: {}", e);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:50 -05:00
|
|
|
/// Factory method to get a specific crypto version
|
|
|
|
pub fn get(&self, kind: CryptoKind) -> Option<CryptoSystemVersion> {
|
2023-01-29 13:13:50 -05:00
|
|
|
let inner = self.inner.lock();
|
2023-02-07 21:44:50 -05:00
|
|
|
match kind {
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-vld0")]
|
2023-02-07 21:44:50 -05:00
|
|
|
CRYPTO_KIND_VLD0 => Some(inner.crypto_vld0.clone().unwrap()),
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-none")]
|
|
|
|
CRYPTO_KIND_NONE => Some(inner.crypto_none.clone().unwrap()),
|
2023-02-07 21:44:50 -05:00
|
|
|
_ => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-11 15:54:55 -05:00
|
|
|
// Factory method to get the best crypto version
|
|
|
|
pub fn best(&self) -> CryptoSystemVersion {
|
|
|
|
self.get(best_crypto_kind()).unwrap()
|
|
|
|
}
|
|
|
|
|
2023-02-07 21:44:50 -05:00
|
|
|
/// Signature set verification
|
|
|
|
/// Returns the set of signature cryptokinds that validate and are supported
|
|
|
|
/// If any cryptokinds are supported and do not validate, the whole operation
|
|
|
|
/// returns an error
|
2023-02-08 16:50:07 -05:00
|
|
|
pub fn verify_signatures(
|
2023-02-07 21:44:50 -05:00
|
|
|
&self,
|
2023-02-08 16:50:07 -05:00
|
|
|
node_ids: &[TypedKey],
|
2023-02-07 21:44:50 -05:00
|
|
|
data: &[u8],
|
2023-02-08 16:50:07 -05:00
|
|
|
typed_signatures: &[TypedSignature],
|
2023-05-29 19:24:57 +00:00
|
|
|
) -> VeilidAPIResult<TypedKeySet> {
|
2023-03-03 10:55:31 -05:00
|
|
|
let mut out = TypedKeySet::with_capacity(node_ids.len());
|
2023-02-08 16:50:07 -05:00
|
|
|
for sig in typed_signatures {
|
|
|
|
for nid in node_ids {
|
|
|
|
if nid.kind == sig.kind {
|
|
|
|
if let Some(vcrypto) = self.get(sig.kind) {
|
2023-03-01 15:50:30 -05:00
|
|
|
vcrypto.verify(&nid.value, data, &sig.value)?;
|
2023-03-03 10:55:31 -05:00
|
|
|
out.add(*nid);
|
2023-02-08 16:50:07 -05:00
|
|
|
}
|
|
|
|
}
|
2023-02-07 21:44:50 -05:00
|
|
|
}
|
|
|
|
}
|
2023-02-15 18:18:08 -05:00
|
|
|
Ok(out)
|
2023-02-07 21:44:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Signature set generation
|
|
|
|
/// Generates the set of signatures that are supported
|
|
|
|
/// Any cryptokinds that are not supported are silently dropped
|
|
|
|
pub fn generate_signatures<F, R>(
|
|
|
|
&self,
|
|
|
|
data: &[u8],
|
2023-02-08 16:50:07 -05:00
|
|
|
typed_key_pairs: &[TypedKeyPair],
|
2023-02-07 21:44:50 -05:00
|
|
|
transform: F,
|
2023-05-29 19:24:57 +00:00
|
|
|
) -> VeilidAPIResult<Vec<R>>
|
2023-02-07 21:44:50 -05:00
|
|
|
where
|
|
|
|
F: Fn(&TypedKeyPair, Signature) -> R,
|
|
|
|
{
|
2023-02-08 16:50:07 -05:00
|
|
|
let mut out = Vec::<R>::with_capacity(typed_key_pairs.len());
|
|
|
|
for kp in typed_key_pairs {
|
2023-02-07 21:44:50 -05:00
|
|
|
if let Some(vcrypto) = self.get(kp.kind) {
|
2023-03-01 15:50:30 -05:00
|
|
|
let sig = vcrypto.sign(&kp.value.key, &kp.value.secret, data)?;
|
2023-02-07 21:44:50 -05:00
|
|
|
out.push(transform(kp, sig))
|
|
|
|
}
|
2023-01-29 13:13:50 -05:00
|
|
|
}
|
2023-02-07 21:44:50 -05:00
|
|
|
Ok(out)
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
|
2023-03-03 10:55:31 -05:00
|
|
|
/// Generate keypair
|
|
|
|
/// Does not require startup/init
|
2023-05-29 19:24:57 +00:00
|
|
|
pub fn generate_keypair(crypto_kind: CryptoKind) -> VeilidAPIResult<TypedKeyPair> {
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-vld0")]
|
2023-03-03 10:55:31 -05:00
|
|
|
if crypto_kind == CRYPTO_KIND_VLD0 {
|
|
|
|
let kp = vld0_generate_keypair();
|
|
|
|
return Ok(TypedKeyPair::new(crypto_kind, kp));
|
|
|
|
}
|
2023-03-13 16:14:31 -04:00
|
|
|
#[cfg(feature = "enable-crypto-none")]
|
|
|
|
if crypto_kind == CRYPTO_KIND_NONE {
|
|
|
|
let kp = none_generate_keypair();
|
|
|
|
return Ok(TypedKeyPair::new(crypto_kind, kp));
|
|
|
|
}
|
2023-03-03 10:55:31 -05:00
|
|
|
Err(VeilidAPIError::generic("invalid crypto kind"))
|
|
|
|
}
|
|
|
|
|
2023-01-29 13:13:50 -05:00
|
|
|
// Internal utilities
|
|
|
|
|
|
|
|
fn cached_dh_internal<T: CryptoSystem>(
|
2022-07-10 17:36:50 -04:00
|
|
|
&self,
|
2023-01-29 13:13:50 -05:00
|
|
|
vcrypto: &T,
|
2023-02-07 21:44:50 -05:00
|
|
|
key: &PublicKey,
|
|
|
|
secret: &SecretKey,
|
2023-05-29 19:24:57 +00:00
|
|
|
) -> VeilidAPIResult<SharedSecret> {
|
2022-03-20 10:52:03 -04:00
|
|
|
Ok(
|
2023-02-23 21:07:46 -05:00
|
|
|
match self.inner.lock().dh_cache.entry(
|
|
|
|
DHCacheKey {
|
|
|
|
key: *key,
|
|
|
|
secret: *secret,
|
|
|
|
},
|
|
|
|
|_k, _v| {},
|
|
|
|
) {
|
2022-03-20 10:52:03 -04:00
|
|
|
Entry::Occupied(e) => e.get().shared_secret,
|
|
|
|
Entry::Vacant(e) => {
|
2023-01-29 13:13:50 -05:00
|
|
|
let shared_secret = vcrypto.compute_dh(key, secret)?;
|
2022-03-20 10:52:03 -04:00
|
|
|
e.insert(DHCacheValue { shared_secret });
|
|
|
|
shared_secret
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
2021-11-22 11:28:30 -05:00
|
|
|
}
|
|
|
|
}
|