diff --git a/Cargo.toml b/Cargo.toml index 0d29db4..32166be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ ascii-armor = "0.7.1" baid64 = "0.2.2" base64 = "0.22.1" secp256k1 = { version = "0.29.0", features = ["rand", "global-context", "rand-std"] } -ec25519 = "0.1.0" +ec25519 = { version = "0.1.0", features = ["blind-keys"] } rand = "0.8.5" chrono = "0.4.38" clap = { version = "4.5.4", features = ["derive"], optional = true } diff --git a/src/encrypt.rs b/src/encrypt.rs index 1de7dec..68b3e13 100644 --- a/src/encrypt.rs +++ b/src/encrypt.rs @@ -24,9 +24,9 @@ use std::str::FromStr; use aes_gcm::aead::{Aead, Nonce, OsRng}; use aes_gcm::{AeadCore, Aes256Gcm, KeyInit}; use amplify::confinement::{Confined, SmallOrdMap, U64 as U64MAX}; -use amplify::{Bytes32, Wrapper}; +use amplify::Bytes32; use armor::{ArmorHeader, ArmorParseError, AsciiArmor}; -use ec25519::edwards25519; +use ec25519::{edwards25519, KeyPair, Seed}; use rand::random; use sha2::{Digest, Sha256}; use strict_encoding::{StrictDeserialize, StrictSerialize}; @@ -67,8 +67,12 @@ impl AsRef<[u8]> for SymmetricKey { impl SymmetricKey { pub fn new() -> Self { - let key = random::<[u8; 32]>(); - Self(Bytes32::from_byte_array(key)) + loop { + let key = random::<[u8; 32]>(); + if edwards25519::GeP3::from_bytes_vartime(&key).is_some() { + return Self(Bytes32::from_byte_array(key)); + } + } } } @@ -77,7 +81,7 @@ impl SymmetricKey { #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_SSI)] pub struct Encrypted { - pub keys: SmallOrdMap, + pub keys: SmallOrdMap, pub nonce: [u8; 12], pub data: Confined, 0, U64MAX>, } @@ -120,11 +124,10 @@ impl Encrypted { let key = SymmetricKey::new(); let mut keys = bmap![]; for pk in receivers { - keys.insert( - pk, - pk.encrypt_key(&key) - .map_err(|_| EncryptionError::InvalidPubkey(pk))?, - ); + let (msg, c1) = pk + .encrypt_key(&key) + .map_err(|_| EncryptionError::InvalidPubkey(pk))?; + keys.insert(pk, (msg, Bytes32::from_slice_unsafe(c1.as_slice()))); } let (nonce, msg) = encrypt(source, key); Ok(Self { @@ -134,53 +137,76 @@ impl Encrypted { }) } - pub fn decrypt(&self, pair: SsiPair) -> Result, DecryptionError> { - let key = self + pub fn decrypt(&self, pair: impl Into) -> Result, DecryptionError> { + let pair = pair.into(); + let (msg, c1) = self .keys .iter() .find(|(pk, _)| *pk == &pair.pk) .map(|(_, secret)| secret) - .ok_or(DecryptionError::KeyMismatch(pair.pk))? - .copy(); + .ok_or(DecryptionError::KeyMismatch(pair.pk))?; + let c1 = ec25519::PublicKey::new(c1.to_byte_array()); let key = pair - .decrypt_key(key) + .decrypt_key(*msg, c1) .map_err(|_| DecryptionError::InvalidPubkey(pair.pk))?; Ok(decrypt(self.data.as_slice(), self.nonce.into(), key)?) } } impl SsiPub { - pub fn encrypt_key(&self, key: &SymmetricKey) -> Result { + pub fn encrypt_key( + &self, + key: &SymmetricKey, + ) -> Result<(Bytes32, ec25519::PublicKey), InvalidPubkey> { match self.algo() { Algo::Ed25519 => self.encrypt_key_ed25519(key), Algo::Bip340 | Algo::Other(_) => Err(InvalidPubkey), } } - pub fn encrypt_key_ed25519(&self, key: &SymmetricKey) -> Result { - let ge = + pub fn encrypt_key_ed25519( + &self, + message: &SymmetricKey, + ) -> Result<(Bytes32, ec25519::PublicKey), InvalidPubkey> { + let pair = KeyPair::from_seed(Seed::generate()); + let y = pair.sk; + let c1 = pair.pk; + + let h = edwards25519::GeP3::from_bytes_vartime(&self.to_byte_array()).ok_or(InvalidPubkey)?; + let s = edwards25519::ge_scalarmult(&y.seed().scalar(), &h); + + let m = edwards25519::GeP3::from_bytes_vartime(&message.0.to_byte_array()) + .ok_or(InvalidPubkey)?; + let c2 = m + s; - Ok(edwards25519::ge_scalarmult(key.as_ref(), &ge) - .to_bytes() - .into()) + Ok((c2.to_bytes().into(), c1)) } } impl SsiPair { - pub fn decrypt_key(&self, key: Bytes32) -> Result { + pub fn decrypt_key( + &self, + encrypted_message: Bytes32, + c1: ec25519::PublicKey, + ) -> Result { match self.pk.algo() { - Algo::Ed25519 => self.decrypt_key_ed25519(key), + Algo::Ed25519 => self.decrypt_key_ed25519(encrypted_message, c1), Algo::Bip340 | Algo::Other(_) => Err(InvalidPubkey), } } - pub fn decrypt_key_ed25519(&self, key: Bytes32) -> Result { - let ge = edwards25519::GeP3::from_bytes_negate_vartime(&self.pk.to_byte_array()) + pub fn decrypt_key_ed25519( + &self, + encrypted_message: Bytes32, + c1: ec25519::PublicKey, + ) -> Result { + let c1 = edwards25519::GeP3::from_bytes_vartime(&c1).ok_or(InvalidPubkey)?; + let s = edwards25519::ge_scalarmult(&self.sk.secret_bytes(), &c1); + let c2 = edwards25519::GeP3::from_bytes_vartime(&encrypted_message.to_byte_array()) .ok_or(InvalidPubkey)?; - Ok(edwards25519::ge_scalarmult(key.as_ref(), &ge) - .to_bytes() - .into()) + let key = c2 - s; + Ok(SymmetricKey::from(key.to_bytes())) } } @@ -228,8 +254,8 @@ mod test { let sk = SsiSecret::new(Algo::Ed25519, Chain::Bitcoin); let pair = SsiPair::from(sk); let key = SymmetricKey::new(); - let encrypted = pair.pk.encrypt_key(&key).unwrap(); - let decrypted = pair.decrypt_key(encrypted).unwrap(); + let (encrypted, c1) = pair.pk.encrypt_key(&key).unwrap(); + let decrypted = pair.decrypt_key(encrypted, c1).unwrap(); assert_eq!(key.0, decrypted.0); } diff --git a/src/secret.rs b/src/secret.rs index 9066b35..3a16fcd 100644 --- a/src/secret.rs +++ b/src/secret.rs @@ -215,7 +215,7 @@ impl SsiSecret { } pub fn conceal(&self, passwd: impl AsRef) -> EncryptedSecret { - let (nonce, key) = encrypt(self.as_secret_bytes().to_vec(), passwd.as_ref()); + let (nonce, key) = encrypt(self.secret_bytes().to_vec(), passwd.as_ref()); EncryptedSecret { fp: self.to_public().fingerprint(), nonce, @@ -224,10 +224,10 @@ impl SsiSecret { } } - pub fn as_secret_bytes(&self) -> &[u8] { + pub fn secret_bytes(&self) -> [u8; 32] { match self { - SsiSecret::Bip340(sk) => sk.0.as_ref(), - SsiSecret::Ed25519(sk) => sk.0.as_ref(), + SsiSecret::Bip340(sk) => sk.0.secret_bytes(), + SsiSecret::Ed25519(sk) => sk.0.seed().scalar(), } } }