mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-03-26 22:23:14 +00:00
Rename to PublicKey and PrivateKey
This commit is contained in:
parent
99264d2f66
commit
c9d84a482c
@ -7,7 +7,7 @@ use chat_proto::logoschat::{
|
||||
encryption::{Doubleratchet, EncryptedPayload, encrypted_payload::Encryption},
|
||||
};
|
||||
use crypto::SymmetricKey32;
|
||||
use crypto::X25519PublicKey;
|
||||
use crypto::PublicKey;
|
||||
use double_ratchets::{Header, InstallationKeyPair, RatchetState};
|
||||
use prost::{Message, bytes::Bytes};
|
||||
use std::fmt::Debug;
|
||||
@ -60,7 +60,7 @@ pub struct PrivateV1Convo {
|
||||
}
|
||||
|
||||
impl PrivateV1Convo {
|
||||
pub fn new_initiator(seed_key: SymmetricKey32, remote: X25519PublicKey) -> Self {
|
||||
pub fn new_initiator(seed_key: SymmetricKey32, remote: PublicKey) -> Self {
|
||||
let base_convo_id = BaseConvoId::new(&seed_key);
|
||||
let local_convo_id = base_convo_id.id_for_participant(Role::Initiator);
|
||||
let remote_convo_id = base_convo_id.id_for_participant(Role::Responder);
|
||||
@ -125,13 +125,13 @@ impl PrivateV1Convo {
|
||||
return Err(EncryptionError::Decryption("missing payload".into()));
|
||||
};
|
||||
|
||||
// Turn the bytes into a X25519PublicKey
|
||||
// Turn the bytes into a PublicKey
|
||||
let byte_arr: [u8; 32] = dr_header
|
||||
.dh
|
||||
.to_vec()
|
||||
.try_into()
|
||||
.map_err(|_| EncryptionError::Decryption("invalid public key length".into()))?;
|
||||
let dh_pub = X25519PublicKey::from(byte_arr);
|
||||
let dh_pub = PublicKey::from(byte_arr);
|
||||
|
||||
// Build the Header that DR impl expects
|
||||
let header = Header {
|
||||
@ -221,16 +221,16 @@ impl Debug for PrivateV1Convo {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crypto::X25519PrivateKey;
|
||||
use crypto::PrivateKey;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_encrypt_roundtrip() {
|
||||
let saro = X25519PrivateKey::random();
|
||||
let raya = X25519PrivateKey::random();
|
||||
let saro = PrivateKey::random();
|
||||
let raya = PrivateKey::random();
|
||||
|
||||
let pub_raya = X25519PublicKey::from(&raya);
|
||||
let pub_raya = PublicKey::from(&raya);
|
||||
|
||||
let seed_key = saro.diffie_hellman(&pub_raya);
|
||||
let send_content_bytes = vec![0, 2, 4, 6, 8];
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
pub use crypto::{X25519PrivateKey, X25519PublicKey};
|
||||
pub use crypto::{PrivateKey, PublicKey};
|
||||
|
||||
use prost::bytes::Bytes;
|
||||
|
||||
@ -6,7 +6,7 @@ pub trait CopyBytes {
|
||||
fn copy_to_bytes(&self) -> Bytes;
|
||||
}
|
||||
|
||||
impl CopyBytes for X25519PublicKey {
|
||||
impl CopyBytes for PublicKey {
|
||||
fn copy_to_bytes(&self) -> Bytes {
|
||||
Bytes::copy_from_slice(self.as_bytes())
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::crypto::{X25519PrivateKey, X25519PublicKey};
|
||||
use crate::crypto::{PrivateKey, PublicKey};
|
||||
|
||||
pub struct Identity {
|
||||
secret: X25519PrivateKey,
|
||||
secret: PrivateKey,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Identity {
|
||||
@ -18,15 +18,15 @@ impl fmt::Debug for Identity {
|
||||
impl Identity {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
secret: X25519PrivateKey::random(),
|
||||
secret: PrivateKey::random(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn public_key(&self) -> X25519PublicKey {
|
||||
X25519PublicKey::from(&self.secret)
|
||||
pub fn public_key(&self) -> PublicKey {
|
||||
PublicKey::from(&self.secret)
|
||||
}
|
||||
|
||||
pub fn secret(&self) -> &X25519PrivateKey {
|
||||
pub fn secret(&self) -> &PrivateKey {
|
||||
&self.secret
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,14 +10,14 @@ use crypto::{PrekeyBundle, SymmetricKey32};
|
||||
|
||||
use crate::context::Introduction;
|
||||
use crate::conversation::{ChatError, ConversationId, Convo, Id, PrivateV1Convo};
|
||||
use crate::crypto::{CopyBytes, X25519PrivateKey, X25519PublicKey};
|
||||
use crate::crypto::{CopyBytes, PrivateKey, PublicKey};
|
||||
use crate::identity::Identity;
|
||||
use crate::inbox::handshake::InboxHandshake;
|
||||
use crate::proto;
|
||||
use crate::types::{AddressedEncryptedPayload, ContentData};
|
||||
|
||||
/// Compute the deterministic Delivery_address for an installation
|
||||
fn delivery_address_for_installation(_: X25519PublicKey) -> String {
|
||||
fn delivery_address_for_installation(_: PublicKey) -> String {
|
||||
// TODO: Implement Delivery Address
|
||||
"delivery_address".into()
|
||||
}
|
||||
@ -25,7 +25,7 @@ fn delivery_address_for_installation(_: X25519PublicKey) -> String {
|
||||
pub struct Inbox {
|
||||
ident: Rc<Identity>,
|
||||
local_convo_id: String,
|
||||
ephemeral_keys: HashMap<String, X25519PrivateKey>,
|
||||
ephemeral_keys: HashMap<String, PrivateKey>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Inbox {
|
||||
@ -47,14 +47,14 @@ impl Inbox {
|
||||
Self {
|
||||
ident,
|
||||
local_convo_id,
|
||||
ephemeral_keys: HashMap::<String, X25519PrivateKey>::new(),
|
||||
ephemeral_keys: HashMap::<String, PrivateKey>::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_intro_bundle(&mut self) -> Introduction {
|
||||
let ephemeral = X25519PrivateKey::random();
|
||||
let ephemeral = PrivateKey::random();
|
||||
|
||||
let ephemeral_key: X25519PublicKey = (&ephemeral).into();
|
||||
let ephemeral_key: PublicKey = (&ephemeral).into();
|
||||
self.ephemeral_keys
|
||||
.insert(hex::encode(ephemeral_key.as_bytes()), ephemeral);
|
||||
|
||||
@ -169,17 +169,17 @@ impl Inbox {
|
||||
|
||||
fn perform_handshake(
|
||||
&self,
|
||||
ephemeral_key: &X25519PrivateKey,
|
||||
ephemeral_key: &PrivateKey,
|
||||
header: proto::InboxHeaderV1,
|
||||
bytes: Bytes,
|
||||
) -> Result<(SymmetricKey32, proto::InboxV1Frame), ChatError> {
|
||||
// Get X25519PublicKeys from protobuf
|
||||
let initator_static = X25519PublicKey::from(
|
||||
// Get PublicKeys from protobuf
|
||||
let initator_static = PublicKey::from(
|
||||
<[u8; 32]>::try_from(header.initiator_static.as_ref())
|
||||
.map_err(|_| ChatError::BadBundleValue("wrong size - initator static".into()))?,
|
||||
);
|
||||
|
||||
let initator_ephemeral = X25519PublicKey::from(
|
||||
let initator_ephemeral = PublicKey::from(
|
||||
<[u8; 32]>::try_from(header.initiator_ephemeral.as_ref())
|
||||
.map_err(|_| ChatError::BadBundleValue("wrong size - initator ephemeral".into()))?,
|
||||
);
|
||||
@ -215,13 +215,13 @@ impl Inbox {
|
||||
Ok(frame)
|
||||
}
|
||||
|
||||
fn lookup_ephemeral_key(&self, key: &str) -> Result<&X25519PrivateKey, ChatError> {
|
||||
fn lookup_ephemeral_key(&self, key: &str) -> Result<&PrivateKey, ChatError> {
|
||||
self.ephemeral_keys
|
||||
.get(key)
|
||||
.ok_or(ChatError::UnknownEphemeralKey())
|
||||
}
|
||||
|
||||
pub fn inbox_identifier_for_key(pubkey: X25519PublicKey) -> String {
|
||||
pub fn inbox_identifier_for_key(pubkey: PublicKey) -> String {
|
||||
// TODO: Implement ID according to spec
|
||||
hex::encode(Blake2b512::digest(pubkey))
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ use blake2::{
|
||||
use crypto::{DomainSeparator, PrekeyBundle, SymmetricKey32, X3Handshake};
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
use crate::crypto::{X25519PrivateKey, X25519PublicKey};
|
||||
use crate::crypto::{PrivateKey, PublicKey};
|
||||
|
||||
type Blake2bMac256 = Blake2bMac<U32>;
|
||||
|
||||
@ -21,10 +21,10 @@ pub struct InboxHandshake {}
|
||||
impl InboxHandshake {
|
||||
/// Performs
|
||||
pub fn perform_as_initiator<R: RngCore + CryptoRng>(
|
||||
identity_keypair: &X25519PrivateKey,
|
||||
identity_keypair: &PrivateKey,
|
||||
recipient_bundle: &PrekeyBundle,
|
||||
rng: &mut R,
|
||||
) -> (SymmetricKey32, X25519PublicKey) {
|
||||
) -> (SymmetricKey32, PublicKey) {
|
||||
// Perform X3DH handshake to get shared secret
|
||||
let (shared_secret, ephemeral_public) =
|
||||
InboxKeyExchange::initator(identity_keypair, recipient_bundle, rng);
|
||||
@ -42,11 +42,11 @@ impl InboxHandshake {
|
||||
/// * `initiator_identity` - Initiator's identity public key
|
||||
/// * `initiator_ephemeral` - Initiator's ephemeral public key
|
||||
pub fn perform_as_responder(
|
||||
identity_keypair: &X25519PrivateKey,
|
||||
signed_prekey: &X25519PrivateKey,
|
||||
onetime_prekey: Option<&X25519PrivateKey>,
|
||||
initiator_identity: &X25519PublicKey,
|
||||
initiator_ephemeral: &X25519PublicKey,
|
||||
identity_keypair: &PrivateKey,
|
||||
signed_prekey: &PrivateKey,
|
||||
onetime_prekey: Option<&PrivateKey>,
|
||||
initiator_identity: &PublicKey,
|
||||
initiator_ephemeral: &PublicKey,
|
||||
) -> SymmetricKey32 {
|
||||
// Perform X3DH to get shared secret
|
||||
let shared_secret = InboxKeyExchange::responder(
|
||||
@ -85,17 +85,17 @@ mod tests {
|
||||
let mut rng = OsRng;
|
||||
|
||||
// Alice (initiator) generates her identity key
|
||||
let alice_identity = X25519PrivateKey::random_from_rng(rng);
|
||||
let alice_identity_pub = X25519PublicKey::from(&alice_identity);
|
||||
let alice_identity = PrivateKey::random_from_rng(rng);
|
||||
let alice_identity_pub = PublicKey::from(&alice_identity);
|
||||
|
||||
// Bob (responder) generates his keys
|
||||
let bob_identity = X25519PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey = X25519PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey_pub = X25519PublicKey::from(&bob_signed_prekey);
|
||||
let bob_identity = PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey = PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey);
|
||||
|
||||
// Create Bob's prekey bundle
|
||||
let bob_bundle = PrekeyBundle {
|
||||
identity_key: X25519PublicKey::from(&bob_identity),
|
||||
identity_key: PublicKey::from(&bob_identity),
|
||||
signed_prekey: bob_signed_prekey_pub,
|
||||
signature: crypto::Ed25519Signature([0u8; 64]),
|
||||
onetime_prekey: None,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD};
|
||||
use chat_proto::logoschat::intro::IntroBundle;
|
||||
use crypto::{Ed25519Signature, X25519PrivateKey, X25519PublicKey};
|
||||
use crypto::{Ed25519Signature, PrivateKey, PublicKey};
|
||||
use prost::Message;
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
|
||||
@ -8,7 +8,7 @@ use crate::errors::ChatError;
|
||||
|
||||
const BUNDLE_PREFIX: &str = "logos_chatintro_1_";
|
||||
|
||||
fn intro_binding_message(ephemeral: &X25519PublicKey) -> Vec<u8> {
|
||||
fn intro_binding_message(ephemeral: &PublicKey) -> Vec<u8> {
|
||||
let mut message = Vec::with_capacity(BUNDLE_PREFIX.len() + 32);
|
||||
message.extend_from_slice(BUNDLE_PREFIX.as_bytes());
|
||||
message.extend_from_slice(ephemeral.as_bytes());
|
||||
@ -16,8 +16,8 @@ fn intro_binding_message(ephemeral: &X25519PublicKey) -> Vec<u8> {
|
||||
}
|
||||
|
||||
pub(crate) fn sign_intro_binding<R: RngCore + CryptoRng>(
|
||||
secret: &X25519PrivateKey,
|
||||
ephemeral: &X25519PublicKey,
|
||||
secret: &PrivateKey,
|
||||
ephemeral: &PublicKey,
|
||||
rng: R,
|
||||
) -> Ed25519Signature {
|
||||
let message = intro_binding_message(ephemeral);
|
||||
@ -25,8 +25,8 @@ pub(crate) fn sign_intro_binding<R: RngCore + CryptoRng>(
|
||||
}
|
||||
|
||||
pub(crate) fn verify_intro_binding(
|
||||
pubkey: &X25519PublicKey,
|
||||
ephemeral: &X25519PublicKey,
|
||||
pubkey: &PublicKey,
|
||||
ephemeral: &PublicKey,
|
||||
signature: &Ed25519Signature,
|
||||
) -> Result<(), crypto::SignatureError> {
|
||||
let message = intro_binding_message(ephemeral);
|
||||
@ -35,16 +35,16 @@ pub(crate) fn verify_intro_binding(
|
||||
|
||||
/// Supplies remote participants with the required keys to use Inbox protocol
|
||||
pub struct Introduction {
|
||||
installation_key: X25519PublicKey,
|
||||
ephemeral_key: X25519PublicKey,
|
||||
installation_key: PublicKey,
|
||||
ephemeral_key: PublicKey,
|
||||
signature: Ed25519Signature,
|
||||
}
|
||||
|
||||
impl Introduction {
|
||||
/// Create a new `Introduction` by signing the ephemeral key with the installation secret.
|
||||
pub(crate) fn new<R: RngCore + CryptoRng>(
|
||||
installation_secret: &X25519PrivateKey,
|
||||
ephemeral_key: X25519PublicKey,
|
||||
installation_secret: &PrivateKey,
|
||||
ephemeral_key: PublicKey,
|
||||
rng: R,
|
||||
) -> Self {
|
||||
let installation_key = installation_secret.into();
|
||||
@ -56,11 +56,11 @@ impl Introduction {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn installation_key(&self) -> &X25519PublicKey {
|
||||
pub fn installation_key(&self) -> &PublicKey {
|
||||
&self.installation_key
|
||||
}
|
||||
|
||||
pub fn ephemeral_key(&self) -> &X25519PublicKey {
|
||||
pub fn ephemeral_key(&self) -> &PublicKey {
|
||||
&self.ephemeral_key
|
||||
}
|
||||
|
||||
@ -125,8 +125,8 @@ impl TryFrom<&[u8]> for Introduction {
|
||||
.try_into()
|
||||
.map_err(|_| ChatError::BadBundleValue("invalid signature length".into()))?;
|
||||
|
||||
let installation_key = X25519PublicKey::from(installation_bytes);
|
||||
let ephemeral_key = X25519PublicKey::from(ephemeral_bytes);
|
||||
let installation_key = PublicKey::from(installation_bytes);
|
||||
let ephemeral_key = PublicKey::from(ephemeral_bytes);
|
||||
let signature = Ed25519Signature(signature_bytes);
|
||||
|
||||
verify_intro_binding(&installation_key, &ephemeral_key, &signature)
|
||||
@ -146,10 +146,10 @@ mod tests {
|
||||
use rand_core::OsRng;
|
||||
|
||||
fn create_test_introduction() -> Introduction {
|
||||
let install_secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let install_secret = PrivateKey::random_from_rng(OsRng);
|
||||
|
||||
let ephemeral_secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let ephemeral_pub: X25519PublicKey = (&ephemeral_secret).into();
|
||||
let ephemeral_secret = PrivateKey::random_from_rng(OsRng);
|
||||
let ephemeral_pub: PublicKey = (&ephemeral_secret).into();
|
||||
|
||||
Introduction::new(&install_secret, ephemeral_pub, OsRng)
|
||||
}
|
||||
|
||||
@ -2,79 +2,78 @@ pub use generic_array::{GenericArray, typenum::U32};
|
||||
|
||||
use rand_core::{CryptoRng, OsRng, RngCore};
|
||||
use std::{fmt::Debug, ops::Deref};
|
||||
use x25519_dalek;
|
||||
use xeddsa::xed25519;
|
||||
use xeddsa::xed25519::{PrivateKey as EdPrivateKey, PublicKey as EdPublicKey};
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Hash, Eq, Zeroize)] // TODO: (!) Zeroize only required by InstallationKeyPair
|
||||
pub struct X25519PublicKey(x25519_dalek::PublicKey);
|
||||
pub struct PublicKey(x25519_dalek::PublicKey);
|
||||
|
||||
impl From<x25519_dalek::PublicKey> for X25519PublicKey {
|
||||
impl From<x25519_dalek::PublicKey> for PublicKey {
|
||||
fn from(value: x25519_dalek::PublicKey) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&X25519PrivateKey> for X25519PublicKey {
|
||||
fn from(value: &X25519PrivateKey) -> Self {
|
||||
impl From<&PrivateKey> for PublicKey {
|
||||
fn from(value: &PrivateKey) -> Self {
|
||||
Self(x25519_dalek::PublicKey::from(&value.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for X25519PublicKey {
|
||||
impl From<[u8; 32]> for PublicKey {
|
||||
fn from(value: [u8; 32]) -> Self {
|
||||
Self(x25519_dalek::PublicKey::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for X25519PublicKey {
|
||||
impl Deref for PublicKey {
|
||||
type Target = x25519_dalek::PublicKey;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for X25519PublicKey {
|
||||
impl AsRef<[u8]> for PublicKey {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.0.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&X25519PublicKey> for xed25519::PublicKey {
|
||||
fn from(value: &X25519PublicKey) -> Self {
|
||||
impl From<&PublicKey> for EdPublicKey {
|
||||
fn from(value: &PublicKey) -> Self {
|
||||
Self::from(&value.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct X25519PrivateKey(x25519_dalek::StaticSecret);
|
||||
pub struct PrivateKey(x25519_dalek::StaticSecret);
|
||||
|
||||
impl X25519PrivateKey {
|
||||
impl PrivateKey {
|
||||
pub fn random_from_rng<T: RngCore + CryptoRng>(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() -> X25519PrivateKey {
|
||||
Self::random_from_rng(&mut OsRng)
|
||||
pub fn random() -> PrivateKey {
|
||||
Self::random_from_rng(OsRng)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for X25519PrivateKey {
|
||||
impl From<[u8; 32]> for PrivateKey {
|
||||
fn from(value: [u8; 32]) -> Self {
|
||||
Self(x25519_dalek::StaticSecret::from(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for X25519PrivateKey {
|
||||
impl Deref for PrivateKey {
|
||||
type Target = x25519_dalek::StaticSecret;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&X25519PrivateKey> for xed25519::PrivateKey {
|
||||
fn from(value: &X25519PrivateKey) -> Self {
|
||||
impl From<&PrivateKey> for EdPrivateKey {
|
||||
fn from(value: &PrivateKey) -> Self {
|
||||
Self::from(&value.0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,6 @@ mod keys;
|
||||
mod x3dh;
|
||||
mod xeddsa_sign;
|
||||
|
||||
pub use keys::{GenericArray, SymmetricKey32, X25519PrivateKey, X25519PublicKey};
|
||||
pub use keys::{GenericArray, SymmetricKey32, PrivateKey, PublicKey};
|
||||
pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake};
|
||||
pub use xeddsa_sign::{Ed25519Signature, SignatureError, xeddsa_sign, xeddsa_verify};
|
||||
|
||||
@ -5,16 +5,16 @@ use rand_core::{CryptoRng, RngCore};
|
||||
use sha2::Sha256;
|
||||
use x25519_dalek::SharedSecret;
|
||||
|
||||
use crate::keys::{SymmetricKey32, X25519PrivateKey, X25519PublicKey};
|
||||
use crate::keys::{SymmetricKey32, PrivateKey, PublicKey};
|
||||
use crate::xeddsa_sign::Ed25519Signature;
|
||||
|
||||
/// A prekey bundle containing the public keys needed to initiate an X3DH key exchange.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PrekeyBundle {
|
||||
pub identity_key: X25519PublicKey,
|
||||
pub signed_prekey: X25519PublicKey,
|
||||
pub identity_key: PublicKey,
|
||||
pub signed_prekey: PublicKey,
|
||||
pub signature: Ed25519Signature,
|
||||
pub onetime_prekey: Option<X25519PublicKey>,
|
||||
pub onetime_prekey: Option<PublicKey>,
|
||||
}
|
||||
|
||||
pub trait DomainSeparator {
|
||||
@ -67,13 +67,13 @@ impl<D: DomainSeparator> X3Handshake<D> {
|
||||
/// # Returns
|
||||
/// A tuple of (shared secret bytes, ephemeral public key)
|
||||
pub fn initator<R: RngCore + CryptoRng>(
|
||||
identity_keypair: &X25519PrivateKey,
|
||||
identity_keypair: &PrivateKey,
|
||||
recipient_bundle: &PrekeyBundle,
|
||||
rng: &mut R,
|
||||
) -> (SymmetricKey32, X25519PublicKey) {
|
||||
// Generate ephemeral key for this handshake (using X25519PrivateKey for multiple DH operations)
|
||||
let ephemeral_secret = X25519PrivateKey::random_from_rng(rng);
|
||||
let ephemeral_public = X25519PublicKey::from(&ephemeral_secret);
|
||||
) -> (SymmetricKey32, PublicKey) {
|
||||
// Generate ephemeral key for this handshake (using PrivateKey for multiple DH operations)
|
||||
let ephemeral_secret = PrivateKey::random_from_rng(rng);
|
||||
let ephemeral_public = PublicKey::from(&ephemeral_secret);
|
||||
|
||||
// Perform the 4 Diffie-Hellman operations
|
||||
let dh1 = identity_keypair.diffie_hellman(&recipient_bundle.signed_prekey);
|
||||
@ -102,11 +102,11 @@ impl<D: DomainSeparator> X3Handshake<D> {
|
||||
/// # Returns
|
||||
/// The derived shared secret bytes
|
||||
pub fn responder(
|
||||
identity_keypair: &X25519PrivateKey,
|
||||
signed_prekey: &X25519PrivateKey,
|
||||
onetime_prekey: Option<&X25519PrivateKey>,
|
||||
initiator_identity: &X25519PublicKey,
|
||||
initiator_ephemeral: &X25519PublicKey,
|
||||
identity_keypair: &PrivateKey,
|
||||
signed_prekey: &PrivateKey,
|
||||
onetime_prekey: Option<&PrivateKey>,
|
||||
initiator_identity: &PublicKey,
|
||||
initiator_ephemeral: &PublicKey,
|
||||
) -> SymmetricKey32 {
|
||||
let dh1 = signed_prekey.diffie_hellman(initiator_identity);
|
||||
let dh2 = identity_keypair.diffie_hellman(initiator_ephemeral);
|
||||
@ -135,18 +135,18 @@ mod tests {
|
||||
let mut rng = OsRng;
|
||||
|
||||
// Alice (initiator) generates her identity key
|
||||
let alice_identity = X25519PrivateKey::random_from_rng(rng);
|
||||
let alice_identity_pub = X25519PublicKey::from(&alice_identity);
|
||||
let alice_identity = PrivateKey::random_from_rng(rng);
|
||||
let alice_identity_pub = PublicKey::from(&alice_identity);
|
||||
|
||||
// Bob (responder) generates his keys
|
||||
let bob_identity = X25519PrivateKey::random_from_rng(rng);
|
||||
let bob_identity_pub = X25519PublicKey::from(&bob_identity);
|
||||
let bob_identity = PrivateKey::random_from_rng(rng);
|
||||
let bob_identity_pub = PublicKey::from(&bob_identity);
|
||||
|
||||
let bob_signed_prekey = X25519PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey_pub = X25519PublicKey::from(&bob_signed_prekey);
|
||||
let bob_signed_prekey = PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey);
|
||||
|
||||
let bob_onetime_prekey = X25519PrivateKey::random_from_rng(rng);
|
||||
let bob_onetime_prekey_pub = X25519PublicKey::from(&bob_onetime_prekey);
|
||||
let bob_onetime_prekey = PrivateKey::random_from_rng(rng);
|
||||
let bob_onetime_prekey_pub = PublicKey::from(&bob_onetime_prekey);
|
||||
|
||||
// Create Bob's prekey bundle (with one-time prekey)
|
||||
let bob_bundle = PrekeyBundle {
|
||||
@ -178,15 +178,15 @@ mod tests {
|
||||
let mut rng = OsRng;
|
||||
|
||||
// Alice (initiator) generates her identity key
|
||||
let alice_identity = X25519PrivateKey::random_from_rng(rng);
|
||||
let alice_identity_pub = X25519PublicKey::from(&alice_identity);
|
||||
let alice_identity = PrivateKey::random_from_rng(rng);
|
||||
let alice_identity_pub = PublicKey::from(&alice_identity);
|
||||
|
||||
// Bob (responder) generates his keys
|
||||
let bob_identity = X25519PrivateKey::random_from_rng(rng);
|
||||
let bob_identity_pub = X25519PublicKey::from(&bob_identity);
|
||||
let bob_identity = PrivateKey::random_from_rng(rng);
|
||||
let bob_identity_pub = PublicKey::from(&bob_identity);
|
||||
|
||||
let bob_signed_prekey = X25519PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey_pub = X25519PublicKey::from(&bob_signed_prekey);
|
||||
let bob_signed_prekey = PrivateKey::random_from_rng(rng);
|
||||
let bob_signed_prekey_pub = PublicKey::from(&bob_signed_prekey);
|
||||
|
||||
// Create Bob's prekey bundle (without one-time prekey)
|
||||
let bob_bundle = PrekeyBundle {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
use rand_core::{CryptoRng, RngCore};
|
||||
use xeddsa::{Sign, Verify, xed25519};
|
||||
|
||||
use crate::keys::{X25519PrivateKey, X25519PublicKey};
|
||||
use crate::keys::{PrivateKey, PublicKey};
|
||||
|
||||
/// A 64-byte XEdDSA signature over an Ed25519-compatible curve.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
@ -45,7 +45,7 @@ pub struct SignatureError;
|
||||
/// # Returns
|
||||
/// An `Ed25519Signature`
|
||||
pub fn xeddsa_sign<R: RngCore + CryptoRng>(
|
||||
secret: &X25519PrivateKey,
|
||||
secret: &PrivateKey,
|
||||
message: &[u8],
|
||||
mut rng: R,
|
||||
) -> Ed25519Signature {
|
||||
@ -63,7 +63,7 @@ pub fn xeddsa_sign<R: RngCore + CryptoRng>(
|
||||
/// # Returns
|
||||
/// `Ok(())` if the signature is valid, `Err(SignatureError)` otherwise
|
||||
pub fn xeddsa_verify(
|
||||
pubkey: &X25519PublicKey,
|
||||
pubkey: &PublicKey,
|
||||
message: &[u8],
|
||||
signature: &Ed25519Signature,
|
||||
) -> Result<(), SignatureError> {
|
||||
@ -80,8 +80,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_sign_and_verify_roundtrip() {
|
||||
let secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let public = X25519PublicKey::from(&secret);
|
||||
let secret = PrivateKey::random_from_rng(OsRng);
|
||||
let public = PublicKey::from(&secret);
|
||||
let message = b"test message";
|
||||
|
||||
let signature = xeddsa_sign(&secret, message, OsRng);
|
||||
@ -91,13 +91,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_wrong_key_fails() {
|
||||
let secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let secret = PrivateKey::random_from_rng(OsRng);
|
||||
let message = b"test message";
|
||||
|
||||
let signature = xeddsa_sign(&secret, message, OsRng);
|
||||
|
||||
let wrong_secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let wrong_public = X25519PublicKey::from(&wrong_secret);
|
||||
let wrong_secret = PrivateKey::random_from_rng(OsRng);
|
||||
let wrong_public = PublicKey::from(&wrong_secret);
|
||||
|
||||
assert_eq!(
|
||||
xeddsa_verify(&wrong_public, message, &signature),
|
||||
@ -107,8 +107,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_wrong_message_fails() {
|
||||
let secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let public = X25519PublicKey::from(&secret);
|
||||
let secret = PrivateKey::random_from_rng(OsRng);
|
||||
let public = PublicKey::from(&secret);
|
||||
let message = b"test message";
|
||||
|
||||
let signature = xeddsa_sign(&secret, message, OsRng);
|
||||
@ -121,8 +121,8 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_corrupted_signature_fails() {
|
||||
let secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let public = X25519PublicKey::from(&secret);
|
||||
let secret = PrivateKey::random_from_rng(OsRng);
|
||||
let public = PublicKey::from(&secret);
|
||||
let message = b"test message";
|
||||
|
||||
let mut signature = xeddsa_sign(&secret, message, OsRng);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crypto::X25519PublicKey;
|
||||
use crypto::PublicKey;
|
||||
use safer_ffi::prelude::*;
|
||||
|
||||
use crate::{
|
||||
@ -22,7 +22,7 @@ fn double_ratchet_init_sender(
|
||||
shared_secret: [u8; 32],
|
||||
remote_pub: [u8; 32],
|
||||
) -> repr_c::Box<FFIRatchetState> {
|
||||
let state = RatchetState::init_sender(shared_secret, X25519PublicKey::from(remote_pub));
|
||||
let state = RatchetState::init_sender(shared_secret, PublicKey::from(remote_pub));
|
||||
Box::new(FFIRatchetState(state)).into()
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crypto::{X25519PrivateKey, X25519PublicKey};
|
||||
use crypto::{PrivateKey, PublicKey};
|
||||
use rand_core::OsRng;
|
||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||
|
||||
@ -6,22 +6,22 @@ use crate::types::SharedSecret;
|
||||
|
||||
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
|
||||
pub struct InstallationKeyPair {
|
||||
secret: X25519PrivateKey,
|
||||
public: X25519PublicKey,
|
||||
secret: PrivateKey,
|
||||
public: PublicKey,
|
||||
}
|
||||
|
||||
impl InstallationKeyPair {
|
||||
pub fn generate() -> Self {
|
||||
let secret = X25519PrivateKey::random_from_rng(OsRng);
|
||||
let public = X25519PublicKey::from(&secret);
|
||||
let secret = PrivateKey::random_from_rng(OsRng);
|
||||
let public = PublicKey::from(&secret);
|
||||
Self { secret, public }
|
||||
}
|
||||
|
||||
pub fn dh(&self, their_public: &X25519PublicKey) -> SharedSecret {
|
||||
pub fn dh(&self, their_public: &PublicKey) -> SharedSecret {
|
||||
self.secret.diffie_hellman(their_public).to_bytes()
|
||||
}
|
||||
|
||||
pub fn public(&self) -> &X25519PublicKey {
|
||||
pub fn public(&self) -> &PublicKey {
|
||||
&self.public
|
||||
}
|
||||
|
||||
@ -32,15 +32,15 @@ impl InstallationKeyPair {
|
||||
|
||||
/// Import the secret key from raw bytes.
|
||||
pub fn from_secret_bytes(bytes: [u8; 32]) -> Self {
|
||||
let secret = X25519PrivateKey::from(bytes);
|
||||
let public = X25519PublicKey::from(&secret);
|
||||
let secret = PrivateKey::from(bytes);
|
||||
let public = PublicKey::from(&secret);
|
||||
Self { secret, public }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<X25519PrivateKey> for InstallationKeyPair {
|
||||
fn from(value: X25519PrivateKey) -> Self {
|
||||
let public = X25519PublicKey::from(&value);
|
||||
impl From<PrivateKey> for InstallationKeyPair {
|
||||
fn from(value: PrivateKey) -> Self {
|
||||
let public = PublicKey::from(&value);
|
||||
Self {
|
||||
secret: value,
|
||||
public,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::{collections::HashMap, marker::PhantomData};
|
||||
|
||||
use crypto::X25519PublicKey;
|
||||
use crypto::PublicKey;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
|
||||
use zeroize::{Zeroize, Zeroizing};
|
||||
|
||||
@ -29,13 +29,13 @@ pub struct RatchetState<D: HkdfInfo = DefaultDomain> {
|
||||
pub receiving_chain: Option<ChainKey>,
|
||||
|
||||
pub dh_self: InstallationKeyPair,
|
||||
pub dh_remote: Option<X25519PublicKey>,
|
||||
pub dh_remote: Option<PublicKey>,
|
||||
|
||||
pub msg_send: u32,
|
||||
pub msg_recv: u32,
|
||||
pub prev_chain_len: u32,
|
||||
|
||||
pub skipped_keys: HashMap<(X25519PublicKey, u32), MessageKey>,
|
||||
pub skipped_keys: HashMap<(PublicKey, u32), MessageKey>,
|
||||
|
||||
pub(crate) _domain: PhantomData<D>,
|
||||
}
|
||||
@ -144,7 +144,7 @@ impl<D: HkdfInfo> RatchetState<D> {
|
||||
let dh_self = InstallationKeyPair::from_secret_bytes(dh_self_bytes);
|
||||
dh_self_bytes.zeroize();
|
||||
|
||||
let dh_remote = reader.read_option()?.map(X25519PublicKey::from);
|
||||
let dh_remote = reader.read_option()?.map(PublicKey::from);
|
||||
|
||||
let msg_send = reader.read_u32()?;
|
||||
let msg_recv = reader.read_u32()?;
|
||||
@ -153,7 +153,7 @@ impl<D: HkdfInfo> RatchetState<D> {
|
||||
let skipped_count = reader.read_u32()? as usize;
|
||||
let mut skipped_keys = HashMap::with_capacity(skipped_count);
|
||||
for _ in 0..skipped_count {
|
||||
let pk = X25519PublicKey::from(reader.read_array::<32>()?);
|
||||
let pk = PublicKey::from(reader.read_array::<32>()?);
|
||||
let msg_num = reader.read_u32()?;
|
||||
let mk: MessageKey = reader.read_array()?;
|
||||
skipped_keys.insert((pk, msg_num), mk);
|
||||
@ -198,7 +198,7 @@ impl<'de, D: HkdfInfo> Deserialize<'de> for RatchetState<D> {
|
||||
/// Public header attached to every encrypted message (unencrypted but authenticated).
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Header {
|
||||
pub dh_pub: X25519PublicKey,
|
||||
pub dh_pub: PublicKey,
|
||||
pub msg_num: u32,
|
||||
pub prev_chain_len: u32,
|
||||
}
|
||||
@ -233,7 +233,7 @@ impl<D: HkdfInfo> RatchetState<D> {
|
||||
/// # Returns
|
||||
///
|
||||
/// A new `RatchetState` ready to send the first message.
|
||||
pub fn init_sender(shared_secret: SharedSecret, remote_pub: X25519PublicKey) -> Self {
|
||||
pub fn init_sender(shared_secret: SharedSecret, remote_pub: PublicKey) -> Self {
|
||||
let dh_self = InstallationKeyPair::generate();
|
||||
|
||||
// Initial DH
|
||||
@ -296,7 +296,7 @@ impl<D: HkdfInfo> RatchetState<D> {
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `remote_pub` - The new DH public key from the sender.
|
||||
pub fn dh_ratchet_receive(&mut self, remote_pub: X25519PublicKey) {
|
||||
pub fn dh_ratchet_receive(&mut self, remote_pub: PublicKey) {
|
||||
let dh_out = self.dh_self.dh(&remote_pub);
|
||||
let (new_root, recv_chain) = kdf_root::<D>(&self.root_key, &dh_out);
|
||||
|
||||
@ -605,7 +605,7 @@ mod tests {
|
||||
// Tamper with header (change DH pub byte)
|
||||
let mut tampered_pub_bytes = header.dh_pub.to_bytes();
|
||||
tampered_pub_bytes[0] ^= 0xff;
|
||||
header.dh_pub = X25519PublicKey::from(tampered_pub_bytes);
|
||||
header.dh_pub = PublicKey::from(tampered_pub_bytes);
|
||||
|
||||
let result = bob.decrypt_message(&ct, header);
|
||||
assert!(result.is_err());
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
//! Session wrapper for automatic state persistence.
|
||||
|
||||
use crypto::X25519PublicKey;
|
||||
use crypto::PublicKey;
|
||||
|
||||
use crate::{
|
||||
InstallationKeyPair, SessionError,
|
||||
@ -54,7 +54,7 @@ impl<'a, D: HkdfInfo + Clone> RatchetSession<'a, D> {
|
||||
storage: &'a mut RatchetStorage,
|
||||
conversation_id: &str,
|
||||
shared_secret: SharedSecret,
|
||||
remote_pub: X25519PublicKey,
|
||||
remote_pub: PublicKey,
|
||||
) -> Result<Self, SessionError> {
|
||||
if storage.exists(conversation_id)? {
|
||||
return Err(SessionError::ConvAlreadyExists(conversation_id.to_string()));
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
//! Storage types for ratchet state.
|
||||
use crypto::X25519PublicKey;
|
||||
use crypto::PublicKey;
|
||||
|
||||
use crate::{
|
||||
hkdf::HkdfInfo,
|
||||
@ -42,13 +42,13 @@ impl RatchetStateRecord {
|
||||
use std::marker::PhantomData;
|
||||
|
||||
let dh_self = InstallationKeyPair::from_secret_bytes(self.dh_self_secret);
|
||||
let dh_remote = self.dh_remote.map(X25519PublicKey::from);
|
||||
let dh_remote = self.dh_remote.map(PublicKey::from);
|
||||
|
||||
let skipped: HashMap<(X25519PublicKey, u32), MessageKey> = skipped_keys
|
||||
let skipped: HashMap<(PublicKey, u32), MessageKey> = skipped_keys
|
||||
.into_iter()
|
||||
.map(|sk| {
|
||||
(
|
||||
(X25519PublicKey::from(sk.public_key), sk.msg_num),
|
||||
(PublicKey::from(sk.public_key), sk.msg_num),
|
||||
sk.message_key,
|
||||
)
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user