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 = [
"blake2",
"chacha20poly1305",
"crypto",
"hkdf",
"rand",
"rand_core",

View File

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

View File

@ -1,24 +1,15 @@
use generic_array::{GenericArray, typenum::U32};
use rand_core::{CryptoRng, OsRng, RngCore};
use std::{fmt::Debug, ops::Deref};
use std::{
fmt::Debug,
ops::{Deref, DerefMut},
};
use x25519_dalek;
use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Debug, Copy, Clone)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
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 {
fn from(value: &PrivateKey32) -> Self {
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 {
fn as_ref(&self) -> &[u8] {
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 {
type Target = x25519_dalek::StaticSecret;
fn deref(&self) -> &Self::Target {

View File

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

View File

@ -1,5 +1,5 @@
use crypto::PublicKey32;
use safer_ffi::prelude::*;
use x25519_dalek::PublicKey;
use crate::{
Header, RatchetState,
@ -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, PublicKey::from(remote_pub));
let state = RatchetState::init_sender(shared_secret, PublicKey32::from(remote_pub));
Box::new(FFIRatchetState(state)).into()
}

View File

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

View File

@ -1,7 +1,7 @@
use std::{collections::HashMap, marker::PhantomData};
use crypto::PublicKey32;
use serde::{Deserialize, Deserializer, Serialize, Serializer, de::Error as DeError};
use x25519_dalek::PublicKey;
use zeroize::{Zeroize, Zeroizing};
use crate::{
@ -29,13 +29,13 @@ pub struct RatchetState<D: HkdfInfo = DefaultDomain> {
pub receiving_chain: Option<ChainKey>,
pub dh_self: InstallationKeyPair,
pub dh_remote: Option<PublicKey>,
pub dh_remote: Option<PublicKey32>,
pub msg_send: u32,
pub msg_recv: 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>,
}
@ -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(PublicKey::from);
let dh_remote = reader.read_option()?.map(PublicKey32::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 = PublicKey::from(reader.read_array::<32>()?);
let pk = PublicKey32::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: PublicKey,
pub dh_pub: PublicKey32,
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: PublicKey) -> Self {
pub fn init_sender(shared_secret: SharedSecret, remote_pub: PublicKey32) -> 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: PublicKey) {
pub fn dh_ratchet_receive(&mut self, remote_pub: PublicKey32) {
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 = PublicKey::from(tampered_pub_bytes);
header.dh_pub = PublicKey32::from(tampered_pub_bytes);
let result = bob.decrypt_message(&ct, header);
assert!(result.is_err());

View File

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

View File

@ -3,8 +3,8 @@ use crate::{
state::{RatchetState, SkippedKey},
types::MessageKey,
};
use crypto::PublicKey32;
use thiserror::Error;
use x25519_dalek::PublicKey;
#[derive(Debug, Error)]
pub enum StorageError {
@ -58,11 +58,16 @@ impl RatchetStateRecord {
use std::marker::PhantomData;
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()
.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();
RatchetState {