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"
|
rand = "0.8"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
rustyline = "9"
|
rustyline = "9"
|
||||||
|
scrypt = "0.10"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
@@ -77,3 +78,7 @@ name = "opaque"
|
|||||||
[package.metadata.docs.rs]
|
[package.metadata.docs.rs]
|
||||||
features = ["argon2", "std", "x25519-u64"]
|
features = ["argon2", "std", "x25519-u64"]
|
||||||
targets = []
|
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
|
// The ciphersuite trait allows to specify the underlying primitives that will
|
||||||
// be used in the OPAQUE protocol
|
// be used in the OPAQUE protocol
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct Default;
|
struct DefaultCipherSuite;
|
||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for DefaultCipherSuite {
|
||||||
type OprfCs = opaque_ke::Ristretto255;
|
type OprfCs = opaque_ke::Ristretto255;
|
||||||
type KeGroup = opaque_ke::Ristretto255;
|
type KeGroup = opaque_ke::Ristretto255;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
|
||||||
@@ -56,7 +56,7 @@ impl CipherSuite for Default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ristretto255"))]
|
#[cfg(not(feature = "ristretto255"))]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for DefaultCipherSuite {
|
||||||
type OprfCs = p256::NistP256;
|
type OprfCs = p256::NistP256;
|
||||||
type KeGroup = p256::NistP256;
|
type KeGroup = p256::NistP256;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
|
||||||
@@ -65,7 +65,7 @@ impl CipherSuite for Default {
|
|||||||
|
|
||||||
struct Locker {
|
struct Locker {
|
||||||
contents: Vec<u8>,
|
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
|
// 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
|
// Password-based registration and encryption of client secret message between a
|
||||||
// client and server
|
// client and server
|
||||||
fn register_locker(
|
fn register_locker(
|
||||||
server_setup: &ServerSetup<Default>,
|
server_setup: &ServerSetup<DefaultCipherSuite>,
|
||||||
locker_id: usize,
|
locker_id: usize,
|
||||||
password: String,
|
password: String,
|
||||||
secret_message: String,
|
secret_message: String,
|
||||||
) -> Locker {
|
) -> Locker {
|
||||||
let mut client_rng = OsRng;
|
let mut client_rng = OsRng;
|
||||||
let client_registration_start_result =
|
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();
|
let registration_request_bytes = client_registration_start_result.message.serialize();
|
||||||
|
|
||||||
// Client sends registration_request_bytes to server
|
// 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,
|
server_setup,
|
||||||
RegistrationRequest::deserialize(®istration_request_bytes).unwrap(),
|
RegistrationRequest::deserialize(®istration_request_bytes).unwrap(),
|
||||||
&locker_id.to_be_bytes(),
|
&locker_id.to_be_bytes(),
|
||||||
@@ -137,7 +138,7 @@ fn register_locker(
|
|||||||
// Client sends message_bytes to server
|
// Client sends message_bytes to server
|
||||||
|
|
||||||
let password_file = ServerRegistration::finish(
|
let password_file = ServerRegistration::finish(
|
||||||
RegistrationUpload::<Default>::deserialize(&message_bytes).unwrap(),
|
RegistrationUpload::<DefaultCipherSuite>::deserialize(&message_bytes).unwrap(),
|
||||||
);
|
);
|
||||||
|
|
||||||
Locker {
|
Locker {
|
||||||
@@ -148,19 +149,20 @@ fn register_locker(
|
|||||||
|
|
||||||
// Open the contents of a locker with a password between a client and server
|
// Open the contents of a locker with a password between a client and server
|
||||||
fn open_locker(
|
fn open_locker(
|
||||||
server_setup: &ServerSetup<Default>,
|
server_setup: &ServerSetup<DefaultCipherSuite>,
|
||||||
locker_id: usize,
|
locker_id: usize,
|
||||||
password: String,
|
password: String,
|
||||||
locker: &Locker,
|
locker: &Locker,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
let mut client_rng = OsRng;
|
let mut client_rng = OsRng;
|
||||||
let client_login_start_result =
|
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();
|
let credential_request_bytes = client_login_start_result.message.serialize();
|
||||||
|
|
||||||
// Client sends credential_request_bytes to server
|
// 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 mut server_rng = OsRng;
|
||||||
let server_login_start_result = ServerLogin::start(
|
let server_login_start_result = ServerLogin::start(
|
||||||
&mut server_rng,
|
&mut server_rng,
|
||||||
@@ -212,7 +214,7 @@ fn open_locker(
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rng = OsRng;
|
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 rl = Editor::<()>::new();
|
||||||
let mut registered_lockers: Vec<Locker> = vec![];
|
let mut registered_lockers: Vec<Locker> = vec![];
|
||||||
|
|||||||
+20
-15
@@ -24,6 +24,7 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
|
use argon2::Argon2;
|
||||||
use generic_array::GenericArray;
|
use generic_array::GenericArray;
|
||||||
use opaque_ke::ciphersuite::CipherSuite;
|
use opaque_ke::ciphersuite::CipherSuite;
|
||||||
use opaque_ke::rand::rngs::OsRng;
|
use opaque_ke::rand::rngs::OsRng;
|
||||||
@@ -39,38 +40,41 @@ use rustyline::Editor;
|
|||||||
// The ciphersuite trait allows to specify the underlying primitives that will
|
// The ciphersuite trait allows to specify the underlying primitives that will
|
||||||
// be used in the OPAQUE protocol
|
// be used in the OPAQUE protocol
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct Default;
|
struct DefaultCipherSuite;
|
||||||
|
|
||||||
#[cfg(feature = "ristretto255")]
|
#[cfg(feature = "ristretto255")]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for DefaultCipherSuite {
|
||||||
type OprfCs = opaque_ke::Ristretto255;
|
type OprfCs = opaque_ke::Ristretto255;
|
||||||
type KeGroup = opaque_ke::Ristretto255;
|
type KeGroup = opaque_ke::Ristretto255;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
|
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
|
||||||
type Ksf = opaque_ke::ksf::Identity;
|
|
||||||
|
type Ksf = Argon2<'static>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "ristretto255"))]
|
#[cfg(not(feature = "ristretto255"))]
|
||||||
impl CipherSuite for Default {
|
impl CipherSuite for DefaultCipherSuite {
|
||||||
type OprfCs = p256::NistP256;
|
type OprfCs = p256::NistP256;
|
||||||
type KeGroup = p256::NistP256;
|
type KeGroup = p256::NistP256;
|
||||||
type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDh;
|
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
|
// Password-based registration between a client and server
|
||||||
fn account_registration(
|
fn account_registration(
|
||||||
server_setup: &ServerSetup<Default>,
|
server_setup: &ServerSetup<DefaultCipherSuite>,
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
) -> GenericArray<u8, ServerRegistrationLen<Default>> {
|
) -> GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>> {
|
||||||
let mut client_rng = OsRng;
|
let mut client_rng = OsRng;
|
||||||
let client_registration_start_result =
|
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();
|
let registration_request_bytes = client_registration_start_result.message.serialize();
|
||||||
|
|
||||||
// Client sends registration_request_bytes to server
|
// 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,
|
server_setup,
|
||||||
RegistrationRequest::deserialize(®istration_request_bytes).unwrap(),
|
RegistrationRequest::deserialize(®istration_request_bytes).unwrap(),
|
||||||
username.as_bytes(),
|
username.as_bytes(),
|
||||||
@@ -94,26 +98,27 @@ fn account_registration(
|
|||||||
// Client sends message_bytes to server
|
// Client sends message_bytes to server
|
||||||
|
|
||||||
let password_file = ServerRegistration::finish(
|
let password_file = ServerRegistration::finish(
|
||||||
RegistrationUpload::<Default>::deserialize(&message_bytes).unwrap(),
|
RegistrationUpload::<DefaultCipherSuite>::deserialize(&message_bytes).unwrap(),
|
||||||
);
|
);
|
||||||
password_file.serialize()
|
password_file.serialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Password-based login between a client and server
|
// Password-based login between a client and server
|
||||||
fn account_login(
|
fn account_login(
|
||||||
server_setup: &ServerSetup<Default>,
|
server_setup: &ServerSetup<DefaultCipherSuite>,
|
||||||
username: String,
|
username: String,
|
||||||
password: String,
|
password: String,
|
||||||
password_file_bytes: &[u8],
|
password_file_bytes: &[u8],
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let mut client_rng = OsRng;
|
let mut client_rng = OsRng;
|
||||||
let client_login_start_result =
|
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();
|
let credential_request_bytes = client_login_start_result.message.serialize();
|
||||||
|
|
||||||
// Client sends credential_request_bytes to server
|
// 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 mut server_rng = OsRng;
|
||||||
let server_login_start_result = ServerLogin::start(
|
let server_login_start_result = ServerLogin::start(
|
||||||
&mut server_rng,
|
&mut server_rng,
|
||||||
@@ -153,11 +158,11 @@ fn account_login(
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut rng = OsRng;
|
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 rl = Editor::<()>::new();
|
||||||
let mut registered_users =
|
let mut registered_users =
|
||||||
HashMap::<String, GenericArray<u8, ServerRegistrationLen<Default>>>::new();
|
HashMap::<String, GenericArray<u8, ServerRegistrationLen<DefaultCipherSuite>>>::new();
|
||||||
loop {
|
loop {
|
||||||
println!(
|
println!(
|
||||||
"\nCurrently registered usernames: {:?}\n",
|
"\nCurrently registered usernames: {:?}\n",
|
||||||
|
|||||||
+97
@@ -986,6 +986,103 @@
|
|||||||
//! let server_setup = ServerSetup::<Default, YourRemoteKey>::new_with_key(&mut OsRng, keypair);
|
//! 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
|
//! # Features
|
||||||
//!
|
//!
|
||||||
//! - The `argon2` feature, when enabled, introduces a dependency on `argon2`
|
//! - The `argon2` feature, when enabled, introduces a dependency on `argon2`
|
||||||
|
|||||||
Reference in New Issue
Block a user