From 33464543c10877a9a0c4ce60a73cf8c02c497900 Mon Sep 17 00:00:00 2001 From: daxpedda Date: Tue, 9 Sep 2025 09:25:04 +0200 Subject: [PATCH] Add migration guide to changelog (#393) --- CHANGELOG.md | 31 +++++++++++++- Cargo.toml | 3 +- tests/migration.rs | 104 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 tests/migration.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a68099..5faf1a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,10 +10,39 @@ * Modified the dummy registration file to only contain the public key instead of the keypair * **Breaking: existing `ServerSetup`s need to be updated** + ```rust + // Given `old` is a `ServerSetup` from `opaque-ke` v3. + let old_serialized = old.serialize(); + + type OldSeedLen = <<::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize; + type OldSkLen = <::KeGroup as opaque_ke_3::key_exchange::group::KeGroup>::SkLen; + + let (old_serialied_rest, old_fake_keypair_serialized): ( + GenericArray>, + _, + ) = old_serialized.split(); + + let old_fake_keypair = + KeyPair::<::KeGroup>::from_private_key_slice( + &old_fake_keypair_serialized, + ) + .unwrap(); + let old_fake_pk_serialized = old_fake_keypair.public().serialize(); + + let new_serialized = old_serialied_rest.concat(old_fake_pk_serialized); + // Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to `OldCipherSuite`. + ServerSetup::::deserialize(&new_serialized).unwrap() + ``` * Added remote OPRF seed support * Replace remote private key trait with a state machine, facilitating async support. * Serde de/serialization formats have been simplified - * **Breaking: existing `RegistrationUpload`s may need to be updated** + * **Breaking: existing `ServerRegistration`s may need to be updated** + ```rust + // Given `old` is a `ServerRegistration` from `opaque-ke` v3. + let old_serialized = old.serialize(); + // Given `NewCipherSuite` is a `CipherSuite` implementation equivalent to the old cipher suite. + ServerRegistration::::deserialize(&old_serialized).unwrap() + ``` ## 3.0.0 (October 10, 2024) diff --git a/Cargo.toml b/Cargo.toml index e8eb421..9d414c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ name = "opaque-ke" readme = "README.md" repository = "https://github.com/facebook/opaque-ke" rust-version = "1.85" -version = "3.0.0" +version = "4.0.0-pre.0" [features] argon2 = ["dep:argon2"] @@ -73,6 +73,7 @@ criterion = "0.5" cryptoki = "0.9" elliptic-curve = { version = "0.13", features = ["alloc", "pkcs8"] } hex = "0.4" +opaque-ke-3 = { package = "opaque-ke", version = "=3.0.0" } p256 = { version = "0.13", default-features = false, features = [ "ecdsa", "hash2curve", diff --git a/tests/migration.rs b/tests/migration.rs new file mode 100644 index 0000000..58dfc21 --- /dev/null +++ b/tests/migration.rs @@ -0,0 +1,104 @@ +use digest::OutputSizeUser; +use generic_array::GenericArray; +use generic_array::sequence::{Concat, Split}; +use generic_array::typenum::Sum; +use opaque_ke::ksf::Identity; +use opaque_ke::{CipherSuite, ClientLogin, ServerLogin, ServerRegistration, ServerSetup, TripleDh}; +use opaque_ke_3::key_exchange::group::KeGroup as v3KeGroup; +use opaque_ke_3::key_exchange::tripledh::TripleDh as v3TripleDh; +use opaque_ke_3::keypair::KeyPair; +use opaque_ke_3::ksf::Identity as v3Identity; +use opaque_ke_3::{ + CipherSuite as v3CipherSuite, ClientRegistration as v3ClientRegistration, + ServerRegistration as v3ServerRegistration, ServerSetup as v3ServerSetup, +}; +use p256::NistP256; +use rand::rngs::OsRng; +use sha2::Sha256; + +const PASSWORD: &[u8] = b"test password"; +const CLIENT_IDENTIFIER: &[u8] = b"test client identifier"; + +struct OldCipherSuite; + +impl v3CipherSuite for OldCipherSuite { + type OprfCs = NistP256; + type KeGroup = NistP256; + type KeyExchange = v3TripleDh; + type Ksf = v3Identity; +} + +struct NewCipherSuite; + +impl CipherSuite for NewCipherSuite { + type OprfCs = NistP256; + type KeyExchange = TripleDh; + type Ksf = Identity; +} + +#[test] +fn registration_upload() { + // V3 registration. + let result = v3ClientRegistration::::start(&mut OsRng, PASSWORD).unwrap(); + let client = result.state; + + let old_server_setup = v3ServerSetup::::new(&mut OsRng); + let response = + v3ServerRegistration::start(&old_server_setup, result.message, CLIENT_IDENTIFIER) + .unwrap() + .message; + + let upload = client + .finish(&mut OsRng, PASSWORD, response, Default::default()) + .unwrap() + .message; + + let old_registration = v3ServerRegistration::finish(upload); + + // `ServerSetup` migration. + let server_setup = { + let old_serialized = old_server_setup.serialize(); + + type OldSeedLen = <<::OprfCs as voprf::CipherSuite>::Hash as OutputSizeUser>::OutputSize; + type OldSkLen = <::KeGroup as v3KeGroup>::SkLen; + let (old_serialied_rest, old_fake_keypair_serialized): ( + GenericArray>, + _, + ) = old_serialized.split(); + let old_fake_keypair = + KeyPair::<::KeGroup>::from_private_key_slice( + &old_fake_keypair_serialized, + ) + .unwrap(); + let old_fake_pk_serialized = old_fake_keypair.public().serialize(); + + let new_serialized = old_serialied_rest.concat(old_fake_pk_serialized); + ServerSetup::::deserialize(&new_serialized).unwrap() + }; + + // `ServerRegistration` migration. + let old_registration_serialized = old_registration.serialize(); + let registration = + ServerRegistration::::deserialize(&old_registration_serialized).unwrap(); + + // Check if new `ServerRegistration` still works. + let result = ClientLogin::::start(&mut OsRng, PASSWORD).unwrap(); + let client = result.state; + + let result = ServerLogin::start( + &mut OsRng, + &server_setup, + Some(registration), + result.message, + CLIENT_IDENTIFIER, + Default::default(), + ) + .unwrap(); + let server = result.state; + + let result = client + .finish(&mut OsRng, PASSWORD, result.message, Default::default()) + .unwrap(); + + server.finish(result.message, Default::default()).unwrap(); +}