Argon2 Example (#282)
* 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]>
This commit is contained in:
@@ -68,6 +68,7 @@ proptest = "1"
|
||||
rand = "0.8"
|
||||
regex = "1"
|
||||
rustyline = "9"
|
||||
scrypt = "0.10"
|
||||
serde_json = "1"
|
||||
|
||||
[[bench]]
|
||||
@@ -77,3 +78,7 @@ name = "opaque"
|
||||
[package.metadata.docs.rs]
|
||||
features = ["argon2", "std", "x25519-u64"]
|
||||
targets = []
|
||||
|
||||
[[example]]
|
||||
name = "simple_login"
|
||||
required-features = ["argon2"]
|
||||
|
||||
+14
-12
@@ -45,10 +45,10 @@ 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;
|
||||
@@ -56,7 +56,7 @@ impl CipherSuite for Default {
|
||||
}
|
||||
|
||||
#[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;
|
||||
@@ -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
|
||||
@@ -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(®istration_request_bytes).unwrap(),
|
||||
&locker_id.to_be_bytes(),
|
||||
@@ -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 {
|
||||
@@ -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,
|
||||
@@ -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![];
|
||||
|
||||
+20
-15
@@ -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;
|
||||
@@ -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(®istration_request_bytes).unwrap(),
|
||||
username.as_bytes(),
|
||||
@@ -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,
|
||||
@@ -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",
|
||||
|
||||
+97
@@ -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`
|
||||
|
||||
Reference in New Issue
Block a user