Skip to content

Commit

Permalink
Argon2 Example (#282)
Browse files Browse the repository at this point in the history
* add argon2 example to simple_login.rs

* rename Default to DefaultCipherSuite in examples to avoid conflicts with core::default::Default

* put the custom KSF example in the documentation

* add links in documentation

Co-authored-by: daxpedda <[email protected]>

* remove no_run on argon2 doctest

* hide argon2 cfg attribute in docs

Co-authored-by: daxpedda <[email protected]>

Co-authored-by: daxpedda <[email protected]>
  • Loading branch information
zer0x64 and daxpedda authored Jul 25, 2022
1 parent 9ce5d8d commit 94fd359
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 27 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ proptest = "1"
rand = "0.8"
regex = "1"
rustyline = "9"
scrypt = "0.10"
serde_json = "1"

[[bench]]
Expand All @@ -77,3 +78,7 @@ name = "opaque"
[package.metadata.docs.rs]
features = ["argon2", "std", "x25519-u64"]
targets = []

[[example]]
name = "simple_login"
required-features = ["argon2"]
26 changes: 14 additions & 12 deletions examples/digital_locker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@ use rustyline::Editor;
// The ciphersuite trait allows to specify the underlying primitives that will
// be used in the OPAQUE protocol
#[allow(dead_code)]
struct Default;
struct DefaultCipherSuite;

#[cfg(feature = "ristretto255")]
impl CipherSuite for Default {
impl CipherSuite for DefaultCipherSuite {
type OprfCs = opaque_ke::Ristretto255;
type KeGroup = opaque_ke::Ristretto255;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;
}

#[cfg(not(feature = "ristretto255"))]
impl CipherSuite for Default {
impl CipherSuite for DefaultCipherSuite {
type OprfCs = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
Expand All @@ -65,7 +65,7 @@ impl CipherSuite for Default {

struct Locker {
contents: Vec<u8>,
password_file: GenericArray<u8, ServerRegistrationLen<Default>>,
password_file: GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>>,
}

// Given a key and plaintext, produce an AEAD ciphertext along with a nonce
Expand Down Expand Up @@ -96,18 +96,19 @@ fn decrypt(key: &[u8], ciphertext: &[u8]) -> Vec<u8> {
// Password-based registration and encryption of client secret message between a
// client and server
fn register_locker(
server_setup: &ServerSetup<Default>,
server_setup: &ServerSetup<DefaultCipherSuite>,
locker_id: usize,
password: String,
secret_message: String,
) -> Locker {
let mut client_rng = OsRng;
let client_registration_start_result =
ClientRegistration::<Default>::start(&mut client_rng, password.as_bytes()).unwrap();
ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes())
.unwrap();
let registration_request_bytes = client_registration_start_result.message.serialize();

// Client sends registration_request_bytes to server
let server_registration_start_result = ServerRegistration::<Default>::start(
let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start(
server_setup,
RegistrationRequest::deserialize(&registration_request_bytes).unwrap(),
&locker_id.to_be_bytes(),
Expand Down Expand Up @@ -137,7 +138,7 @@ fn register_locker(
// Client sends message_bytes to server

let password_file = ServerRegistration::finish(
RegistrationUpload::<Default>::deserialize(&message_bytes).unwrap(),
RegistrationUpload::<DefaultCipherSuite>::deserialize(&message_bytes).unwrap(),
);

Locker {
Expand All @@ -148,19 +149,20 @@ fn register_locker(

// Open the contents of a locker with a password between a client and server
fn open_locker(
server_setup: &ServerSetup<Default>,
server_setup: &ServerSetup<DefaultCipherSuite>,
locker_id: usize,
password: String,
locker: &Locker,
) -> Result<String, String> {
let mut client_rng = OsRng;
let client_login_start_result =
ClientLogin::<Default>::start(&mut client_rng, password.as_bytes()).unwrap();
ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap();
let credential_request_bytes = client_login_start_result.message.serialize();

// Client sends credential_request_bytes to server

let password_file = ServerRegistration::<Default>::deserialize(&locker.password_file).unwrap();
let password_file =
ServerRegistration::<DefaultCipherSuite>::deserialize(&locker.password_file).unwrap();
let mut server_rng = OsRng;
let server_login_start_result = ServerLogin::start(
&mut server_rng,
Expand Down Expand Up @@ -212,7 +214,7 @@ fn open_locker(

fn main() {
let mut rng = OsRng;
let server_setup = ServerSetup::<Default>::new(&mut rng);
let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);

let mut rl = Editor::<()>::new();
let mut registered_lockers: Vec<Locker> = vec![];
Expand Down
35 changes: 20 additions & 15 deletions examples/simple_login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
use std::collections::HashMap;
use std::process::exit;

use argon2::Argon2;
use generic_array::GenericArray;
use opaque_ke::ciphersuite::CipherSuite;
use opaque_ke::rand::rngs::OsRng;
Expand All @@ -39,38 +40,41 @@ use rustyline::Editor;
// The ciphersuite trait allows to specify the underlying primitives that will
// be used in the OPAQUE protocol
#[allow(dead_code)]
struct Default;
struct DefaultCipherSuite;

#[cfg(feature = "ristretto255")]
impl CipherSuite for Default {
impl CipherSuite for DefaultCipherSuite {
type OprfCs = opaque_ke::Ristretto255;
type KeGroup = opaque_ke::Ristretto255;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;

type Ksf = Argon2<'static>;
}

#[cfg(not(feature = "ristretto255"))]
impl CipherSuite for Default {
impl CipherSuite for DefaultCipherSuite {
type OprfCs = p256::NistP256;
type KeGroup = p256::NistP256;
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
type Ksf = opaque_ke::ksf::Identity;

type Ksf = Argon2<'static>;
}

// Password-based registration between a client and server
fn account_registration(
server_setup: &ServerSetup<Default>,
server_setup: &ServerSetup<DefaultCipherSuite>,
username: String,
password: String,
) -> GenericArray<u8, ServerRegistrationLen<Default>> {
) -> GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>> {
let mut client_rng = OsRng;
let client_registration_start_result =
ClientRegistration::<Default>::start(&mut client_rng, password.as_bytes()).unwrap();
ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes())
.unwrap();
let registration_request_bytes = client_registration_start_result.message.serialize();

// Client sends registration_request_bytes to server

let server_registration_start_result = ServerRegistration::<Default>::start(
let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start(
server_setup,
RegistrationRequest::deserialize(&registration_request_bytes).unwrap(),
username.as_bytes(),
Expand All @@ -94,26 +98,27 @@ fn account_registration(
// Client sends message_bytes to server

let password_file = ServerRegistration::finish(
RegistrationUpload::<Default>::deserialize(&message_bytes).unwrap(),
RegistrationUpload::<DefaultCipherSuite>::deserialize(&message_bytes).unwrap(),
);
password_file.serialize()
}

// Password-based login between a client and server
fn account_login(
server_setup: &ServerSetup<Default>,
server_setup: &ServerSetup<DefaultCipherSuite>,
username: String,
password: String,
password_file_bytes: &[u8],
) -> bool {
let mut client_rng = OsRng;
let client_login_start_result =
ClientLogin::<Default>::start(&mut client_rng, password.as_bytes()).unwrap();
ClientLogin::<DefaultCipherSuite>::start(&mut client_rng, password.as_bytes()).unwrap();
let credential_request_bytes = client_login_start_result.message.serialize();

// Client sends credential_request_bytes to server

let password_file = ServerRegistration::<Default>::deserialize(password_file_bytes).unwrap();
let password_file =
ServerRegistration::<DefaultCipherSuite>::deserialize(password_file_bytes).unwrap();
let mut server_rng = OsRng;
let server_login_start_result = ServerLogin::start(
&mut server_rng,
Expand Down Expand Up @@ -153,11 +158,11 @@ fn account_login(

fn main() {
let mut rng = OsRng;
let server_setup = ServerSetup::<Default>::new(&mut rng);
let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);

let mut rl = Editor::<()>::new();
let mut registered_users =
HashMap::<String, GenericArray<u8, ServerRegistrationLen<Default>>>::new();
HashMap::<String, GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>>>::new();
loop {
println!(
"\nCurrently registered usernames: {:?}\n",
Expand Down
97 changes: 97 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -986,6 +986,103 @@
//! let server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key(&mut OsRng, keypair);
//! ```
//!
//! ## Custom KSF and Parameters
//!
//! An application might want to use a custom KSF (Key Stretching Function)
//! that's not supported directly by this crate. The maintainer of the said KSF
//! or of the application itself can implement the [`Ksf`](ksf::Ksf) trait to
//! use it with `opaque-ke`. `scrypt` is used for this example, but any KSF
//! can be used.
//! ```
//! # use generic_array::GenericArray;
//! #[derive(Default)]
//! struct CustomKsf(scrypt::Params);
//!
//! // The Ksf trait must be implemented to be used in the ciphersuite.
//! impl opaque_ke::ksf::Ksf for CustomKsf {
//! fn hash<L: generic_array::ArrayLength<u8>>(
//! &self,
//! input: GenericArray<u8, L>,
//! ) -> Result<GenericArray<u8, L>, opaque_ke::errors::InternalError> {
//! let mut output = GenericArray::<u8, L>::default();
//! scrypt::scrypt(&input, &[], &self.0, &mut output)
//! .map_err(|_| opaque_ke::errors::InternalError::KsfError)?;
//!
//! Ok(output)
//! }
//! }
//! ```
//!
//! It is also possible to override the default derivation parameters that are
//! used by the KSF during registration and login. This can be especially
//! helpful if the `Ksf` trait is already implemented.
//! ```
//! # use opaque_ke::CipherSuite;
//! # use opaque_ke::ClientRegistration;
//! # use opaque_ke::ClientRegistrationFinishParameters;
//! # use opaque_ke::ServerSetup;
//! # use opaque_ke::errors::ProtocolError;
//! # use rand::rngs::OsRng;
//! # use rand::RngCore;
//! # use std::default::Default;
//! # #[cfg(feature = "argon2")]
//! # {
//! # struct DefaultCipherSuite;
//! # #[cfg(feature = "ristretto255")]
//! # impl CipherSuite for DefaultCipherSuite {
//! # type OprfCs = opaque_ke::Ristretto255;
//! # type KeGroup = opaque_ke::Ristretto255;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = argon2::Argon2<'static>;
//! # }
//! # #[cfg(not(feature = "ristretto255"))]
//! # impl CipherSuite for DefaultCipherSuite {
//! # type OprfCs = p256::NistP256;
//! # type KeGroup = p256::NistP256;
//! # type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
//! # type Ksf = argon2::Argon2<'static>;
//! # }
//! #
//! # let password = b"password";
//! # let mut rng = OsRng;
//! # let server_setup = ServerSetup::<DefaultCipherSuite>::new(&mut rng);
//! # let mut client_rng = OsRng;
//! # let client_registration_start_result =
//! # ClientRegistration::<DefaultCipherSuite>::start(&mut client_rng, password)?;
//! # use opaque_ke::ServerRegistration;
//! # let server_registration_start_result = ServerRegistration::<DefaultCipherSuite>::start(
//! # &server_setup,
//! # client_registration_start_result.message,
//! # b"[email protected]",
//! # )?;
//! #
//! // Create an Argon2 instance with the specified parameters
//! let argon2_params = argon2::Params::new(131072, 2, 4, None).unwrap();
//! let argon2_params = argon2::Argon2::new(
//! argon2::Algorithm::Argon2id,
//! argon2::Version::V0x13,
//! argon2_params,
//! );
//!
//! // Override the default parameters with the custom ones
//! let hash_params = ClientRegistrationFinishParameters {
//! ksf: Some(&argon2_params),
//! ..Default::default()
//! };
//!
//! let client_registration_finish_result = client_registration_start_result
//! .state
//! .finish(
//! &mut rng,
//! password,
//! server_registration_start_result.message,
//! hash_params,
//! )
//! .unwrap();
//! # }
//! # Ok::<(), ProtocolError>(())
//! ```
//!
//! # Features
//!
//! - The `argon2` feature, when enabled, introduces a dependency on `argon2`
Expand Down

0 comments on commit 94fd359

Please sign in to comment.