diff --git a/.gitignore b/.gitignore index ef5dddd..c204227 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ /node_modules /.idea .env +.DS_Store diff --git a/Cargo.lock b/Cargo.lock index 8293d41..8a7e5bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -353,6 +353,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.7" @@ -641,6 +647,8 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" dependencies = [ + "jobserver", + "libc", "shlex", ] @@ -795,6 +803,18 @@ version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -937,12 +957,47 @@ version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "either" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "embedded-io" version = "0.4.0" @@ -1015,6 +1070,16 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1165,6 +1230,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "h2" version = "0.3.26" @@ -1733,6 +1809,15 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.72" @@ -1763,6 +1848,54 @@ version = "0.2.165" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e" +[[package]] +name = "libcrux-ecdh" +version = "0.0.2-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706661e22936e496552fb372a97be642707653c5450ee3227a34008675578f4c" +dependencies = [ + "libcrux-hacl", + "rand", +] + +[[package]] +name = "libcrux-hacl" +version = "0.0.2-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc642d4586eca52dd453de27f13c241ea70633f1ba8115599ed81a2464516e2d" +dependencies = [ + "cc", + "libcrux-platform", +] + +[[package]] +name = "libcrux-hkdf" +version = "0.0.2-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f50ac3c91f5e1d299875b3d276a8b74ed35e8e310a567b3c6602de5c6f3ec2" +dependencies = [ + "libcrux-hacl", +] + +[[package]] +name = "libcrux-hmac" +version = "0.0.2-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "783d10e569d462ee05ec682c07fe2d78c1c454fd6b31c42f10fbac8ba944f292" +dependencies = [ + "libcrux-hacl", + "libcrux-hkdf", +] + +[[package]] +name = "libcrux-platform" +version = "0.0.2-alpha.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f024adfcf750f591404e7f83034d822c3f88a220cf59c5d7a1f3edfaf3f6d2" +dependencies = [ + "libc", +] + [[package]] name = "libloading" version = "0.8.5" @@ -2145,6 +2278,18 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -2350,6 +2495,15 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2613,6 +2767,16 @@ dependencies = [ "windows-registry", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.8" @@ -2838,6 +3002,20 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "2.11.1" @@ -3112,9 +3290,17 @@ dependencies = [ "bitwarden", "cookie", "dotenvy", + "getrandom", + "libcrux-ecdh", + "libcrux-hkdf", + "libcrux-hmac", "libsql", "nanoid", + "p256", "postcard", + "rand", + "rand_chacha", + "ring", "serde", "thiserror 2.0.3", "time", @@ -3796,6 +3982,22 @@ version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +[[package]] +name = "web-shove" +version = "0.1.0" +dependencies = [ + "base64 0.22.1", + "getrandom", + "libcrux-ecdh", + "libcrux-hkdf", + "libcrux-hmac", + "p256", + "rand", + "rand_chacha", + "ring", + "thiserror 2.0.3", +] + [[package]] name = "web-sys" version = "0.3.72" diff --git a/Cargo.toml b/Cargo.toml index ba870e6..9e3e828 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,25 +1,2 @@ -[package] -name = "supernova" -version = "0.1.0" -edition = "2021" - -[dependencies] -askama = "0.12.1" -askama_axum = "0.4.0" -axum = { version = "0.7.9", features = [] } -axum-extra = { version = "0.9.6", features = ["cookie", "cookie-private"] } -base64 = "0.22.1" -bitwarden = "1.0.0" -cookie = "0.18.1" -dotenvy = "0.15.7" -libsql = "0.6.0" -nanoid = "0.4.0" -postcard = { version = "1.1.0", features = ["alloc"], default-features = false } -serde = { version = "1.0.215", features = ["derive"] } -thiserror = "2.0.3" -time = { version = "0.3.36", features = ["serde"] } -tokio = { version = "1.41.1", features = ["full"] } -tower-http = { version = "0.6.2", features = ["fs"] } -tracing = "0.1.40" -tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } -uuid = "1.11.0" +[workspace] +members = ["supernova", "web-shove"] diff --git a/supernova/.gitignore b/supernova/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/supernova/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/supernova/Cargo.toml b/supernova/Cargo.toml new file mode 100644 index 0000000..de22d59 --- /dev/null +++ b/supernova/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "supernova" +version = "0.1.0" +edition = "2021" + +[dependencies] +askama = "0.12.1" +askama_axum = "0.4.0" +axum = { version = "0.7.9", features = [] } +axum-extra = { version = "0.9.6", features = ["cookie", "cookie-private"] } +base64 = "0.22.1" +bitwarden = "1.0.0" +cookie = "0.18.1" +dotenvy = "0.15.7" +getrandom = { version = "0.2.15", features = ["custom"] } +libcrux-ecdh = "0.0.2-alpha.3" +libcrux-hkdf = "0.0.2-alpha.3" +libcrux-hmac = "0.0.2-alpha.3" +libsql = "0.6.0" +nanoid = "0.4.0" +p256 = { version = "0.13.2", features = ["ecdh"] } +postcard = { version = "1.1.0", features = ["alloc"], default-features = false } +rand = "0.8.5" +rand_chacha = "0.3.1" +ring = { version = "0.17.8", features = ["less-safe-getrandom-custom-or-rdrand"] } +serde = { version = "1.0.215", features = ["derive"] } +thiserror = "2.0.3" +time = { version = "0.3.36", features = ["serde"] } +tokio = { version = "1.41.1", features = ["full"] } +tower-http = { version = "0.6.2", features = ["fs"] } +tracing = "0.1.40" +tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +uuid = "1.11.0" diff --git a/app.css b/supernova/app.css similarity index 100% rename from app.css rename to supernova/app.css diff --git a/package.json b/supernova/package.json similarity index 100% rename from package.json rename to supernova/package.json diff --git a/pnpm-lock.yaml b/supernova/pnpm-lock.yaml similarity index 100% rename from pnpm-lock.yaml rename to supernova/pnpm-lock.yaml diff --git a/public/.gitignore b/supernova/public/.gitignore similarity index 100% rename from public/.gitignore rename to supernova/public/.gitignore diff --git a/src/auth/authenticated_user.rs b/supernova/src/auth/authenticated_user.rs similarity index 100% rename from src/auth/authenticated_user.rs rename to supernova/src/auth/authenticated_user.rs diff --git a/src/auth/cookie.rs b/supernova/src/auth/cookie.rs similarity index 100% rename from src/auth/cookie.rs rename to supernova/src/auth/cookie.rs diff --git a/src/auth/mod.rs b/supernova/src/auth/mod.rs similarity index 100% rename from src/auth/mod.rs rename to supernova/src/auth/mod.rs diff --git a/supernova/src/encrypted_content_encoding.rs b/supernova/src/encrypted_content_encoding.rs new file mode 100644 index 0000000..23adf65 --- /dev/null +++ b/supernova/src/encrypted_content_encoding.rs @@ -0,0 +1,146 @@ +use std::{array::TryFromSliceError, rc::Rc}; + +use rand::prelude::*; +use ring::{ + agreement::{self, EphemeralPrivateKey}, + rand::SecureRandom, +}; +use thiserror::Error; + +const KEY_INFO: &[u8] = b"WebPush: info\0"; +const NONCE_INFO: &[u8] = b"Content-Encoding: nonce\0"; + +//TODO use ring when we know it works and figure out deterministic key generation for testing as it only generates ephemeral keys +fn create_pseudo_random_key<'a>( + application_server_private_key: &[u8], + user_agent_public_key: &[u8], + authentication_secret: &[u8], +) -> Rc<[u8]> { + // let mut random = rand_chacha::ChaCha8Rng::seed_from_u64(69); + // let random = ring::rand::SystemRandom::new(); + // EphemeralPrivateKey::generate(&agreement::ECDH_P256, &random); + // let number: u32 = random.gen(); + // let mut buffer = [0u8; 4]; + // let number = random.fill(&mut buffer); + // println!("My data is {:?}", buffer); + // println!("My number is {number}"); + // EphemeralPrivateKey::generate(alg, rng) + let application_server_key = + libcrux_ecdh::P256PrivateKey::try_from(application_server_private_key).unwrap(); + + // The first byte is a special byte that is used to identify the key type + let user_agent_key = + libcrux_ecdh::P256PublicKey::try_from(&user_agent_public_key[1..]).unwrap(); + + let shared_key = libcrux_ecdh::p256_derive(&user_agent_key, &application_server_key).unwrap(); + + // HKDF expand? + // libcrux_hkdf::expand(libcrux_hkdf::Algorithm::Sha256, prk, info, okm_len) + libcrux_hmac::hmac( + libcrux_hmac::Algorithm::Sha256, + application_server_private_key, + authentication_secret, + None, + ) + .into() + // libcrux_hkdf::hkdf( + // libcrux_hkdf::Algorithm::Sha256, + // authentication_secret, + // application_server_private_key, + // info, + // okm_len, + // ); +} + +fn create_shared_ecdh_secret( + application_server_private_key: &[u8], + user_agent_public_key: &[u8], +) -> [u8; 32] { + let application_server_private_key: &[u8; 32] = + application_server_private_key.try_into().unwrap(); + + let user_agent_public_key: &[u8; 64] = &user_agent_public_key[1..].try_into().unwrap(); + + let application_server_private_key = + libcrux_ecdh::P256PrivateKey::from(application_server_private_key); + + let user_agent_public_key = libcrux_ecdh::P256PublicKey::from(user_agent_public_key); + + let shared_ecdh_secret = + libcrux_ecdh::p256_derive(&user_agent_public_key, &application_server_private_key).unwrap(); + + shared_ecdh_secret.0[..32].try_into().unwrap() +} + +// 2591738300 +// 2591738300 +#[cfg(test)] +mod test { + use base64::{ + prelude::{BASE64_URL_SAFE, BASE64_URL_SAFE_NO_PAD}, + Engine, + }; + + use super::*; + + const APPLICATION_SERVER_PRIVATE_KEY: &str = "yfWPiYE-n46HLnH0KqZOF1fJJU3MYrct3AELtAQ-oRw"; + const USER_AGENT_PUBLIC_KEY: &str = "BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcx\ + aOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4"; + const AUTHENTICATION_SECRET: &str = "BTBZMqHH6r4Tts7J_aSIgg"; + #[ignore] + #[test] + fn can_crate_pseudo_random_key_for_combining() { + // Arrange + const EXPECTED_PSEUDO_RANDOM_KEY: &str = "Snr3JMxaHVDXHWJn5wdC52WjpCtd2EIEGBykDcZW32k"; + let application_server_private_key = BASE64_URL_SAFE_NO_PAD + .decode(APPLICATION_SERVER_PRIVATE_KEY) + .unwrap(); + + let user_agent_public_key = BASE64_URL_SAFE_NO_PAD + .decode(USER_AGENT_PUBLIC_KEY) + .unwrap(); + + let authentication_secret = BASE64_URL_SAFE_NO_PAD + .decode(AUTHENTICATION_SECRET) + .unwrap(); + + // Act + let pseudo_random_key = create_pseudo_random_key( + &application_server_private_key, + &user_agent_public_key, + &authentication_secret, + ); + + let encoded = BASE64_URL_SAFE.encode(pseudo_random_key); + + // Assert + assert_eq!(EXPECTED_PSEUDO_RANDOM_KEY.len(), encoded.len()); + assert_eq!(EXPECTED_PSEUDO_RANDOM_KEY, encoded); + } + + #[test] + fn can_produce_shared_ecdh_secret() { + // Arrange + let expected_shared_ecdh_secret = BASE64_URL_SAFE_NO_PAD + .decode("kyrL1jIIOHEzg3sM2ZWRHDRB62YACZhhSlknJ672kSs") + .unwrap(); + + let application_server_private_key: [u8; 32] = BASE64_URL_SAFE_NO_PAD + .decode(APPLICATION_SERVER_PRIVATE_KEY) + .unwrap() + .try_into() + .unwrap(); + + let user_agent_public_key = BASE64_URL_SAFE_NO_PAD + .decode(USER_AGENT_PUBLIC_KEY) + .unwrap(); + + // Act + + let shared_secret = + create_shared_ecdh_secret(&application_server_private_key, &user_agent_public_key); + + // Assert + assert_eq!(expected_shared_ecdh_secret, shared_secret); + } +} diff --git a/src/index.rs b/supernova/src/index.rs similarity index 100% rename from src/index.rs rename to supernova/src/index.rs diff --git a/src/main.rs b/supernova/src/main.rs similarity index 97% rename from src/main.rs rename to supernova/src/main.rs index 07f83cf..1e7ed79 100644 --- a/src/main.rs +++ b/supernova/src/main.rs @@ -1,6 +1,7 @@ mod secrets; mod auth; +mod encrypted_content_encoding; mod index; use std::net::Ipv4Addr; diff --git a/src/secrets.rs b/supernova/src/secrets.rs similarity index 100% rename from src/secrets.rs rename to supernova/src/secrets.rs diff --git a/templates/index.html b/supernova/templates/index.html similarity index 100% rename from templates/index.html rename to supernova/templates/index.html diff --git a/templates/layout.html b/supernova/templates/layout.html similarity index 100% rename from templates/layout.html rename to supernova/templates/layout.html diff --git a/templates/sign_in.html b/supernova/templates/sign_in.html similarity index 100% rename from templates/sign_in.html rename to supernova/templates/sign_in.html diff --git a/web-shove/Cargo.toml b/web-shove/Cargo.toml new file mode 100644 index 0000000..ed6457e --- /dev/null +++ b/web-shove/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "web-shove" +version = "0.1.0" +edition = "2021" + +[dependencies] +base64 = "0.22.1" +getrandom = { version = "0.2.15", features = ["custom"] } +libcrux-ecdh = "0.0.2-alpha.3" +libcrux-hkdf = "0.0.2-alpha.3" +libcrux-hmac = "0.0.2-alpha.3" +p256 = { version = "0.13.2", features = ["ecdh"] } +rand = "0.8.5" +rand_chacha = "0.3.1" +ring = { version = "0.17.8", features = [ + "less-safe-getrandom-custom-or-rdrand", +] } +thiserror = "2.0.3" diff --git a/web-shove/src/lib.rs b/web-shove/src/lib.rs new file mode 100644 index 0000000..23adf65 --- /dev/null +++ b/web-shove/src/lib.rs @@ -0,0 +1,146 @@ +use std::{array::TryFromSliceError, rc::Rc}; + +use rand::prelude::*; +use ring::{ + agreement::{self, EphemeralPrivateKey}, + rand::SecureRandom, +}; +use thiserror::Error; + +const KEY_INFO: &[u8] = b"WebPush: info\0"; +const NONCE_INFO: &[u8] = b"Content-Encoding: nonce\0"; + +//TODO use ring when we know it works and figure out deterministic key generation for testing as it only generates ephemeral keys +fn create_pseudo_random_key<'a>( + application_server_private_key: &[u8], + user_agent_public_key: &[u8], + authentication_secret: &[u8], +) -> Rc<[u8]> { + // let mut random = rand_chacha::ChaCha8Rng::seed_from_u64(69); + // let random = ring::rand::SystemRandom::new(); + // EphemeralPrivateKey::generate(&agreement::ECDH_P256, &random); + // let number: u32 = random.gen(); + // let mut buffer = [0u8; 4]; + // let number = random.fill(&mut buffer); + // println!("My data is {:?}", buffer); + // println!("My number is {number}"); + // EphemeralPrivateKey::generate(alg, rng) + let application_server_key = + libcrux_ecdh::P256PrivateKey::try_from(application_server_private_key).unwrap(); + + // The first byte is a special byte that is used to identify the key type + let user_agent_key = + libcrux_ecdh::P256PublicKey::try_from(&user_agent_public_key[1..]).unwrap(); + + let shared_key = libcrux_ecdh::p256_derive(&user_agent_key, &application_server_key).unwrap(); + + // HKDF expand? + // libcrux_hkdf::expand(libcrux_hkdf::Algorithm::Sha256, prk, info, okm_len) + libcrux_hmac::hmac( + libcrux_hmac::Algorithm::Sha256, + application_server_private_key, + authentication_secret, + None, + ) + .into() + // libcrux_hkdf::hkdf( + // libcrux_hkdf::Algorithm::Sha256, + // authentication_secret, + // application_server_private_key, + // info, + // okm_len, + // ); +} + +fn create_shared_ecdh_secret( + application_server_private_key: &[u8], + user_agent_public_key: &[u8], +) -> [u8; 32] { + let application_server_private_key: &[u8; 32] = + application_server_private_key.try_into().unwrap(); + + let user_agent_public_key: &[u8; 64] = &user_agent_public_key[1..].try_into().unwrap(); + + let application_server_private_key = + libcrux_ecdh::P256PrivateKey::from(application_server_private_key); + + let user_agent_public_key = libcrux_ecdh::P256PublicKey::from(user_agent_public_key); + + let shared_ecdh_secret = + libcrux_ecdh::p256_derive(&user_agent_public_key, &application_server_private_key).unwrap(); + + shared_ecdh_secret.0[..32].try_into().unwrap() +} + +// 2591738300 +// 2591738300 +#[cfg(test)] +mod test { + use base64::{ + prelude::{BASE64_URL_SAFE, BASE64_URL_SAFE_NO_PAD}, + Engine, + }; + + use super::*; + + const APPLICATION_SERVER_PRIVATE_KEY: &str = "yfWPiYE-n46HLnH0KqZOF1fJJU3MYrct3AELtAQ-oRw"; + const USER_AGENT_PUBLIC_KEY: &str = "BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcx\ + aOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4"; + const AUTHENTICATION_SECRET: &str = "BTBZMqHH6r4Tts7J_aSIgg"; + #[ignore] + #[test] + fn can_crate_pseudo_random_key_for_combining() { + // Arrange + const EXPECTED_PSEUDO_RANDOM_KEY: &str = "Snr3JMxaHVDXHWJn5wdC52WjpCtd2EIEGBykDcZW32k"; + let application_server_private_key = BASE64_URL_SAFE_NO_PAD + .decode(APPLICATION_SERVER_PRIVATE_KEY) + .unwrap(); + + let user_agent_public_key = BASE64_URL_SAFE_NO_PAD + .decode(USER_AGENT_PUBLIC_KEY) + .unwrap(); + + let authentication_secret = BASE64_URL_SAFE_NO_PAD + .decode(AUTHENTICATION_SECRET) + .unwrap(); + + // Act + let pseudo_random_key = create_pseudo_random_key( + &application_server_private_key, + &user_agent_public_key, + &authentication_secret, + ); + + let encoded = BASE64_URL_SAFE.encode(pseudo_random_key); + + // Assert + assert_eq!(EXPECTED_PSEUDO_RANDOM_KEY.len(), encoded.len()); + assert_eq!(EXPECTED_PSEUDO_RANDOM_KEY, encoded); + } + + #[test] + fn can_produce_shared_ecdh_secret() { + // Arrange + let expected_shared_ecdh_secret = BASE64_URL_SAFE_NO_PAD + .decode("kyrL1jIIOHEzg3sM2ZWRHDRB62YACZhhSlknJ672kSs") + .unwrap(); + + let application_server_private_key: [u8; 32] = BASE64_URL_SAFE_NO_PAD + .decode(APPLICATION_SERVER_PRIVATE_KEY) + .unwrap() + .try_into() + .unwrap(); + + let user_agent_public_key = BASE64_URL_SAFE_NO_PAD + .decode(USER_AGENT_PUBLIC_KEY) + .unwrap(); + + // Act + + let shared_secret = + create_shared_ecdh_secret(&application_server_private_key, &user_agent_public_key); + + // Assert + assert_eq!(expected_shared_ecdh_secret, shared_secret); + } +}