From 973fa40dd1cf391dd7809f5f0ae7432a5c330831 Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Tue, 8 Jun 2021 22:23:46 +0200 Subject: [PATCH] Add OPAQUE implementation --- Cargo.lock | 70 +++++++++++++++++++ app/Cargo.lock | 70 +++++++++++++++++++ app/Cargo.toml | 5 +- model/Cargo.lock | 110 ++++++++++++++++++++++++++++-- model/Cargo.toml | 16 +++++ model/src/lib.rs | 4 +- model/src/opaque.rs | 159 ++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 425 insertions(+), 9 deletions(-) create mode 100644 model/src/opaque.rs diff --git a/Cargo.lock b/Cargo.lock index 5fd6e7a..cde7a43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -685,6 +685,19 @@ dependencies = [ "subtle", ] +[[package]] +name = "curve25519-dalek" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3" +dependencies = [ + "byteorder", + "digest", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "derive_more" version = "0.99.14" @@ -718,6 +731,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" +[[package]] +name = "displaydoc" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc2ab4d5a16117f9029e9a6b5e4e79f4c67f6519bc134210d4d4a04ba31f41b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -927,6 +951,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "generic-bytes" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6638d839bbd1cea640d8c5348dd82e0d545dbd364f3c2a251646eaf2ef0773b" +dependencies = [ + "generic-array", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -945,8 +978,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -1010,6 +1045,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "hmac" version = "0.10.1" @@ -1241,8 +1286,14 @@ name = "lldap_model" version = "0.1.0" dependencies = [ "chrono", + "curve25519-dalek", + "getrandom 0.2.3", + "opaque-ke", + "rand 0.8.3", "serde", + "sha2", "sqlx", + "thiserror", ] [[package]] @@ -1548,6 +1599,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "opaque-ke" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c5e93081243e35cb270a2812883dcba34121c8d4054f6869149f2c3f7db10e3" +dependencies = [ + "curve25519-dalek", + "digest", + "displaydoc", + "generic-array", + "generic-bytes", + "hkdf", + "hmac", + "rand 0.8.3", + "subtle", + "thiserror", + "zeroize", +] + [[package]] name = "openssl" version = "0.10.34" diff --git a/app/Cargo.lock b/app/Cargo.lock index 2814914..97c1745 100644 --- a/app/Cargo.lock +++ b/app/Cargo.lock @@ -271,6 +271,19 @@ dependencies = [ "subtle", ] +[[package]] +name = "curve25519-dalek" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3" +dependencies = [ + "byteorder", + "digest", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "digest" version = "0.9.0" @@ -280,6 +293,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "displaydoc" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc2ab4d5a16117f9029e9a6b5e4e79f4c67f6519bc134210d4d4a04ba31f41b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -433,6 +457,15 @@ dependencies = [ "version_check", ] +[[package]] +name = "generic-bytes" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6638d839bbd1cea640d8c5348dd82e0d545dbd364f3c2a251646eaf2ef0773b" +dependencies = [ + "generic-array", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -451,8 +484,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", + "js-sys", "libc", "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -551,6 +586,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "hmac" version = "0.10.1" @@ -699,8 +744,14 @@ name = "lldap_model" version = "0.1.0" dependencies = [ "chrono", + "curve25519-dalek", + "getrandom 0.2.3", + "opaque-ke", + "rand 0.8.4", "serde", + "sha2", "sqlx", + "thiserror", ] [[package]] @@ -916,6 +967,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "opaque-ke" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c5e93081243e35cb270a2812883dcba34121c8d4054f6869149f2c3f7db10e3" +dependencies = [ + "curve25519-dalek", + "digest", + "displaydoc", + "generic-array", + "generic-bytes", + "hkdf", + "hmac", + "rand 0.8.4", + "subtle", + "thiserror", + "zeroize", +] + [[package]] name = "openssl" version = "0.10.35" diff --git a/app/Cargo.toml b/app/Cargo.toml index 0d7059a..b7608f2 100644 --- a/app/Cargo.toml +++ b/app/Cargo.toml @@ -9,7 +9,6 @@ anyhow = "1" chrono = "*" http = "0.2.4" jwt = "0.13" -lldap_model = { path = "../model" } serde = "1" serde_json = "1" wasm-bindgen = "0.2" @@ -25,5 +24,9 @@ features = [ "console", ] +[dependencies.lldap_model] +path = "../model" +features = [ "opaque_client" ] + [lib] crate-type = ["cdylib"] diff --git a/model/Cargo.lock b/model/Cargo.lock index d267a6e..756c7a6 100644 --- a/model/Cargo.lock +++ b/model/Cargo.lock @@ -24,7 +24,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f200cbb1e856866d9eade941cf3aa0c5d7dd36f74311c4273b494f4ef036957" dependencies = [ - "getrandom", + "getrandom 0.2.2", "once_cell", "version_check", ] @@ -223,6 +223,19 @@ dependencies = [ "subtle", ] +[[package]] +name = "curve25519-dalek" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "639891fde0dbea823fc3d798a0fdf9d2f9440a42d64a78ab3488b0ca025117b3" +dependencies = [ + "byteorder", + "digest", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "digest" version = "0.9.0" @@ -252,6 +265,17 @@ dependencies = [ "winapi", ] +[[package]] +name = "displaydoc" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc2ab4d5a16117f9029e9a6b5e4e79f4c67f6519bc134210d4d4a04ba31f41b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "dotenv" version = "0.15.0" @@ -399,6 +423,26 @@ dependencies = [ "version_check", ] +[[package]] +name = "generic-bytes" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6638d839bbd1cea640d8c5348dd82e0d545dbd364f3c2a251646eaf2ef0773b" +dependencies = [ + "generic-array", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.2" @@ -406,8 +450,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -452,6 +498,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hkdf" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" +dependencies = [ + "digest", + "hmac", +] + [[package]] name = "hmac" version = "0.10.1" @@ -547,8 +603,14 @@ name = "lldap_model" version = "0.1.0" dependencies = [ "chrono", + "curve25519-dalek", + "getrandom 0.2.2", + "opaque-ke", + "rand", "serde", + "sha2", "sqlx", + "thiserror", ] [[package]] @@ -753,6 +815,25 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "opaque-ke" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c5e93081243e35cb270a2812883dcba34121c8d4054f6869149f2c3f7db10e3" +dependencies = [ + "curve25519-dalek", + "digest", + "displaydoc", + "generic-array", + "generic-bytes", + "hkdf", + "hmac", + "rand", + "subtle", + "thiserror", + "zeroize", +] + [[package]] name = "openssl" version = "0.10.34" @@ -896,7 +977,7 @@ checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.2", "rand_hc", ] @@ -907,7 +988,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.2", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -916,7 +1006,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom", + "getrandom 0.2.2", ] [[package]] @@ -925,7 +1015,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core", + "rand_core 0.6.2", ] [[package]] @@ -943,7 +1033,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom", + "getrandom 0.2.2", "redox_syscall", ] @@ -1458,6 +1548,12 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/model/Cargo.toml b/model/Cargo.toml index e172cc3..dfb936a 100644 --- a/model/Cargo.toml +++ b/model/Cargo.toml @@ -5,10 +5,18 @@ authors = ["Valentin Tolmer ", "Steve Barrau = std::result::Result; + +/// The ciphersuite trait allows to specify the underlying primitives +/// that will be used in the OPAQUE protocol +#[allow(dead_code)] +pub struct DefaultSuite; +impl CipherSuite for DefaultSuite { + type Group = curve25519_dalek::ristretto::RistrettoPoint; + type KeyExchange = opaque_ke::key_exchange::tripledh::TripleDH; + type Hash = sha2::Sha512; + type SlowHash = opaque_ke::slow_hash::NoOpHash; +} + +/// Client-side code for OPAQUE protocol handling, to register a new user and login. All methods' +/// results must be sent to the server using the serialized `.message`. Incoming messages can be +/// deserialized using the type's `deserialize` method. +#[cfg(feature = "opaque_client")] +pub mod client { + use super::*; + /// Methods to register a new user, from the client side. + pub mod registration { + use super::*; + use opaque_ke::{ + ClientRegistration, ClientRegistrationFinishParameters, ClientRegistrationFinishResult, + ClientRegistrationStartResult, RegistrationResponse, + }; + /// Initiate the registration negotiation. + pub fn start_registration( + password: &str, + rng: &mut R, + ) -> AuthenticationResult> { + Ok(ClientRegistration::::start( + rng, + password.as_bytes(), + )?) + } + + /// Finalize the registration negotiation. + pub fn finish_registration( + registration_start: ClientRegistration, + registration_response: RegistrationResponse, + rng: &mut R, + ) -> AuthenticationResult> { + Ok(registration_start.finish( + rng, + registration_response, + ClientRegistrationFinishParameters::default(), + )?) + } + } + + /// Methods to login, from the client side. + pub mod login { + use super::*; + use opaque_ke::{ + ClientLogin, ClientLoginFinishParameters, ClientLoginFinishResult, + ClientLoginStartParameters, ClientLoginStartResult, CredentialResponse, + }; + + /// Initiate the login negotiation. + pub fn start_login( + password: &str, + rng: &mut R, + ) -> AuthenticationResult> { + Ok(ClientLogin::::start( + rng, + password.as_bytes(), + ClientLoginStartParameters::default(), + )?) + } + + /// Finalize the client login negotiation. + pub fn finish_login( + login_start: ClientLogin, + login_response: CredentialResponse, + ) -> AuthenticationResult> { + Ok(login_start.finish(login_response, ClientLoginFinishParameters::default())?) + } + } +} + +/// Server-side code for OPAQUE protocol handling, to register a new user and login. The +/// intermediate results must be sent to the client using the serialized `.message`. +#[cfg(feature = "opaque_server")] +pub mod server { + use super::*; + use opaque_ke::{keypair::Key, ServerRegistration}; + /// Methods to register a new user, from the server side. + pub mod registration { + use super::*; + use opaque_ke::{RegistrationRequest, RegistrationUpload, ServerRegistrationStartResult}; + /// Start a registration process, from a request sent by the client. + /// + /// The result must be kept for the next step. + pub fn start_registration( + rng: &mut R, + registration_request: RegistrationRequest, + server_public_key: &Key, + ) -> AuthenticationResult> { + Ok(ServerRegistration::::start( + rng, + registration_request, + server_public_key, + )?) + } + + /// Finish to register a new user, and get the data to store in the database. + pub fn get_password_file( + registration_start: ServerRegistration, + registration_upload: RegistrationUpload, + ) -> AuthenticationResult> { + Ok(registration_start.finish(registration_upload)?) + } + } + + /// Methods to handle user login, from the server-side. + pub mod login { + use super::*; + use opaque_ke::{ + CredentialFinalization, CredentialRequest, ServerLogin, ServerLoginFinishResult, + ServerLoginStartParameters, ServerLoginStartResult, + }; + + /// Start a login process, from a request sent by the client. + /// + /// The result must be kept for the next step. + pub fn start_login( + rng: &mut R, + password_file: ServerRegistration, + server_private_key: &Key, + credential_request: CredentialRequest, + ) -> AuthenticationResult> { + Ok(ServerLogin::start( + rng, + password_file, + server_private_key, + credential_request, + ServerLoginStartParameters::default(), + )?) + } + + /// Finish to authorize a new user, and get the session key to decrypt associated data. + pub fn finalize_login( + login_start: ServerLogin, + credential_finalization: CredentialFinalization, + ) -> AuthenticationResult { + Ok(login_start.finish(credential_finalization)?) + } + } +}