mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-02-11 01:13:24 +00:00
replace StaticSecret with PrivateKey32
This commit is contained in:
parent
c1abc82f28
commit
5adee47a97
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -473,6 +473,7 @@ dependencies = [
|
|||||||
"crypto",
|
"crypto",
|
||||||
"hex",
|
"hex",
|
||||||
"prost",
|
"prost",
|
||||||
|
"rand",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"safer-ffi",
|
"safer-ffi",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
|||||||
@ -13,6 +13,7 @@ crypto = { path = "../crypto" }
|
|||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
prost = "0.14.1"
|
prost = "0.14.1"
|
||||||
rand_core = { version = "0.6" }
|
rand_core = { version = "0.6" }
|
||||||
|
rand = "0.8.5"
|
||||||
safer-ffi = "0.1.13"
|
safer-ffi = "0.1.13"
|
||||||
thiserror = "2.0.17"
|
thiserror = "2.0.17"
|
||||||
x25519-dalek = { version = "2.0.1", features = ["static_secrets", "reusable_secrets", "getrandom"] }
|
x25519-dalek = { version = "2.0.1", features = ["static_secrets", "reusable_secrets", "getrandom"] }
|
||||||
|
|||||||
@ -2,8 +2,7 @@ pub use blake2::Digest;
|
|||||||
use blake2::{Blake2b, digest};
|
use blake2::{Blake2b, digest};
|
||||||
use prost::bytes::Bytes;
|
use prost::bytes::Bytes;
|
||||||
|
|
||||||
pub use crypto::PublicKey32;
|
pub use crypto::{PrivateKey32, PublicKey32};
|
||||||
pub use x25519_dalek::StaticSecret;
|
|
||||||
|
|
||||||
pub trait CopyBytes {
|
pub trait CopyBytes {
|
||||||
fn copy_to_bytes(&self) -> Bytes;
|
fn copy_to_bytes(&self) -> Bytes;
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
use blake2::{Blake2b512, Digest};
|
use blake2::{Blake2b512, Digest};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::crypto::{PublicKey32, StaticSecret};
|
use crate::crypto::{PrivateKey32, PublicKey32};
|
||||||
use x25519_dalek::PublicKey;
|
|
||||||
|
|
||||||
pub struct Identity {
|
pub struct Identity {
|
||||||
secret: StaticSecret,
|
secret: PrivateKey32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Identity {
|
impl fmt::Debug for Identity {
|
||||||
@ -20,7 +19,7 @@ impl fmt::Debug for Identity {
|
|||||||
impl Identity {
|
impl Identity {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
secret: StaticSecret::random(),
|
secret: PrivateKey32::random(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,10 +28,10 @@ impl Identity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn public_key(&self) -> PublicKey32 {
|
pub fn public_key(&self) -> PublicKey32 {
|
||||||
PublicKey::from(&self.secret).into()
|
PublicKey32::from(&self.secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn secret(&self) -> &StaticSecret {
|
pub fn secret(&self) -> &PrivateKey32 {
|
||||||
&self.secret
|
&self.secret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use blake2::{
|
|||||||
use crypto::{DomainSeparator, PrekeyBundle, SecretKey32, X3Handshake};
|
use crypto::{DomainSeparator, PrekeyBundle, SecretKey32, X3Handshake};
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
use crate::crypto::{PublicKey32, StaticSecret};
|
use crate::crypto::{PrivateKey32, PublicKey32};
|
||||||
|
|
||||||
type Blake2bMac256 = Blake2bMac<U32>;
|
type Blake2bMac256 = Blake2bMac<U32>;
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ pub struct InboxHandshake {}
|
|||||||
impl InboxHandshake {
|
impl InboxHandshake {
|
||||||
/// Performs
|
/// Performs
|
||||||
pub fn perform_as_initiator<R: RngCore + CryptoRng>(
|
pub fn perform_as_initiator<R: RngCore + CryptoRng>(
|
||||||
identity_keypair: &StaticSecret,
|
identity_keypair: &PrivateKey32,
|
||||||
recipient_bundle: &PrekeyBundle,
|
recipient_bundle: &PrekeyBundle,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> (SecretKey32, PublicKey32) {
|
) -> (SecretKey32, PublicKey32) {
|
||||||
@ -42,9 +42,9 @@ impl InboxHandshake {
|
|||||||
/// * `initiator_identity` - Initiator's identity public key
|
/// * `initiator_identity` - Initiator's identity public key
|
||||||
/// * `initiator_ephemeral` - Initiator's ephemeral public key
|
/// * `initiator_ephemeral` - Initiator's ephemeral public key
|
||||||
pub fn perform_as_responder(
|
pub fn perform_as_responder(
|
||||||
identity_keypair: &StaticSecret,
|
identity_keypair: &PrivateKey32,
|
||||||
signed_prekey: &StaticSecret,
|
signed_prekey: &PrivateKey32,
|
||||||
onetime_prekey: Option<&StaticSecret>,
|
onetime_prekey: Option<&PrivateKey32>,
|
||||||
initiator_identity: &PublicKey32,
|
initiator_identity: &PublicKey32,
|
||||||
initiator_ephemeral: &PublicKey32,
|
initiator_ephemeral: &PublicKey32,
|
||||||
) -> SecretKey32 {
|
) -> SecretKey32 {
|
||||||
@ -85,12 +85,12 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
// Alice (initiator) generates her identity key
|
// Alice (initiator) generates her identity key
|
||||||
let alice_identity = StaticSecret::random_from_rng(&mut rng);
|
let alice_identity = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let alice_identity_pub = PublicKey32::from(&alice_identity);
|
let alice_identity_pub = PublicKey32::from(&alice_identity);
|
||||||
|
|
||||||
// Bob (responder) generates his keys
|
// Bob (responder) generates his keys
|
||||||
let bob_identity = StaticSecret::random_from_rng(&mut rng);
|
let bob_identity = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let bob_signed_prekey = StaticSecret::random_from_rng(&mut rng);
|
let bob_signed_prekey = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey);
|
let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey);
|
||||||
|
|
||||||
// Create Bob's prekey bundle
|
// Create Bob's prekey bundle
|
||||||
|
|||||||
@ -9,7 +9,7 @@ use crypto::{PrekeyBundle, SecretKey32};
|
|||||||
|
|
||||||
use crate::context::Introduction;
|
use crate::context::Introduction;
|
||||||
use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo};
|
use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, PrivateV1Convo};
|
||||||
use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey32, StaticSecret};
|
use crate::crypto::{Blake2b128, CopyBytes, Digest, PrivateKey32, PublicKey32};
|
||||||
use crate::identity::Identity;
|
use crate::identity::Identity;
|
||||||
use crate::inbox::handshake::InboxHandshake;
|
use crate::inbox::handshake::InboxHandshake;
|
||||||
use crate::proto;
|
use crate::proto;
|
||||||
@ -24,7 +24,7 @@ fn delivery_address_for_installation(_: PublicKey32) -> String {
|
|||||||
pub struct Inbox {
|
pub struct Inbox {
|
||||||
ident: Rc<Identity>,
|
ident: Rc<Identity>,
|
||||||
local_convo_id: String,
|
local_convo_id: String,
|
||||||
ephemeral_keys: HashMap<String, StaticSecret>,
|
ephemeral_keys: HashMap<String, PrivateKey32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> std::fmt::Debug for Inbox {
|
impl<'a> std::fmt::Debug for Inbox {
|
||||||
@ -46,7 +46,7 @@ impl Inbox {
|
|||||||
Self {
|
Self {
|
||||||
ident,
|
ident,
|
||||||
local_convo_id,
|
local_convo_id,
|
||||||
ephemeral_keys: HashMap::<String, StaticSecret>::new(),
|
ephemeral_keys: HashMap::<String, PrivateKey32>::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ impl Inbox {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_bundle(&mut self) -> PrekeyBundle {
|
pub fn create_bundle(&mut self) -> PrekeyBundle {
|
||||||
let ephemeral = StaticSecret::random();
|
let ephemeral = PrivateKey32::random_from_rng(&mut OsRng);
|
||||||
|
|
||||||
let signed_prekey = PublicKey32::from(&ephemeral);
|
let signed_prekey = PublicKey32::from(&ephemeral);
|
||||||
self.ephemeral_keys
|
self.ephemeral_keys
|
||||||
@ -193,7 +193,7 @@ impl Inbox {
|
|||||||
Ok(frame)
|
Ok(frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_ephemeral_key(&self, key: &str) -> Result<&StaticSecret, ChatError> {
|
fn lookup_ephemeral_key(&self, key: &str) -> Result<&PrivateKey32, ChatError> {
|
||||||
self.ephemeral_keys
|
self.ephemeral_keys
|
||||||
.get(key)
|
.get(key)
|
||||||
.ok_or_else(|| return ChatError::UnknownEphemeralKey())
|
.ok_or_else(|| return ChatError::UnknownEphemeralKey())
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use generic_array::{GenericArray, typenum::U32};
|
use generic_array::{GenericArray, typenum::U32};
|
||||||
|
use rand_core::{CryptoRng, OsRng, RngCore};
|
||||||
use std::{fmt::Debug, ops::Deref};
|
use std::{fmt::Debug, ops::Deref};
|
||||||
use x25519_dalek;
|
use x25519_dalek;
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
@ -18,6 +19,12 @@ impl From<&x25519_dalek::StaticSecret> for PublicKey32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&PrivateKey32> for PublicKey32 {
|
||||||
|
fn from(value: &PrivateKey32) -> Self {
|
||||||
|
Self(x25519_dalek::PublicKey::from(&value.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<[u8; 32]> for PublicKey32 {
|
impl From<[u8; 32]> for PublicKey32 {
|
||||||
fn from(value: [u8; 32]) -> Self {
|
fn from(value: [u8; 32]) -> Self {
|
||||||
Self(x25519_dalek::PublicKey::from(value))
|
Self(x25519_dalek::PublicKey::from(value))
|
||||||
@ -37,6 +44,27 @@ impl AsRef<[u8]> for PublicKey32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
|
||||||
|
pub struct PrivateKey32(x25519_dalek::StaticSecret);
|
||||||
|
|
||||||
|
impl PrivateKey32 {
|
||||||
|
pub fn random_from_rng<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
|
||||||
|
Self(x25519_dalek::StaticSecret::random_from_rng(csprng))
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: Remove. Force internal callers provide Rng to make deterministic testing possible
|
||||||
|
pub fn random() -> PrivateKey32 {
|
||||||
|
Self::random_from_rng(&mut OsRng)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for PrivateKey32 {
|
||||||
|
type Target = x25519_dalek::StaticSecret;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq)]
|
#[derive(Clone, Zeroize, ZeroizeOnDrop, PartialEq)]
|
||||||
pub struct SecretKey32([u8; 32]);
|
pub struct SecretKey32([u8; 32]);
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
mod keys;
|
mod keys;
|
||||||
mod x3dh;
|
mod x3dh;
|
||||||
|
|
||||||
pub use keys::{PublicKey32, SecretKey32};
|
pub use keys::{PrivateKey32, PublicKey32, SecretKey32};
|
||||||
pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake};
|
pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake};
|
||||||
|
|||||||
@ -3,9 +3,9 @@ use std::marker::PhantomData;
|
|||||||
use hkdf::Hkdf;
|
use hkdf::Hkdf;
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
use sha2::Sha256;
|
use sha2::Sha256;
|
||||||
use x25519_dalek::{SharedSecret, StaticSecret};
|
use x25519_dalek::SharedSecret;
|
||||||
|
|
||||||
use crate::keys::{PublicKey32, SecretKey32};
|
use crate::keys::{PrivateKey32, PublicKey32, SecretKey32};
|
||||||
|
|
||||||
/// A prekey bundle containing the public keys needed to initiate an X3DH key exchange.
|
/// A prekey bundle containing the public keys needed to initiate an X3DH key exchange.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@ -66,12 +66,12 @@ impl<D: DomainSeparator> X3Handshake<D> {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// A tuple of (shared secret bytes, ephemeral public key)
|
/// A tuple of (shared secret bytes, ephemeral public key)
|
||||||
pub fn initator<R: RngCore + CryptoRng>(
|
pub fn initator<R: RngCore + CryptoRng>(
|
||||||
identity_keypair: &StaticSecret,
|
identity_keypair: &PrivateKey32,
|
||||||
recipient_bundle: &PrekeyBundle,
|
recipient_bundle: &PrekeyBundle,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> (SecretKey32, PublicKey32) {
|
) -> (SecretKey32, PublicKey32) {
|
||||||
// Generate ephemeral key for this handshake (using StaticSecret for multiple DH operations)
|
// Generate ephemeral key for this handshake
|
||||||
let ephemeral_secret = StaticSecret::random_from_rng(rng);
|
let ephemeral_secret = PrivateKey32::random_from_rng(rng);
|
||||||
let ephemeral_public = PublicKey32::from(&ephemeral_secret);
|
let ephemeral_public = PublicKey32::from(&ephemeral_secret);
|
||||||
|
|
||||||
// Perform the 4 Diffie-Hellman operations
|
// Perform the 4 Diffie-Hellman operations
|
||||||
@ -101,9 +101,9 @@ impl<D: DomainSeparator> X3Handshake<D> {
|
|||||||
/// # Returns
|
/// # Returns
|
||||||
/// The derived shared secret bytes
|
/// The derived shared secret bytes
|
||||||
pub fn responder(
|
pub fn responder(
|
||||||
identity_keypair: &StaticSecret,
|
identity_keypair: &PrivateKey32,
|
||||||
signed_prekey: &StaticSecret,
|
signed_prekey: &PrivateKey32,
|
||||||
onetime_prekey: Option<&StaticSecret>,
|
onetime_prekey: Option<&PrivateKey32>,
|
||||||
initiator_identity: &PublicKey32,
|
initiator_identity: &PublicKey32,
|
||||||
initiator_ephemeral: &PublicKey32,
|
initiator_ephemeral: &PublicKey32,
|
||||||
) -> SecretKey32 {
|
) -> SecretKey32 {
|
||||||
@ -134,17 +134,17 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
// Alice (initiator) generates her identity key
|
// Alice (initiator) generates her identity key
|
||||||
let alice_identity = StaticSecret::random_from_rng(&mut rng);
|
let alice_identity = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let alice_identity_pub = PublicKey32::from(&alice_identity);
|
let alice_identity_pub = PublicKey32::from(&alice_identity);
|
||||||
|
|
||||||
// Bob (responder) generates his keys
|
// Bob (responder) generates his keys
|
||||||
let bob_identity = StaticSecret::random_from_rng(&mut rng);
|
let bob_identity = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let bob_identity_pub = PublicKey32::from(&bob_identity);
|
let bob_identity_pub = PublicKey32::from(&bob_identity);
|
||||||
|
|
||||||
let bob_signed_prekey = StaticSecret::random_from_rng(&mut rng);
|
let bob_signed_prekey = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey);
|
let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey);
|
||||||
|
|
||||||
let bob_onetime_prekey = StaticSecret::random_from_rng(&mut rng);
|
let bob_onetime_prekey = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let bob_onetime_prekey_pub = PublicKey32::from(&bob_onetime_prekey);
|
let bob_onetime_prekey_pub = PublicKey32::from(&bob_onetime_prekey);
|
||||||
|
|
||||||
// Create Bob's prekey bundle (with one-time prekey)
|
// Create Bob's prekey bundle (with one-time prekey)
|
||||||
@ -177,14 +177,14 @@ mod tests {
|
|||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
// Alice (initiator) generates her identity key
|
// Alice (initiator) generates her identity key
|
||||||
let alice_identity = StaticSecret::random_from_rng(&mut rng);
|
let alice_identity = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let alice_identity_pub = PublicKey32::from(&alice_identity);
|
let alice_identity_pub = PublicKey32::from(&alice_identity);
|
||||||
|
|
||||||
// Bob (responder) generates his keys
|
// Bob (responder) generates his keys
|
||||||
let bob_identity = StaticSecret::random_from_rng(&mut rng);
|
let bob_identity = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let bob_identity_pub = PublicKey32::from(&bob_identity);
|
let bob_identity_pub = PublicKey32::from(&bob_identity);
|
||||||
|
|
||||||
let bob_signed_prekey = StaticSecret::random_from_rng(&mut rng);
|
let bob_signed_prekey = PrivateKey32::random_from_rng(&mut rng);
|
||||||
let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey);
|
let bob_signed_prekey_pub = PublicKey32::from(&bob_signed_prekey);
|
||||||
|
|
||||||
// Create Bob's prekey bundle (without one-time prekey)
|
// Create Bob's prekey bundle (without one-time prekey)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user