try multiple cryptosystems
This commit is contained in:
		| @@ -10,7 +10,7 @@ license = "LGPL-2.0-or-later OR MPL-2.0 OR (MIT AND BSD-3-Clause)" | ||||
| crate-type = ["cdylib", "staticlib", "rlib"] | ||||
|  | ||||
| [features] | ||||
| default = [ "enable-crypto-vld0" ] | ||||
| default = [ "enable-crypto-none", "enable-crypto-vld0" ] | ||||
| enable-crypto-vld0 = [] | ||||
| enable-crypto-none = [] | ||||
| rt-async-std = ["async-std", "async-std-resolver", "async_executors/async_std", "rtnetlink?/smol_socket", "veilid-tools/rt-async-std"] | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| mod blake3digest512; | ||||
| mod byte_array_types; | ||||
| mod dh_cache; | ||||
| mod envelope; | ||||
| @@ -6,9 +7,13 @@ mod types; | ||||
| mod value; | ||||
|  | ||||
| pub mod crypto_system; | ||||
| #[cfg(feature = "enable-crypto-none")] | ||||
| pub mod none; | ||||
| pub mod tests; | ||||
| #[cfg(feature = "enable-crypto-vld0")] | ||||
| pub mod vld0; | ||||
|  | ||||
| pub use blake3digest512::*; | ||||
| pub use byte_array_types::*; | ||||
| pub use crypto_system::*; | ||||
| pub use dh_cache::*; | ||||
| @@ -16,6 +21,10 @@ pub use envelope::*; | ||||
| pub use receipt::*; | ||||
| pub use types::*; | ||||
| pub use value::*; | ||||
|  | ||||
| #[cfg(feature = "enable-crypto-none")] | ||||
| pub use none::*; | ||||
| #[cfg(feature = "enable-crypto-vld0")] | ||||
| pub use vld0::*; | ||||
|  | ||||
| use crate::*; | ||||
| @@ -24,11 +33,26 @@ use hashlink::linked_hash_map::Entry; | ||||
| use hashlink::LruCache; | ||||
| use serde::{Deserialize, Serialize}; | ||||
|  | ||||
| // Handle to a particular cryptosystem | ||||
| /// Handle to a particular cryptosystem | ||||
| pub type CryptoSystemVersion = Arc<dyn CryptoSystem + Send + Sync>; | ||||
|  | ||||
| /// 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]; | ||||
| 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"); | ||||
|     } | ||||
| } | ||||
| /// 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 | ||||
| @@ -36,7 +60,7 @@ pub fn best_crypto_kind() -> CryptoKind { | ||||
|     VALID_CRYPTO_KINDS[0] | ||||
| } | ||||
|  | ||||
| // Version number of envelope format | ||||
| /// Version number of envelope format | ||||
| pub type EnvelopeVersion = u8; | ||||
|  | ||||
| /// Envelope versions in order of preference, best envelope version is the first one, worst is the last one | ||||
| @@ -51,7 +75,10 @@ pub fn best_envelope_version() -> EnvelopeVersion { | ||||
| struct CryptoInner { | ||||
|     dh_cache: DHCache, | ||||
|     flush_future: Option<SendPinBoxFuture<()>>, | ||||
|     #[cfg(feature = "enable-crypto-vld0")] | ||||
|     crypto_vld0: Option<Arc<dyn CryptoSystem + Send + Sync>>, | ||||
|     #[cfg(feature = "enable-crypto-none")] | ||||
|     crypto_none: Option<Arc<dyn CryptoSystem + Send + Sync>>, | ||||
| } | ||||
|  | ||||
| struct CryptoUnlockedInner { | ||||
| @@ -72,7 +99,10 @@ impl Crypto { | ||||
|         CryptoInner { | ||||
|             dh_cache: DHCache::new(DH_CACHE_SIZE), | ||||
|             flush_future: None, | ||||
|             #[cfg(feature = "enable-crypto-vld0")] | ||||
|             crypto_vld0: None, | ||||
|             #[cfg(feature = "enable-crypto-none")] | ||||
|             crypto_none: None, | ||||
|         } | ||||
|     } | ||||
|  | ||||
| @@ -90,7 +120,15 @@ impl Crypto { | ||||
|             inner: Arc::new(Mutex::new(Self::new_inner())), | ||||
|         }; | ||||
|  | ||||
|         out.inner.lock().crypto_vld0 = Some(Arc::new(vld0::CryptoSystemVLD0::new(out.clone()))); | ||||
|         #[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()))); | ||||
|         } | ||||
|  | ||||
|         out | ||||
|     } | ||||
| @@ -203,7 +241,10 @@ impl Crypto { | ||||
|     pub fn get(&self, kind: CryptoKind) -> Option<CryptoSystemVersion> { | ||||
|         let inner = self.inner.lock(); | ||||
|         match kind { | ||||
|             #[cfg(feature = "enable-crypto-vld0")] | ||||
|             CRYPTO_KIND_VLD0 => Some(inner.crypto_vld0.clone().unwrap()), | ||||
|             #[cfg(feature = "enable-crypto-none")] | ||||
|             CRYPTO_KIND_NONE => Some(inner.crypto_none.clone().unwrap()), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| @@ -262,10 +303,16 @@ impl Crypto { | ||||
|     /// Generate keypair | ||||
|     /// Does not require startup/init | ||||
|     pub fn generate_keypair(crypto_kind: CryptoKind) -> Result<TypedKeyPair, VeilidAPIError> { | ||||
|         #[cfg(feature = "enable-crypto-vld0")] | ||||
|         if crypto_kind == CRYPTO_KIND_VLD0 { | ||||
|             let kp = vld0_generate_keypair(); | ||||
|             return Ok(TypedKeyPair::new(crypto_kind, kp)); | ||||
|         } | ||||
|         #[cfg(feature = "enable-crypto-none")] | ||||
|         if crypto_kind == CRYPTO_KIND_NONE { | ||||
|             let kp = none_generate_keypair(); | ||||
|             return Ok(TypedKeyPair::new(crypto_kind, kp)); | ||||
|         } | ||||
|         Err(VeilidAPIError::generic("invalid crypto kind")) | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -1,62 +1,68 @@ | ||||
| pub mod blake3digest512; | ||||
| pub use blake3digest512::*; | ||||
|  | ||||
| use super::*; | ||||
|  | ||||
| use chacha20::cipher::{KeyIvInit, StreamCipher}; | ||||
| use chacha20::XChaCha20; | ||||
| use chacha20poly1305 as ch; | ||||
| use chacha20poly1305::aead::{AeadInPlace, NewAead}; | ||||
| use core::convert::TryInto; | ||||
| use curve25519_dalek as cd; | ||||
| use digest::Digest; | ||||
| use ed25519_dalek as ed; | ||||
| use x25519_dalek as xd; | ||||
| use rand::RngCore; | ||||
|  | ||||
| const AEAD_OVERHEAD: usize = 16; | ||||
| pub const CRYPTO_KIND_VLD0: CryptoKind = FourCC([b'V', b'L', b'D', b'0']); | ||||
| const AEAD_OVERHEAD: usize = PUBLIC_KEY_LENGTH; | ||||
| pub const CRYPTO_KIND_NONE: CryptoKind = FourCC([b'N', b'O', b'N', b'E']); | ||||
|  | ||||
| fn ed25519_to_x25519_pk(key: &ed::PublicKey) -> Result<xd::PublicKey, VeilidAPIError> { | ||||
|     let bytes = key.to_bytes(); | ||||
|     let compressed = cd::edwards::CompressedEdwardsY(bytes); | ||||
|     let point = compressed | ||||
|         .decompress() | ||||
|         .ok_or_else(|| VeilidAPIError::internal("ed25519_to_x25519_pk failed"))?; | ||||
|     let mp = point.to_montgomery(); | ||||
|     Ok(xd::PublicKey::from(mp.to_bytes())) | ||||
| } | ||||
| fn ed25519_to_x25519_sk(key: &ed::SecretKey) -> Result<xd::StaticSecret, VeilidAPIError> { | ||||
|     let exp = ed::ExpandedSecretKey::from(key); | ||||
|     let bytes: [u8; ed::EXPANDED_SECRET_KEY_LENGTH] = exp.to_bytes(); | ||||
|     let lowbytes: [u8; 32] = bytes[0..32].try_into().map_err(VeilidAPIError::internal)?; | ||||
|     Ok(xd::StaticSecret::from(lowbytes)) | ||||
| } | ||||
|  | ||||
| pub fn vld0_generate_keypair() -> KeyPair { | ||||
| pub fn none_generate_keypair() -> KeyPair { | ||||
|     let mut csprng = VeilidRng {}; | ||||
|     let keypair = ed::Keypair::generate(&mut csprng); | ||||
|     let dht_key = PublicKey::new(keypair.public.to_bytes()); | ||||
|     let dht_key_secret = SecretKey::new(keypair.secret.to_bytes()); | ||||
|  | ||||
|     let mut pub_bytes = [0u8; PUBLIC_KEY_LENGTH]; | ||||
|     let mut sec_bytes = [0u8; SECRET_KEY_LENGTH]; | ||||
|     csprng.fill_bytes(&mut pub_bytes); | ||||
|     for n in 0..PUBLIC_KEY_LENGTH { | ||||
|         sec_bytes[n] = !pub_bytes[n]; | ||||
|     } | ||||
|     let dht_key = PublicKey::new(pub_bytes); | ||||
|     let dht_key_secret = SecretKey::new(sec_bytes); | ||||
|     KeyPair::new(dht_key, dht_key_secret) | ||||
| } | ||||
|  | ||||
| /// V0 CryptoSystem | ||||
| fn do_xor_32(a: &[u8], b: &[u8]) -> [u8; 32] { | ||||
|     let mut out = [0u8; 32]; | ||||
|     for n in 0..32 { | ||||
|         out[n] = a[n] ^ b[n]; | ||||
|     } | ||||
|     out | ||||
| } | ||||
|  | ||||
| fn do_xor_inplace(a: &mut [u8], key: &[u8]) { | ||||
|     for n in 0..a.len() { | ||||
|         a[n] ^= key[n % key.len()]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn do_xor_b2b(a: &[u8], b: &mut [u8], key: &[u8]) { | ||||
|     for n in 0..a.len() { | ||||
|         b[n] = a[n] ^ key[n % key.len()]; | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn is_bytes_eq_32(a: &[u8], v: u8) -> bool { | ||||
|     for n in 0..32 { | ||||
|         if a[n] != v { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
|     true | ||||
| } | ||||
|  | ||||
| /// None CryptoSystem | ||||
| #[derive(Clone)] | ||||
| pub struct CryptoSystemVLD0 { | ||||
| pub struct CryptoSystemNONE { | ||||
|     crypto: Crypto, | ||||
| } | ||||
|  | ||||
| impl CryptoSystemVLD0 { | ||||
| impl CryptoSystemNONE { | ||||
|     pub fn new(crypto: Crypto) -> Self { | ||||
|         Self { crypto } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl CryptoSystem for CryptoSystemVLD0 { | ||||
| impl CryptoSystem for CryptoSystemNONE { | ||||
|     // Accessors | ||||
|     fn kind(&self) -> CryptoKind { | ||||
|         CRYPTO_KIND_VLD0 | ||||
|         CRYPTO_KIND_NONE | ||||
|     } | ||||
|  | ||||
|     fn crypto(&self) -> Crypto { | ||||
| @@ -70,17 +76,17 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         secret: &SecretKey, | ||||
|     ) -> Result<SharedSecret, VeilidAPIError> { | ||||
|         self.crypto | ||||
|             .cached_dh_internal::<CryptoSystemVLD0>(self, key, secret) | ||||
|             .cached_dh_internal::<CryptoSystemNONE>(self, key, secret) | ||||
|     } | ||||
|  | ||||
|     // Generation | ||||
|     fn random_nonce(&self) -> Nonce { | ||||
|         let mut nonce = [0u8; 24]; | ||||
|         let mut nonce = [0u8; NONCE_LENGTH]; | ||||
|         random_bytes(&mut nonce).unwrap(); | ||||
|         Nonce::new(nonce) | ||||
|     } | ||||
|     fn random_shared_secret(&self) -> SharedSecret { | ||||
|         let mut s = [0u8; 32]; | ||||
|         let mut s = [0u8; SHARED_SECRET_LENGTH]; | ||||
|         random_bytes(&mut s).unwrap(); | ||||
|         SharedSecret::new(s) | ||||
|     } | ||||
| @@ -89,14 +95,11 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         key: &PublicKey, | ||||
|         secret: &SecretKey, | ||||
|     ) -> Result<SharedSecret, VeilidAPIError> { | ||||
|         let pk_ed = ed::PublicKey::from_bytes(&key.bytes).map_err(VeilidAPIError::internal)?; | ||||
|         let pk_xd = ed25519_to_x25519_pk(&pk_ed)?; | ||||
|         let sk_ed = ed::SecretKey::from_bytes(&secret.bytes).map_err(VeilidAPIError::internal)?; | ||||
|         let sk_xd = ed25519_to_x25519_sk(&sk_ed)?; | ||||
|         Ok(SharedSecret::new(sk_xd.diffie_hellman(&pk_xd).to_bytes())) | ||||
|         let s = do_xor_32(&key.bytes, &secret.bytes); | ||||
|         Ok(SharedSecret::new(s)) | ||||
|     } | ||||
|     fn generate_keypair(&self) -> KeyPair { | ||||
|         vld0_generate_keypair() | ||||
|         none_generate_keypair() | ||||
|     } | ||||
|     fn generate_hash(&self, data: &[u8]) -> PublicKey { | ||||
|         PublicKey::new(*blake3::hash(data).as_bytes()) | ||||
| @@ -123,7 +126,6 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|     } | ||||
|     fn validate_hash(&self, data: &[u8], dht_key: &PublicKey) -> bool { | ||||
|         let bytes = *blake3::hash(data).as_bytes(); | ||||
|  | ||||
|         bytes == dht_key.bytes | ||||
|     } | ||||
|     fn validate_hash_reader( | ||||
| @@ -154,22 +156,21 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         dht_key_secret: &SecretKey, | ||||
|         data: &[u8], | ||||
|     ) -> Result<Signature, VeilidAPIError> { | ||||
|         let mut kpb: [u8; SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH] = | ||||
|             [0u8; SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH]; | ||||
|  | ||||
|         kpb[..SECRET_KEY_LENGTH].copy_from_slice(&dht_key_secret.bytes); | ||||
|         kpb[SECRET_KEY_LENGTH..].copy_from_slice(&dht_key.bytes); | ||||
|         let keypair = ed::Keypair::from_bytes(&kpb) | ||||
|             .map_err(|e| VeilidAPIError::parse_error("Keypair is invalid", e))?; | ||||
|         if !is_bytes_eq_32(&do_xor_32(&dht_key.bytes, &dht_key_secret.bytes), 0xFFu8) { | ||||
|             return Err(VeilidAPIError::parse_error( | ||||
|                 "Keypair is invalid", | ||||
|                 "invalid keys", | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         let mut dig = Blake3Digest512::new(); | ||||
|         dig.update(data); | ||||
|  | ||||
|         let sig = keypair | ||||
|             .sign_prehashed(dig, None) | ||||
|             .map_err(VeilidAPIError::internal)?; | ||||
|  | ||||
|         let dht_sig = Signature::new(sig.to_bytes()); | ||||
|         let sig = dig.finalize(); | ||||
|         let in_sig_bytes: [u8; SIGNATURE_LENGTH] = sig.into(); | ||||
|         let mut sig_bytes = [0u8; SIGNATURE_LENGTH]; | ||||
|         sig_bytes[0..32].copy_from_slice(&in_sig_bytes[0..32]); | ||||
|         sig_bytes[32..64].copy_from_slice(&do_xor_32(&in_sig_bytes[32..64], &dht_key_secret.bytes)); | ||||
|         let dht_sig = Signature::new(sig_bytes.into()); | ||||
|         Ok(dht_sig) | ||||
|     } | ||||
|     fn verify( | ||||
| @@ -178,16 +179,29 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         data: &[u8], | ||||
|         signature: &Signature, | ||||
|     ) -> Result<(), VeilidAPIError> { | ||||
|         let pk = ed::PublicKey::from_bytes(&dht_key.bytes) | ||||
|             .map_err(|e| VeilidAPIError::parse_error("Public key is invalid", e))?; | ||||
|         let sig = ed::Signature::from_bytes(&signature.bytes) | ||||
|             .map_err(|e| VeilidAPIError::parse_error("Signature is invalid", e))?; | ||||
|  | ||||
|         let mut dig = Blake3Digest512::new(); | ||||
|         dig.update(data); | ||||
|         let sig = dig.finalize(); | ||||
|         let in_sig_bytes: [u8; SIGNATURE_LENGTH] = sig.into(); | ||||
|         let mut verify_bytes = [0u8; SIGNATURE_LENGTH]; | ||||
|         verify_bytes[0..32] | ||||
|             .copy_from_slice(&do_xor_32(&in_sig_bytes[0..32], &signature.bytes[0..32])); | ||||
|         verify_bytes[32..64] | ||||
|             .copy_from_slice(&do_xor_32(&in_sig_bytes[32..64], &signature.bytes[32..64])); | ||||
|  | ||||
|         if !is_bytes_eq_32(&verify_bytes[0..32], 0u8) { | ||||
|             return Err(VeilidAPIError::parse_error( | ||||
|                 "Verification failed", | ||||
|                 "signature 0..32 is invalid", | ||||
|             )); | ||||
|         } | ||||
|         if !is_bytes_eq_32(&do_xor_32(&verify_bytes[32..64], &dht_key.bytes), 0xFFu8) { | ||||
|             return Err(VeilidAPIError::parse_error( | ||||
|                 "Verification failed", | ||||
|                 "signature 32..64 is invalid", | ||||
|             )); | ||||
|         } | ||||
|  | ||||
|         pk.verify_prehashed(dig, None, &sig) | ||||
|             .map_err(|e| VeilidAPIError::parse_error("Verification failed", e))?; | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
| @@ -200,14 +214,21 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         body: &mut Vec<u8>, | ||||
|         nonce: &Nonce, | ||||
|         shared_secret: &SharedSecret, | ||||
|         associated_data: Option<&[u8]>, | ||||
|         _associated_data: Option<&[u8]>, | ||||
|     ) -> Result<(), VeilidAPIError> { | ||||
|         let key = ch::Key::from(shared_secret.bytes); | ||||
|         let xnonce = ch::XNonce::from(nonce.bytes); | ||||
|         let aead = ch::XChaCha20Poly1305::new(&key); | ||||
|         aead.decrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body) | ||||
|             .map_err(map_to_string) | ||||
|             .map_err(VeilidAPIError::generic) | ||||
|         let mut blob = nonce.bytes.to_vec(); | ||||
|         blob.extend_from_slice(&[0u8; 8]); | ||||
|         let blob = do_xor_32(&blob, &shared_secret.bytes); | ||||
|  | ||||
|         if body.len() < AEAD_OVERHEAD { | ||||
|             return Err(VeilidAPIError::generic("invalid length")); | ||||
|         } | ||||
|         if &body[body.len() - AEAD_OVERHEAD..] != &blob { | ||||
|             return Err(VeilidAPIError::generic("invalid keyblob")); | ||||
|         } | ||||
|         body.truncate(body.len() - AEAD_OVERHEAD); | ||||
|         do_xor_inplace(body, &blob); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn decrypt_aead( | ||||
| @@ -229,15 +250,14 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         body: &mut Vec<u8>, | ||||
|         nonce: &Nonce, | ||||
|         shared_secret: &SharedSecret, | ||||
|         associated_data: Option<&[u8]>, | ||||
|         _associated_data: Option<&[u8]>, | ||||
|     ) -> Result<(), VeilidAPIError> { | ||||
|         let key = ch::Key::from(shared_secret.bytes); | ||||
|         let xnonce = ch::XNonce::from(nonce.bytes); | ||||
|         let aead = ch::XChaCha20Poly1305::new(&key); | ||||
|  | ||||
|         aead.encrypt_in_place(&xnonce, associated_data.unwrap_or(b""), body) | ||||
|             .map_err(map_to_string) | ||||
|             .map_err(VeilidAPIError::generic) | ||||
|         let mut blob = nonce.bytes.to_vec(); | ||||
|         blob.extend_from_slice(&[0u8; 8]); | ||||
|         let blob = do_xor_32(&blob, &shared_secret.bytes); | ||||
|         do_xor_inplace(body, &blob); | ||||
|         body.append(&mut blob.to_vec()); | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn encrypt_aead( | ||||
| @@ -261,8 +281,10 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         nonce: &Nonce, | ||||
|         shared_secret: &SharedSecret, | ||||
|     ) { | ||||
|         let mut cipher = XChaCha20::new(&shared_secret.bytes.into(), &nonce.bytes.into()); | ||||
|         cipher.apply_keystream(body); | ||||
|         let mut blob = nonce.bytes.to_vec(); | ||||
|         blob.extend_from_slice(&[0u8; 8]); | ||||
|         let blob = do_xor_32(&blob, &shared_secret.bytes); | ||||
|         do_xor_inplace(body, &blob); | ||||
|     } | ||||
|  | ||||
|     fn crypt_b2b_no_auth( | ||||
| @@ -272,8 +294,10 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         nonce: &Nonce, | ||||
|         shared_secret: &SharedSecret, | ||||
|     ) { | ||||
|         let mut cipher = XChaCha20::new(&shared_secret.bytes.into(), &nonce.bytes.into()); | ||||
|         cipher.apply_keystream_b2b(in_buf, out_buf).unwrap(); | ||||
|         let mut blob = nonce.bytes.to_vec(); | ||||
|         blob.extend_from_slice(&[0u8; 8]); | ||||
|         let blob = do_xor_32(&blob, &shared_secret.bytes); | ||||
|         do_xor_b2b(in_buf, out_buf, &blob); | ||||
|     } | ||||
|  | ||||
|     fn crypt_no_auth_aligned_8( | ||||
|   | ||||
| @@ -55,20 +55,14 @@ pub async fn test_sign_and_verify(vcrypto: CryptoSystemVersion) { | ||||
|     let a2 = vcrypto | ||||
|         .sign(&dht_key2, &dht_key_secret2, LOREM_IPSUM.as_bytes()) | ||||
|         .unwrap(); | ||||
|     let b1 = vcrypto | ||||
|     let _b1 = vcrypto | ||||
|         .sign(&dht_key, &dht_key_secret2, LOREM_IPSUM.as_bytes()) | ||||
|         .unwrap(); | ||||
|     let b2 = vcrypto | ||||
|         .unwrap_err(); | ||||
|     let _b2 = vcrypto | ||||
|         .sign(&dht_key2, &dht_key_secret, LOREM_IPSUM.as_bytes()) | ||||
|         .unwrap(); | ||||
|     assert_ne!(a1, b1); | ||||
|     assert_ne!(a2, b2); | ||||
|     assert_ne!(a1, b2); | ||||
|     assert_ne!(a2, b1); | ||||
|         .unwrap_err(); | ||||
|  | ||||
|     assert_ne!(a1, a2); | ||||
|     assert_ne!(b1, b2); | ||||
|     assert_ne!(a1, b2); | ||||
|     assert_ne!(b1, a2); | ||||
|  | ||||
|     assert_eq!( | ||||
|         vcrypto.verify(&dht_key, LOREM_IPSUM.as_bytes(), &a1), | ||||
| @@ -79,10 +73,10 @@ pub async fn test_sign_and_verify(vcrypto: CryptoSystemVersion) { | ||||
|         Ok(()) | ||||
|     ); | ||||
|     assert!(vcrypto | ||||
|         .verify(&dht_key, LOREM_IPSUM.as_bytes(), &b1) | ||||
|         .verify(&dht_key, LOREM_IPSUM.as_bytes(), &a2) | ||||
|         .is_err()); | ||||
|     assert!(vcrypto | ||||
|         .verify(&dht_key2, LOREM_IPSUM.as_bytes(), &b2) | ||||
|         .verify(&dht_key2, LOREM_IPSUM.as_bytes(), &a1) | ||||
|         .is_err()); | ||||
|  | ||||
|     // Try verifications that should work | ||||
|   | ||||
| @@ -1,70 +0,0 @@ | ||||
| use digest::generic_array::typenum::U64; | ||||
| use digest::{Digest, Output}; | ||||
| use generic_array::GenericArray; | ||||
|  | ||||
| pub struct Blake3Digest512 { | ||||
|     dig: blake3::Hasher, | ||||
| } | ||||
|  | ||||
| impl Digest for Blake3Digest512 { | ||||
|     type OutputSize = U64; | ||||
|  | ||||
|     fn new() -> Self { | ||||
|         Self { | ||||
|             dig: blake3::Hasher::new(), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn update(&mut self, data: impl AsRef<[u8]>) { | ||||
|         self.dig.update(data.as_ref()); | ||||
|     } | ||||
|  | ||||
|     fn chain(mut self, data: impl AsRef<[u8]>) -> Self | ||||
|     where | ||||
|         Self: Sized, | ||||
|     { | ||||
|         self.update(data); | ||||
|         self | ||||
|     } | ||||
|  | ||||
|     fn finalize(self) -> Output<Self> { | ||||
|         let mut b = [0u8; 64]; | ||||
|         self.dig.finalize_xof().fill(&mut b); | ||||
|         let mut out = GenericArray::<u8, U64>::default(); | ||||
|         for n in 0..64 { | ||||
|             out[n] = b[n]; | ||||
|         } | ||||
|         out | ||||
|     } | ||||
|  | ||||
|     fn finalize_reset(&mut self) -> Output<Self> { | ||||
|         let mut b = [0u8; 64]; | ||||
|         self.dig.finalize_xof().fill(&mut b); | ||||
|         let mut out = GenericArray::<u8, U64>::default(); | ||||
|         for n in 0..64 { | ||||
|             out[n] = b[n]; | ||||
|         } | ||||
|         self.reset(); | ||||
|         out | ||||
|     } | ||||
|  | ||||
|     fn reset(&mut self) { | ||||
|         self.dig.reset(); | ||||
|     } | ||||
|  | ||||
|     fn output_size() -> usize { | ||||
|         64 | ||||
|     } | ||||
|  | ||||
|     fn digest(data: &[u8]) -> Output<Self> { | ||||
|         let mut dig = blake3::Hasher::new(); | ||||
|         dig.update(data); | ||||
|         let mut b = [0u8; 64]; | ||||
|         dig.finalize_xof().fill(&mut b); | ||||
|         let mut out = GenericArray::<u8, U64>::default(); | ||||
|         for n in 0..64 { | ||||
|             out[n] = b[n]; | ||||
|         } | ||||
|         out | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,3 @@ | ||||
| pub mod blake3digest512; | ||||
| pub use blake3digest512::*; | ||||
|  | ||||
| use super::*; | ||||
|  | ||||
| use chacha20::cipher::{KeyIvInit, StreamCipher}; | ||||
| @@ -75,12 +72,12 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|  | ||||
|     // Generation | ||||
|     fn random_nonce(&self) -> Nonce { | ||||
|         let mut nonce = [0u8; 24]; | ||||
|         let mut nonce = [0u8; NONCE_LENGTH]; | ||||
|         random_bytes(&mut nonce).unwrap(); | ||||
|         Nonce::new(nonce) | ||||
|     } | ||||
|     fn random_shared_secret(&self) -> SharedSecret { | ||||
|         let mut s = [0u8; 32]; | ||||
|         let mut s = [0u8; SHARED_SECRET_LENGTH]; | ||||
|         random_bytes(&mut s).unwrap(); | ||||
|         SharedSecret::new(s) | ||||
|     } | ||||
| @@ -165,12 +162,15 @@ impl CryptoSystem for CryptoSystemVLD0 { | ||||
|         let mut dig = Blake3Digest512::new(); | ||||
|         dig.update(data); | ||||
|  | ||||
|         let sig = keypair | ||||
|         let sig_bytes = keypair | ||||
|             .sign_prehashed(dig, None) | ||||
|             .map_err(VeilidAPIError::internal)?; | ||||
|  | ||||
|         let dht_sig = Signature::new(sig.to_bytes()); | ||||
|         Ok(dht_sig) | ||||
|         let sig = Signature::new(sig_bytes.to_bytes()); | ||||
|  | ||||
|         self.verify(dht_key, &data, &sig)?; | ||||
|  | ||||
|         Ok(sig) | ||||
|     } | ||||
|     fn verify( | ||||
|         &self, | ||||
|   | ||||
| @@ -35,7 +35,6 @@ mod veilid_layer_filter; | ||||
|  | ||||
| pub use self::api_tracing_layer::ApiTracingLayer; | ||||
| pub use self::core_context::{api_startup, api_startup_json, UpdateCallback}; | ||||
| pub use self::crypto::vld0_generate_keypair; | ||||
| pub use self::veilid_api::*; | ||||
| pub use self::veilid_config::*; | ||||
| pub use self::veilid_layer_filter::*; | ||||
|   | ||||
| @@ -919,8 +919,99 @@ impl VeilidConfig { | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     // Get the node id from config if one is specified | ||||
|     // Must be done -after- protected store startup | ||||
|     #[cfg(not(test))] | ||||
|     async fn init_node_id( | ||||
|         &self, | ||||
|         vcrypto: CryptoSystemVersion, | ||||
|         protected_store: intf::ProtectedStore, | ||||
|     ) -> Result<(TypedKey, TypedSecret), VeilidAPIError> { | ||||
|         let ck = vcrypto.kind(); | ||||
|         let mut node_id = self.inner.read().network.routing_table.node_id.get(ck); | ||||
|         let mut node_id_secret = self | ||||
|             .inner | ||||
|             .read() | ||||
|             .network | ||||
|             .routing_table | ||||
|             .node_id_secret | ||||
|             .get(ck); | ||||
|  | ||||
|         // See if node id was previously stored in the protected store | ||||
|         if node_id.is_none() { | ||||
|             debug!("pulling node_id_{} from storage", ck); | ||||
|             if let Some(s) = protected_store | ||||
|                 .load_user_secret_string(format!("node_id_{}", ck)) | ||||
|                 .await | ||||
|                 .map_err(VeilidAPIError::internal)? | ||||
|             { | ||||
|                 debug!("node_id_{} found in storage", ck); | ||||
|                 node_id = match TypedKey::from_str(s.as_str()) { | ||||
|                     Ok(v) => Some(v), | ||||
|                     Err(_) => { | ||||
|                         debug!("node id in protected store is not valid"); | ||||
|                         None | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 debug!("node_id_{} not found in storage", ck); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // See if node id secret was previously stored in the protected store | ||||
|         if node_id_secret.is_none() { | ||||
|             debug!("pulling node id secret from storage"); | ||||
|             if let Some(s) = protected_store | ||||
|                 .load_user_secret_string(format!("node_id_secret_{}", ck)) | ||||
|                 .await | ||||
|                 .map_err(VeilidAPIError::internal)? | ||||
|             { | ||||
|                 debug!("node_id_secret_{} found in storage", ck); | ||||
|                 node_id_secret = match TypedSecret::from_str(s.as_str()) { | ||||
|                     Ok(v) => Some(v), | ||||
|                     Err(_) => { | ||||
|                         debug!("node id secret in protected store is not valid"); | ||||
|                         None | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 debug!("node_id_secret_{} not found in storage", ck); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         // If we have a node id from storage, check it | ||||
|         let (node_id, node_id_secret) = | ||||
|             if let (Some(node_id), Some(node_id_secret)) = (node_id, node_id_secret) { | ||||
|                 // Validate node id | ||||
|                 if !vcrypto.validate_keypair(&node_id.value, &node_id_secret.value) { | ||||
|                     apibail_generic!(format!( | ||||
|                         "node_id_secret_{} and node_id_key_{} don't match", | ||||
|                         ck, ck | ||||
|                     )); | ||||
|                 } | ||||
|                 (node_id, node_id_secret) | ||||
|             } else { | ||||
|                 // If we still don't have a valid node id, generate one | ||||
|                 debug!("generating new node_id_{}", ck); | ||||
|                 let kp = vcrypto.generate_keypair(); | ||||
|                 (TypedKey::new(ck, kp.key), TypedSecret::new(ck, kp.secret)) | ||||
|             }; | ||||
|         info!("Node Id: {}", node_id); | ||||
|  | ||||
|         // Save the node id / secret in storage | ||||
|         protected_store | ||||
|             .save_user_secret_string(format!("node_id_{}", ck), node_id.to_string()) | ||||
|             .await | ||||
|             .map_err(VeilidAPIError::internal)?; | ||||
|         protected_store | ||||
|             .save_user_secret_string(format!("node_id_secret_{}", ck), node_id_secret.to_string()) | ||||
|             .await | ||||
|             .map_err(VeilidAPIError::internal)?; | ||||
|  | ||||
|         Ok((node_id, node_id_secret)) | ||||
|     } | ||||
|  | ||||
|     /// Get the node id from config if one is specified | ||||
|     /// Must be done -after- protected store startup | ||||
|     #[cfg_attr(test, allow(unused_variables))] | ||||
|     pub async fn init_node_ids( | ||||
|         &self, | ||||
|         crypto: Crypto, | ||||
| @@ -934,88 +1025,14 @@ impl VeilidConfig { | ||||
|                 .get(ck) | ||||
|                 .expect("Valid crypto kind is not actually valid."); | ||||
|  | ||||
|             let mut node_id = self.inner.read().network.routing_table.node_id.get(ck); | ||||
|             let mut node_id_secret = self | ||||
|                 .inner | ||||
|                 .read() | ||||
|                 .network | ||||
|                 .routing_table | ||||
|                 .node_id_secret | ||||
|                 .get(ck); | ||||
|  | ||||
|             // See if node id was previously stored in the protected store | ||||
|             if node_id.is_none() { | ||||
|                 debug!("pulling node_id_{} from storage", ck); | ||||
|                 if let Some(s) = protected_store | ||||
|                     .load_user_secret_string(format!("node_id_{}", ck)) | ||||
|                     .await | ||||
|                     .map_err(VeilidAPIError::internal)? | ||||
|                 { | ||||
|                     debug!("node_id_{} found in storage", ck); | ||||
|                     node_id = match TypedKey::from_str(s.as_str()) { | ||||
|                         Ok(v) => Some(v), | ||||
|                         Err(_) => { | ||||
|                             debug!("node id in protected store is not valid"); | ||||
|                             None | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     debug!("node_id_{} not found in storage", ck); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // See if node id secret was previously stored in the protected store | ||||
|             if node_id_secret.is_none() { | ||||
|                 debug!("pulling node id secret from storage"); | ||||
|                 if let Some(s) = protected_store | ||||
|                     .load_user_secret_string(format!("node_id_secret_{}", ck)) | ||||
|                     .await | ||||
|                     .map_err(VeilidAPIError::internal)? | ||||
|                 { | ||||
|                     debug!("node_id_secret_{} found in storage", ck); | ||||
|                     node_id_secret = match TypedSecret::from_str(s.as_str()) { | ||||
|                         Ok(v) => Some(v), | ||||
|                         Err(_) => { | ||||
|                             debug!("node id secret in protected store is not valid"); | ||||
|                             None | ||||
|                         } | ||||
|                     } | ||||
|                 } else { | ||||
|                     debug!("node_id_secret_{} not found in storage", ck); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             // If we have a node id from storage, check it | ||||
|             #[cfg(test)] | ||||
|             let (node_id, node_id_secret) = { | ||||
|                 let kp = vcrypto.generate_keypair(); | ||||
|                 (TypedKey::new(ck, kp.key), TypedSecret::new(ck, kp.secret)) | ||||
|             }; | ||||
|             #[cfg(not(test))] | ||||
|             let (node_id, node_id_secret) = | ||||
|                 if let (Some(node_id), Some(node_id_secret)) = (node_id, node_id_secret) { | ||||
|                     // Validate node id | ||||
|                     if !vcrypto.validate_keypair(&node_id.value, &node_id_secret.value) { | ||||
|                         apibail_generic!(format!( | ||||
|                             "node_id_secret_{} and node_id_key_{} don't match", | ||||
|                             ck, ck | ||||
|                         )); | ||||
|                     } | ||||
|                     (node_id, node_id_secret) | ||||
|                 } else { | ||||
|                     // If we still don't have a valid node id, generate one | ||||
|                     debug!("generating new node_id_{}", ck); | ||||
|                     let kp = vcrypto.generate_keypair(); | ||||
|                     (TypedKey::new(ck, kp.key), TypedSecret::new(ck, kp.secret)) | ||||
|                 }; | ||||
|             info!("Node Id: {}", node_id); | ||||
|  | ||||
|             // Save the node id / secret in storage | ||||
|             protected_store | ||||
|                 .save_user_secret_string(format!("node_id_{}", ck), node_id.to_string()) | ||||
|                 .await | ||||
|                 .map_err(VeilidAPIError::internal)?; | ||||
|             protected_store | ||||
|                 .save_user_secret_string( | ||||
|                     format!("node_id_secret_{}", ck), | ||||
|                     node_id_secret.to_string(), | ||||
|                 ) | ||||
|                 .await | ||||
|                 .map_err(VeilidAPIError::internal)?; | ||||
|                 self.init_node_id(vcrypto, protected_store.clone()).await?; | ||||
|  | ||||
|             // Save for config | ||||
|             out_node_id.add(node_id); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user