Replace pqclean crate usages with libcrux

This commit is contained in:
Alex Bakon
2025-04-29 09:22:09 -04:00
committed by GitHub
parent aa71b2f2d8
commit 00ca3f4fd8
15 changed files with 462 additions and 548 deletions

View File

@@ -38,21 +38,30 @@ impl super::LibSignalProtocolStore for LibSignalProtocolCurrent {
let mut csprng = rng();
let pre_key_pair = KeyPair::generate(&mut csprng);
let signed_pre_key_pair = KeyPair::generate(&mut csprng);
let signed_pq_pre_key_pair = kem::KeyPair::generate(kem::KeyType::Kyber1024);
let signed_pre_key_public = signed_pre_key_pair.public_key.serialize();
let signed_pre_key_signature = self
let identity_key = self
.0
.get_identity_key_pair()
.now_or_never()
.expect("synchronous")
.expect("can fetch identity key")
.expect("can fetch identity key");
let signed_pre_key_public = signed_pre_key_pair.public_key.serialize();
let signed_pre_key_signature = identity_key
.private_key()
.calculate_signature(&signed_pre_key_public, &mut csprng)
.expect("can calculate signatures");
let signed_pq_pre_key_public = signed_pq_pre_key_pair.public_key.serialize();
let signed_pq_pre_key_signature = identity_key
.private_key()
.calculate_signature(&signed_pq_pre_key_public, &mut csprng)
.expect("can sign");
let device_id: u32 = csprng.random();
let pre_key_id: u32 = csprng.random();
let signed_pre_key_id: u32 = csprng.random();
let kyber_pre_key_id: u32 = csprng.random();
let pre_key_bundle = PreKeyBundle::new(
self.0
@@ -73,7 +82,12 @@ impl super::LibSignalProtocolStore for LibSignalProtocolCurrent {
.expect("can fetch identity key")
.identity_key(),
)
.expect("can create pre-key bundles");
.expect("can create pre-key bundles")
.with_kyber_pre_key(
kyber_pre_key_id.into(),
signed_pq_pre_key_pair.public_key.clone(),
signed_pq_pre_key_signature.to_vec(),
);
self.0
.save_pre_key(
@@ -100,6 +114,20 @@ impl super::LibSignalProtocolStore for LibSignalProtocolCurrent {
.expect("synchronous")
.expect("can save pre-keys");
self.0
.save_kyber_pre_key(
kyber_pre_key_id.into(),
&KyberPreKeyRecord::new(
kyber_pre_key_id.into(),
timestamp,
&signed_pq_pre_key_pair,
&signed_pq_pre_key_signature,
),
)
.now_or_never()
.expect("synchronous")
.expect("can save");
pre_key_bundle
}

View File

@@ -18,6 +18,9 @@ pub trait LibSignalProtocolStore {
mod current;
pub use current::LibSignalProtocolCurrent;
mod v70;
pub use v70::LibSignalProtocolV70;
mod v21;
pub use v21::LibSignalProtocolV21;

View File

@@ -0,0 +1,316 @@
//
// Copyright 2023 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//
use std::time::SystemTime;
use futures_util::FutureExt;
use libsignal_protocol_v70::*;
use rand_v8::{thread_rng, Rng};
fn address(id: &str) -> ProtocolAddress {
ProtocolAddress::new(id.into(), 1.into())
}
pub struct LibSignalProtocolV70(InMemSignalProtocolStore);
impl LibSignalProtocolV70 {
pub fn new() -> Self {
let mut csprng = thread_rng();
let identity_key = IdentityKeyPair::generate(&mut csprng);
// Valid registration IDs fit in 14 bits.
let registration_id: u8 = csprng.gen();
Self(
InMemSignalProtocolStore::new(identity_key, registration_id as u32)
.expect("can initialize"),
)
}
}
impl super::LibSignalProtocolStore for LibSignalProtocolV70 {
fn version(&self) -> &'static str {
"v70"
}
fn create_pre_key_bundle(&mut self) -> super::PreKeyBundle {
let mut csprng = thread_rng();
let pre_key_pair = KeyPair::generate(&mut csprng);
let signed_pre_key_pair = KeyPair::generate(&mut csprng);
let signed_pq_pre_key_pair = kem::KeyPair::generate(kem::KeyType::Kyber1024);
let identity_key = self
.0
.get_identity_key_pair()
.now_or_never()
.expect("synchronous")
.expect("can fetch identity key");
let signed_pre_key_public = signed_pre_key_pair.public_key.serialize();
let signed_pre_key_signature = identity_key
.private_key()
.calculate_signature(&signed_pre_key_public, &mut csprng)
.expect("can calculate signatures");
let signed_pq_pre_key_public = signed_pq_pre_key_pair.public_key.serialize();
let signed_pq_pre_key_signature = identity_key
.private_key()
.calculate_signature(&signed_pq_pre_key_public, &mut csprng)
.expect("can sign");
let device_id: u32 = csprng.gen();
let pre_key_id: u32 = csprng.gen();
let signed_pre_key_id: u32 = csprng.gen();
let kyber_pre_key_id: u32 = csprng.gen();
let pre_key_bundle = super::PreKeyBundle::new(
self.0
.get_local_registration_id()
.now_or_never()
.expect("synchronous")
.expect("can fetch registration id"),
device_id.into(),
Some((pre_key_id.into(), pre_key_pair.public_key.into_current())),
signed_pre_key_id.into(),
signed_pre_key_pair.public_key.into_current(),
signed_pre_key_signature.to_vec(),
self.0
.get_identity_key_pair()
.now_or_never()
.expect("synchronous")
.expect("can fetch identity key")
.identity_key()
.clone()
.into_current(),
)
.expect("can create pre-key bundles")
.with_kyber_pre_key(
kyber_pre_key_id.into(),
signed_pq_pre_key_pair.public_key.clone().into_current(),
signed_pq_pre_key_signature.to_vec(),
);
self.0
.save_pre_key(
pre_key_id.into(),
&PreKeyRecord::new(pre_key_id.into(), &pre_key_pair),
)
.now_or_never()
.expect("synchronous")
.expect("can save pre-keys");
let timestamp = csprng.gen();
self.0
.save_signed_pre_key(
signed_pre_key_id.into(),
&SignedPreKeyRecord::new(
signed_pre_key_id.into(),
timestamp,
&signed_pre_key_pair,
&signed_pre_key_signature,
),
)
.now_or_never()
.expect("synchronous")
.expect("can save pre-keys");
self.0
.save_kyber_pre_key(
kyber_pre_key_id.into(),
&KyberPreKeyRecord::new(
kyber_pre_key_id.into(),
timestamp,
&signed_pq_pre_key_pair,
&signed_pq_pre_key_signature,
),
)
.now_or_never()
.expect("synchronous")
.expect("can save");
pre_key_bundle
}
fn process_pre_key_bundle(&mut self, remote: &str, pre_key_bundle: super::PreKeyBundle) {
let pre_key_bundle = (|| {
let mut bundle = PreKeyBundle::new(
pre_key_bundle.registration_id()?,
ConvertVersion::from_current(pre_key_bundle.device_id()?),
pre_key_bundle
.pre_key_id()?
.map(ConvertVersion::from_current)
.zip(
pre_key_bundle
.pre_key_public()?
.map(ConvertVersion::from_current),
),
u32::from(pre_key_bundle.signed_pre_key_id()?).into(),
ConvertVersion::from_current(pre_key_bundle.signed_pre_key_public()?),
pre_key_bundle.signed_pre_key_signature()?.to_vec(),
ConvertVersion::from_current(pre_key_bundle.identity_key()?.to_owned()),
)
.expect("can produce bundle");
let kyber_keys = pre_key_bundle
.kyber_pre_key_id()?
.zip(pre_key_bundle.kyber_pre_key_public()?)
.zip(pre_key_bundle.kyber_pre_key_signature()?);
if let Some(((id, key), signature)) = kyber_keys {
bundle = bundle.with_kyber_pre_key(
ConvertVersion::from_current(id),
ConvertVersion::from_current(key.clone()),
signature.to_vec(),
);
}
Ok::<_, libsignal_protocol_current::SignalProtocolError>(bundle)
})()
.expect("can retrieve values");
process_prekey_bundle(
&address(remote),
&mut self.0.session_store,
&mut self.0.identity_store,
&pre_key_bundle,
SystemTime::now(),
&mut thread_rng(),
)
.now_or_never()
.expect("synchronous")
.expect("can process pre-key bundles")
}
fn encrypt(&mut self, remote: &str, msg: &[u8]) -> (Vec<u8>, super::CiphertextMessageType) {
let encrypted = message_encrypt(
msg,
&address(remote),
&mut self.0.session_store,
&mut self.0.identity_store,
SystemTime::now(),
)
.now_or_never()
.expect("synchronous")
.expect("can encrypt messages");
(
encrypted.serialize().to_vec(),
encrypted.message_type().into_current(),
)
}
fn decrypt(
&mut self,
remote: &str,
msg: &[u8],
msg_type: super::CiphertextMessageType,
) -> Vec<u8> {
match ConvertVersion::from_current(msg_type) {
CiphertextMessageType::Whisper => message_decrypt_signal(
&SignalMessage::try_from(msg).expect("valid"),
&address(remote),
&mut self.0.session_store,
&mut self.0.identity_store,
&mut thread_rng(),
)
.now_or_never()
.expect("synchronous")
.expect("can decrypt messages"),
CiphertextMessageType::PreKey => message_decrypt_prekey(
&PreKeySignalMessage::try_from(msg).expect("valid"),
&address(remote),
&mut self.0.session_store,
&mut self.0.identity_store,
&mut self.0.pre_key_store,
&mut self.0.signed_pre_key_store,
&mut self.0.kyber_pre_key_store,
&mut thread_rng(),
)
.now_or_never()
.expect("synchronous")
.expect("can decrypt messages"),
_ => panic!("unexpected 1:1 message type"),
}
}
}
trait ConvertVersion {
type Current;
fn into_current(self) -> Self::Current;
fn from_current(current: Self::Current) -> Self;
}
macro_rules! impl_convert_version {
($old:ty, $current:ty as serializable) => {
impl ConvertVersion for $old {
type Current = $current;
fn from_current(current: Self::Current) -> Self {
current
.serialize()
.as_ref()
.try_into()
.expect("compatible serialization")
}
fn into_current(self) -> Self::Current {
self.serialize()
.as_ref()
.try_into()
.expect("compatible serialization")
}
}
};
($old:ty, $current:ty as u32) => {
impl ConvertVersion for $old {
type Current = $current;
fn from_current(current: Self::Current) -> Self {
u32::from(current).into()
}
fn into_current(self) -> Self::Current {
u32::from(self).into()
}
}
};
}
impl_convert_version!(
PublicKey,
libsignal_protocol_current::PublicKey as serializable
);
impl_convert_version!(
IdentityKey,
libsignal_protocol_current::IdentityKey as serializable
);
impl_convert_version!(
kem::PublicKey,
libsignal_protocol_current::kem::PublicKey as serializable
);
impl_convert_version!(
kem::SecretKey,
libsignal_protocol_current::kem::SecretKey as serializable
);
impl_convert_version!(DeviceId, libsignal_protocol_current::DeviceId as u32);
impl_convert_version!(PreKeyId, libsignal_protocol_current::PreKeyId as u32);
impl_convert_version!(
KyberPreKeyId,
libsignal_protocol_current::KyberPreKeyId as u32
);
impl ConvertVersion for CiphertextMessageType {
type Current = libsignal_protocol_current::CiphertextMessageType;
fn into_current(self) -> Self::Current {
match self {
CiphertextMessageType::Whisper => Self::Current::Whisper,
CiphertextMessageType::PreKey => Self::Current::PreKey,
CiphertextMessageType::SenderKey => Self::Current::SenderKey,
CiphertextMessageType::Plaintext => Self::Current::Plaintext,
}
}
fn from_current(current: Self::Current) -> Self {
match current {
Self::Current::Whisper => Self::Whisper,
Self::Current::PreKey => Self::PreKey,
Self::Current::SenderKey => Self::SenderKey,
Self::Current::Plaintext => Self::Plaintext,
}
}
}