Migrate to Crypto::PublicKey32 and PrivateKey32

This commit is contained in:
Jazz Turner-Baggs 2026-01-30 12:28:29 -08:00
parent 5adee47a97
commit 143cb38052
No known key found for this signature in database
9 changed files with 51 additions and 41 deletions

1
Cargo.lock generated
View File

@ -218,6 +218,7 @@ version = "0.0.1"
dependencies = [ dependencies = [
"blake2", "blake2",
"chacha20poly1305", "chacha20poly1305",
"crypto",
"hkdf", "hkdf",
"rand", "rand",
"rand_core", "rand_core",

View File

@ -4,6 +4,7 @@ use prost::bytes::Bytes;
pub use crypto::{PrivateKey32, PublicKey32}; pub use crypto::{PrivateKey32, PublicKey32};
// TODO: (P4) Make handing of Keys in Prost easier
pub trait CopyBytes { pub trait CopyBytes {
fn copy_to_bytes(&self) -> Bytes; fn copy_to_bytes(&self) -> Bytes;
} }

View File

@ -1,24 +1,15 @@
use generic_array::{GenericArray, typenum::U32}; use generic_array::{GenericArray, typenum::U32};
use rand_core::{CryptoRng, OsRng, RngCore}; use rand_core::{CryptoRng, OsRng, RngCore};
use std::{fmt::Debug, ops::Deref}; use std::{
fmt::Debug,
ops::{Deref, DerefMut},
};
use x25519_dalek; use x25519_dalek;
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct PublicKey32(x25519_dalek::PublicKey); pub struct PublicKey32(x25519_dalek::PublicKey);
impl From<x25519_dalek::PublicKey> for PublicKey32 {
fn from(value: x25519_dalek::PublicKey) -> Self {
Self(value)
}
}
impl From<&x25519_dalek::StaticSecret> for PublicKey32 {
fn from(value: &x25519_dalek::StaticSecret) -> Self {
Self(x25519_dalek::PublicKey::from(value))
}
}
impl From<&PrivateKey32> for PublicKey32 { impl From<&PrivateKey32> for PublicKey32 {
fn from(value: &PrivateKey32) -> Self { fn from(value: &PrivateKey32) -> Self {
Self(x25519_dalek::PublicKey::from(&value.0)) Self(x25519_dalek::PublicKey::from(&value.0))
@ -38,6 +29,12 @@ impl Deref for PublicKey32 {
} }
} }
impl DerefMut for PublicKey32 {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl AsRef<[u8]> for PublicKey32 { impl AsRef<[u8]> for PublicKey32 {
fn as_ref(&self) -> &[u8] { fn as_ref(&self) -> &[u8] {
self.0.as_ref() self.0.as_ref()
@ -58,6 +55,12 @@ impl PrivateKey32 {
} }
} }
impl From<[u8; 32]> for PrivateKey32 {
fn from(value: [u8; 32]) -> Self {
Self(x25519_dalek::StaticSecret::from(value))
}
}
impl Deref for PrivateKey32 { impl Deref for PrivateKey32 {
type Target = x25519_dalek::StaticSecret; type Target = x25519_dalek::StaticSecret;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {

View File

@ -11,8 +11,8 @@ name = "generate-headers"
required-features = ["headers"] required-features = ["headers"]
[dependencies] [dependencies]
x25519-dalek = { version="2.0.1", features=["static_secrets"] }
chacha20poly1305 = "0.10.1" chacha20poly1305 = "0.10.1"
crypto = { path = "../crypto" }
rand_core = "0.6.4" rand_core = "0.6.4"
rand = "0.8.5" rand = "0.8.5"
hkdf = "0.12.4" hkdf = "0.12.4"

View File

@ -1,5 +1,5 @@
use crypto::PublicKey32;
use safer_ffi::prelude::*; use safer_ffi::prelude::*;
use x25519_dalek::PublicKey;
use crate::{ use crate::{
Header, RatchetState, Header, RatchetState,
@ -22,7 +22,7 @@ fn double_ratchet_init_sender(
shared_secret: [u8; 32], shared_secret: [u8; 32],
remote_pub: [u8; 32], remote_pub: [u8; 32],
) -> repr_c::Box<FFIRatchetState> { ) -> repr_c::Box<FFIRatchetState> {
let state = RatchetState::init_sender(shared_secret, PublicKey::from(remote_pub)); let state = RatchetState::init_sender(shared_secret, PublicKey32::from(remote_pub));
Box::new(FFIRatchetState(state)).into() Box::new(FFIRatchetState(state)).into()
} }

View File

@ -1,27 +1,27 @@
use crypto::{PrivateKey32, PublicKey32};
use rand_core::OsRng; use rand_core::OsRng;
use x25519_dalek::{PublicKey, StaticSecret};
use zeroize::{Zeroize, ZeroizeOnDrop}; use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::types::SharedSecret; use crate::types::SharedSecret;
#[derive(Clone, Zeroize, ZeroizeOnDrop)] #[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct InstallationKeyPair { pub struct InstallationKeyPair {
secret: StaticSecret, secret: PrivateKey32,
public: PublicKey, public: PublicKey32,
} }
impl InstallationKeyPair { impl InstallationKeyPair {
pub fn generate() -> Self { pub fn generate() -> Self {
let secret = StaticSecret::random_from_rng(OsRng); let secret = PrivateKey32::random_from_rng(OsRng);
let public = PublicKey::from(&secret); let public = PublicKey32::from(&secret);
Self { secret, public } Self { secret, public }
} }
pub fn dh(&self, their_public: &PublicKey) -> SharedSecret { pub fn dh(&self, their_public: &PublicKey32) -> SharedSecret {
self.secret.diffie_hellman(their_public).to_bytes() self.secret.diffie_hellman(their_public).to_bytes()
} }
pub fn public(&self) -> &PublicKey { pub fn public(&self) -> &PublicKey32 {
&self.public &self.public
} }
@ -32,8 +32,8 @@ impl InstallationKeyPair {
/// Import the secret key from raw bytes. /// Import the secret key from raw bytes.
pub fn from_secret_bytes(bytes: [u8; 32]) -> Self { pub fn from_secret_bytes(bytes: [u8; 32]) -> Self {
let secret = StaticSecret::from(bytes); let secret = PrivateKey32::from(bytes);
let public = PublicKey::from(&secret); let public = PublicKey32::from(&secret);
Self { secret, public } Self { secret, public }
} }
} }

View File

@ -1,7 +1,7 @@
use std::{collections::HashMap, marker::PhantomData}; use std::{collections::HashMap, marker::PhantomData};
use crypto::PublicKey32;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError}; use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
use x25519_dalek::PublicKey;
use zeroize::{Zeroize, Zeroizing}; use zeroize::{Zeroize, Zeroizing};
use crate::{ use crate::{
@ -29,13 +29,13 @@ pub struct RatchetState<D: HkdfInfo = DefaultDomain> {
pub receiving_chain: Option<ChainKey>, pub receiving_chain: Option<ChainKey>,
pub dh_self: InstallationKeyPair, pub dh_self: InstallationKeyPair,
pub dh_remote: Option<PublicKey>, pub dh_remote: Option<PublicKey32>,
pub msg_send: u32, pub msg_send: u32,
pub msg_recv: u32, pub msg_recv: u32,
pub prev_chain_len: u32, pub prev_chain_len: u32,
pub skipped_keys: HashMap<(PublicKey, u32), MessageKey>, pub skipped_keys: HashMap<(PublicKey32, u32), MessageKey>,
pub(crate) _domain: PhantomData<D>, pub(crate) _domain: PhantomData<D>,
} }
@ -144,7 +144,7 @@ impl<D: HkdfInfo> RatchetState<D> {
let dh_self = InstallationKeyPair::from_secret_bytes(dh_self_bytes); let dh_self = InstallationKeyPair::from_secret_bytes(dh_self_bytes);
dh_self_bytes.zeroize(); dh_self_bytes.zeroize();
let dh_remote = reader.read_option()?.map(PublicKey::from); let dh_remote = reader.read_option()?.map(PublicKey32::from);
let msg_send = reader.read_u32()?; let msg_send = reader.read_u32()?;
let msg_recv = 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 skipped_count = reader.read_u32()? as usize;
let mut skipped_keys = HashMap::with_capacity(skipped_count); let mut skipped_keys = HashMap::with_capacity(skipped_count);
for _ in 0..skipped_count { for _ in 0..skipped_count {
let pk = PublicKey::from(reader.read_array::<32>()?); let pk = PublicKey32::from(reader.read_array::<32>()?);
let msg_num = reader.read_u32()?; let msg_num = reader.read_u32()?;
let mk: MessageKey = reader.read_array()?; let mk: MessageKey = reader.read_array()?;
skipped_keys.insert((pk, msg_num), mk); 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). /// Public header attached to every encrypted message (unencrypted but authenticated).
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Header { pub struct Header {
pub dh_pub: PublicKey, pub dh_pub: PublicKey32,
pub msg_num: u32, pub msg_num: u32,
pub prev_chain_len: u32, pub prev_chain_len: u32,
} }
@ -233,7 +233,7 @@ impl<D: HkdfInfo> RatchetState<D> {
/// # Returns /// # Returns
/// ///
/// A new `RatchetState` ready to send the first message. /// A new `RatchetState` ready to send the first message.
pub fn init_sender(shared_secret: SharedSecret, remote_pub: PublicKey) -> Self { pub fn init_sender(shared_secret: SharedSecret, remote_pub: PublicKey32) -> Self {
let dh_self = InstallationKeyPair::generate(); let dh_self = InstallationKeyPair::generate();
// Initial DH // Initial DH
@ -296,7 +296,7 @@ impl<D: HkdfInfo> RatchetState<D> {
/// # Arguments /// # Arguments
/// ///
/// * `remote_pub` - The new DH public key from the sender. /// * `remote_pub` - The new DH public key from the sender.
pub fn dh_ratchet_receive(&mut self, remote_pub: PublicKey) { pub fn dh_ratchet_receive(&mut self, remote_pub: PublicKey32) {
let dh_out = self.dh_self.dh(&remote_pub); let dh_out = self.dh_self.dh(&remote_pub);
let (new_root, recv_chain) = kdf_root::<D>(&self.root_key, &dh_out); 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) // Tamper with header (change DH pub byte)
let mut tampered_pub_bytes = header.dh_pub.to_bytes(); let mut tampered_pub_bytes = header.dh_pub.to_bytes();
tampered_pub_bytes[0] ^= 0xff; tampered_pub_bytes[0] ^= 0xff;
header.dh_pub = PublicKey::from(tampered_pub_bytes); header.dh_pub = PublicKey32::from(tampered_pub_bytes);
let result = bob.decrypt_message(&ct, header); let result = bob.decrypt_message(&ct, header);
assert!(result.is_err()); assert!(result.is_err());

View File

@ -1,4 +1,4 @@
use x25519_dalek::PublicKey; use crypto::PublicKey32;
use crate::{ use crate::{
InstallationKeyPair, InstallationKeyPair,
@ -82,7 +82,7 @@ impl<'a, D: HkdfInfo + Clone> RatchetSession<'a, D> {
storage: &'a mut SqliteStorage, storage: &'a mut SqliteStorage,
conversation_id: impl Into<String>, conversation_id: impl Into<String>,
shared_secret: SharedSecret, shared_secret: SharedSecret,
remote_pub: PublicKey, remote_pub: PublicKey32,
) -> Result<Self, StorageError> { ) -> Result<Self, StorageError> {
let state = RatchetState::<D>::init_sender(shared_secret, remote_pub); let state = RatchetState::<D>::init_sender(shared_secret, remote_pub);
Self::create(storage, conversation_id, state) Self::create(storage, conversation_id, state)

View File

@ -3,8 +3,8 @@ use crate::{
state::{RatchetState, SkippedKey}, state::{RatchetState, SkippedKey},
types::MessageKey, types::MessageKey,
}; };
use crypto::PublicKey32;
use thiserror::Error; use thiserror::Error;
use x25519_dalek::PublicKey;
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum StorageError { pub enum StorageError {
@ -58,11 +58,16 @@ impl RatchetStateRecord {
use std::marker::PhantomData; use std::marker::PhantomData;
let dh_self = InstallationKeyPair::from_secret_bytes(self.dh_self_secret); let dh_self = InstallationKeyPair::from_secret_bytes(self.dh_self_secret);
let dh_remote = self.dh_remote.map(PublicKey::from); let dh_remote = self.dh_remote.map(PublicKey32::from);
let skipped: HashMap<(PublicKey, u32), MessageKey> = skipped_keys let skipped: HashMap<(PublicKey32, u32), MessageKey> = skipped_keys
.into_iter() .into_iter()
.map(|sk| ((PublicKey::from(sk.public_key), sk.msg_num), sk.message_key)) .map(|sk| {
(
(PublicKey32::from(sk.public_key), sk.msg_num),
sk.message_key,
)
})
.collect(); .collect();
RatchetState { RatchetState {