From 0570b147a8854dc3f0d8a6101c75f31ba6bd0828 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Mon, 2 Oct 2023 14:30:59 +0300 Subject: [PATCH 01/26] argon2: Initial commit --- Cargo.lock | 172 ++++++++++++++++++------------ Cargo.toml | 4 +- src/crypto_helper.rs | 3 +- src/crypto_helper/algorithm.rs | 65 ++++++++++- src/crypto_helper/computations.rs | 6 +- src/crypto_helper/info.rs | 3 + src/crypto_helper/input.rs | 6 ++ src/crypto_helper/input/argon2.rs | 35 ++++++ src/crypto_helper/output.rs | 1 + 9 files changed, 221 insertions(+), 74 deletions(-) create mode 100644 src/crypto_helper/input/argon2.rs diff --git a/Cargo.lock b/Cargo.lock index 0ed3fabf..9026aff7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -91,6 +91,18 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash 0.5.0", +] + [[package]] name = "asn1-parser" version = "0.1.0" @@ -107,15 +119,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80" [[package]] name = "backtrace" -version = "0.3.69" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" dependencies = [ "addr2line", "cc", @@ -195,9 +207,18 @@ checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + +[[package]] +name = "blake2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] [[package]] name = "block-buffer" @@ -256,9 +277,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "cbc" @@ -383,6 +404,7 @@ dependencies = [ name = "crypto-helper" version = "0.10.0" dependencies = [ + "argon2", "asn1-parser", "base64 0.22.0", "bcrypt", @@ -395,11 +417,12 @@ dependencies = [ "log", "md5", "oid", + "password-hash 0.5.0", "paste", "picky", "picky-krb", - "rand 0.9.0-alpha.0", - "rand_chacha 0.9.0-alpha.0", + "rand 0.9.0-alpha.1", + "rand_chacha 0.9.0-alpha.1", "rsa", "serde", "serde_json", @@ -442,7 +465,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -598,9 +621,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984" [[package]] name = "ff" @@ -614,9 +637,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1676f435fc1dadde4d03e43f5d62b259e1ce5f40bd4ffb21db2b42ebe59c1382" +checksum = "c007b1ae3abe1cb6f85a16305acd418b7ca6343b953633fee2b76d8f108b830f" [[package]] name = "flate2" @@ -700,7 +723,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1169,7 +1192,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1274,14 +1297,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9311685eb9a34808bbb0608ad2fcab9ae216266beca5848613e95553ac914e3b" dependencies = [ "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -1299,9 +1322,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" @@ -1344,9 +1367,9 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libz-sys" -version = "1.1.15" +version = "1.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +checksum = "5e143b5e666b2695d28f6bca6497720813f699c9602dd7f5cac91008b8ada7f9" dependencies = [ "cc", "pkg-config", @@ -1528,6 +1551,17 @@ dependencies = [ "subtle", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.14" @@ -1542,7 +1576,7 @@ checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ "digest 0.10.7", "hmac", - "password-hash", + "password-hash 0.4.2", "sha-1", "sha2", ] @@ -1701,7 +1735,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1756,9 +1790,9 @@ checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platforms" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626dec3cac7cc0e1577a2ec3fc496277ec2baa084bebad95bb6fdbfae235f84c" +checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "powerfmt" @@ -1774,12 +1808,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "prettyplease" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" +checksum = "8d3928fb5db768cb86f891ff014f0144589297e3c6a1aba6ed7cecfdace270c7" dependencies = [ "proc-macro2", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -1908,11 +1942,11 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.0-alpha.0" +version = "0.9.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "807b7862b9cbece02dbbb9465356885df299fcc8b19d27a4570903eaf6a4062e" +checksum = "8d31e63ea85be51c423e52ba8f2e68a3efd53eed30203ee029dd09947333693e" dependencies = [ - "rand_core 0.9.0-alpha.0", + "rand_core 0.9.0-alpha.1", "zerocopy", ] @@ -1928,12 +1962,12 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.9.0-alpha.0" +version = "0.9.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5c41723acb3ac225e48e77a0921e0c69b36b670d857e0914fc8d574efa7df8" +checksum = "78674ef918c19451dbd250f8201f8619b494f64c9aa6f3adb28fd8a0f1f6da46" dependencies = [ "ppv-lite86", - "rand_core 0.9.0-alpha.0", + "rand_core 0.9.0-alpha.1", ] [[package]] @@ -1947,9 +1981,9 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0-alpha.0" +version = "0.9.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b962254c1392bbfc8571c17acb5d0e52116bbefd704e965e92e6c60fadc096e" +checksum = "cc89dffba8377c5ec847d12bb41492bda235dba31a25e8b695cd0fe6589eb8c9" dependencies = [ "getrandom", "zerocopy", @@ -1966,9 +2000,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.3" +version = "1.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" dependencies = [ "aho-corasick", "memchr", @@ -1989,9 +2023,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "rfc6979" @@ -2046,9 +2080,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.31" +version = "0.38.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89" dependencies = [ "bitflags", "errno", @@ -2149,14 +2183,14 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd" dependencies = [ "itoa", "ryu", @@ -2270,9 +2304,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "spin" @@ -2308,9 +2342,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", @@ -2346,7 +2380,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -2428,7 +2462,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -2472,9 +2506,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", "serde", @@ -2529,7 +2563,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", "wasm-bindgen-shared", ] @@ -2563,7 +2597,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2729,7 +2763,7 @@ checksum = "7ad00f6c9436d25c9225ed0fd8eea27e6d2886c1387bf934afdf91e9131b8b77" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -2760,7 +2794,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -2802,27 +2836,27 @@ checksum = "42bfd190a07ca8cfde7cd4c52b3ac463803dc07323db8c34daa697e86365978c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] name = "zerocopy" -version = "0.8.0-alpha.5" +version = "0.8.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd4a4b5a6b38e736bca19abe211abf0ba2552462555fc960d763fbbaff2b191" +checksum = "db678a6ee512bd06adf35c35be471cae2f9c82a5aed2b5d15e03628c98bddd57" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.0-alpha.5" +version = "0.8.0-alpha.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "157bd6b2f5a6f8e2b1b1e5b427aec8d2c085f9ab99c92eaa0ca79b9b84c11254" +checksum = "201585ea96d37ee69f2ac769925ca57160cef31acb137c16f38b02b76f4c1e62" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] [[package]] @@ -2842,5 +2876,5 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.55", ] diff --git a/Cargo.toml b/Cargo.toml index eff6de25..31eef2d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,8 @@ bcrypt = "0.15" flate2 = { version = "1.0", features = ["zlib"] } rand = { version = "0.9.0-alpha.0", default-features = false, features = ["small_rng"] } rand_chacha = "0.9.0-alpha.0" +argon2 = "0.5" +password-hash = "0.5" # asn1 asn1-parser = { path = "./crates/asn1-parser", features = ["std"] } @@ -66,4 +68,4 @@ oid = { version = "0.2", default-features = false } paste = "1.0" # diff -similar = { version = "2.4", features = ["serde"] } \ No newline at end of file +similar = { version = "2.4", features = ["serde"] } diff --git a/src/crypto_helper.rs b/src/crypto_helper.rs index a2690399..0e9e0dc2 100644 --- a/src/crypto_helper.rs +++ b/src/crypto_helper.rs @@ -16,7 +16,7 @@ use yew::{function_component, html, use_effect_with, use_state, Callback, Html}; use yew_hooks::{use_clipboard, use_local_storage, use_location}; use yew_notifications::{use_notification, Notification, NotificationType}; -use self::computations::{process_krb_cipher, process_krb_hmac, process_rsa, process_zlib}; +use self::computations::{process_krb_cipher, process_krb_hmac, process_rsa, process_zlib, process_argon2}; use crate::crypto_helper::computations::process_bcrypt; use crate::url_query_params::generate_crypto_helper_link; @@ -40,6 +40,7 @@ fn convert(algrithm: &Algorithm) -> Result, String> { Algorithm::Rsa(input) => process_rsa(input), Algorithm::Bcrypt(input) => process_bcrypt(input), Algorithm::Zlib(input) => process_zlib(input), + Algorithm::Argon2(input) => process_argon2(input), } } diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index a3397240..155897db 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -18,8 +18,9 @@ pub const RSA: &str = "RSA"; pub const SHA384: &str = "SHA384"; pub const BCRYPT: &str = "BCRYPT"; pub const ZLIB: &str = "ZLIB"; +pub const ARGON2: &str = "ARGON2"; -pub const SUPPORTED_ALGORITHMS: [&str; 12] = [ +pub const SUPPORTED_ALGORITHMS: [&str; 13] = [ MD5, SHA1, SHA256, @@ -32,9 +33,10 @@ pub const SUPPORTED_ALGORITHMS: [&str; 12] = [ SHA384, BCRYPT, ZLIB, + ARGON2, ]; -pub const HASHING_ALGOS: [&str; 6] = [MD5, SHA1, SHA256, SHA384, SHA512, BCRYPT]; +pub const HASHING_ALGOS: [&str; 7] = [MD5, SHA1, SHA256, SHA384, SHA512, BCRYPT, ARGON2]; pub const ENCRYPTION_ALGOS: [&str; 3] = [AES128_CTS_HMAC_SHA1_96, AES256_CTS_HMAC_SHA1_96, RSA]; @@ -362,6 +364,61 @@ pub struct ZlibInput { pub data: Vec, } +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct Argon2HashAction { + memory: u32, + iters: u32, + paralelism: u32, + output_len: u32, +} + +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub enum Argon2Action { + Hash(Argon2HashAction), + Verify(Vec), +} +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub struct Argon2Input { + pub action: Argon2Action, + #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] + pub data: Vec, +} + +impl From for Argon2HashAction { + fn from(value: argon2::Params) -> Self { + let params = argon2::Params::DEFAULT; + Self { + memory: params.m_cost(), + iters: params.t_cost(), + paralelism: params.p_cost(), + output_len: 32 + } + } +} + +impl Default for Argon2HashAction { + fn default() -> Self { + argon2::Params::DEFAULT.into() + } +} + +impl Default for Argon2Action { + fn default() -> Self { + Self::Hash(Argon2HashAction::default()) + } +} + +impl Default for Argon2Input { + fn default() -> Self { + Self { + action: Argon2Action::default(), + data: Vec::new() + } + } +} + + + #[allow(clippy::large_enum_variant)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum Algorithm { @@ -382,6 +439,7 @@ pub enum Algorithm { Rsa(RsaInput), Bcrypt(BcryptInput), Zlib(ZlibInput), + Argon2(Argon2Input), } impl TryFrom<&str> for Algorithm { @@ -412,6 +470,8 @@ impl TryFrom<&str> for Algorithm { return Ok(Algorithm::Bcrypt(Default::default())); } else if value == ZLIB { return Ok(Algorithm::Zlib(Default::default())); + } else if value == ARGON2 { + return Ok(Algorithm::Argon2(Default::default())); } Err(format!( @@ -436,6 +496,7 @@ impl From<&Algorithm> for &str { Algorithm::Rsa(_) => RSA, Algorithm::Bcrypt(_) => BCRYPT, Algorithm::Zlib(_) => ZLIB, + Algorithm::Argon2(_) => ARGON2, } } } diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index d591e445..11390bfe 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -10,7 +10,7 @@ use rsa::rand_core::OsRng; use rsa::Pkcs1v15Encrypt; use super::algorithm::{ - BcryptAction, BcryptInput, KrbInput, KrbInputData, KrbMode, RsaAction, RsaInput, ZlibInput, ZlibMode, + BcryptAction, BcryptInput, KrbInput, KrbInputData, KrbMode, RsaAction, RsaInput, ZlibInput, ZlibMode, Argon2Input, Argon2Action, }; pub fn process_rsa(input: &RsaInput) -> Result, String> { @@ -91,3 +91,7 @@ pub fn process_zlib(input: &ZlibInput) -> Result, String> { } } } + +pub fn process_argon2(input: &Argon2Input) -> Result, String> { + todo!() +} \ No newline at end of file diff --git a/src/crypto_helper/info.rs b/src/crypto_helper/info.rs index 22db9bb0..fdd2d414 100644 --- a/src/crypto_helper/info.rs +++ b/src/crypto_helper/info.rs @@ -73,6 +73,9 @@ fn get_algorithm_info(algorithm: &Algorithm) -> Html { {"RFC"} }, + Algorithm::Argon2(_) => html! { + {"Use Argon2 to encrypt/verify your data."} + }, } } diff --git a/src/crypto_helper/input.rs b/src/crypto_helper/input.rs index 33d189d1..d9ebff9d 100644 --- a/src/crypto_helper/input.rs +++ b/src/crypto_helper/input.rs @@ -1,3 +1,4 @@ +mod argon2; mod bcrypt; mod krb; mod rsa; @@ -6,6 +7,7 @@ mod zlib; use picky_krb::crypto::CipherSuite; use yew::{function_component, html, Callback, Html, Properties, UseStateSetter}; +use self::argon2::build_argon2_input; use self::bcrypt::build_bcrypt_input; use self::krb::build_krb_input; use self::rsa::build_rsa_input; @@ -93,6 +95,10 @@ fn get_input_components(algorithm: &Algorithm, setter: &UseStateSetter build_argon2_input( + input.clone(), + Callback::from(move |input| setter.set(Algorithm::Argon2(input))), + ), } } diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs new file mode 100644 index 00000000..1ad829b9 --- /dev/null +++ b/src/crypto_helper/input/argon2.rs @@ -0,0 +1,35 @@ +use web_sys::HtmlInputElement; +use yew::{classes, function_component, html, Callback, Html, Properties, TargetCast}; +use yew_notifications::{use_notification, Notification, NotificationType}; + +use crate::{crypto_helper::algorithm::Argon2Input as Argon2InputData, common::{build_byte_input, BytesFormat}}; + +#[derive(PartialEq, Properties, Clone)] +pub struct Argon2InputProps { + pub input: Argon2InputData, + pub argon2_input_setter: Callback, +} + +#[function_component(Argon2Input)] +pub fn argon2_input(props: &Argon2InputProps) -> Html { + let data = props.input.data.clone(); + let input_setter = props.argon2_input_setter.clone(); + let action = props.input.action.clone(); + let setter = Callback::from(move |data| { + input_setter.emit(Argon2InputData { + action: action.clone(), + data, + }) + }); + html! { +
+ {build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("argon2".into()))} +
+ } +} + +pub fn build_argon2_input(input: Argon2InputData, setter: Callback) -> Html { + html! { + + } +} diff --git a/src/crypto_helper/output.rs b/src/crypto_helper/output.rs index 095b2e38..9e2e57ce 100644 --- a/src/crypto_helper/output.rs +++ b/src/crypto_helper/output.rs @@ -28,6 +28,7 @@ fn get_output_components(algorithm: &Algorithm, output: &[u8], add_notification: add_notification, ), Algorithm::Zlib(_) => build_simple_output(output.into(), BytesFormat::Hex, add_notification), + Algorithm::Argon2(_) => build_simple_output(output.into(), BytesFormat::Hex, add_notification), } } From 4c20e18f66fce0d993d7ceb7fd391e1a37cfb42c Mon Sep 17 00:00:00 2001 From: Jujumba Date: Mon, 9 Oct 2023 00:57:58 +0300 Subject: [PATCH 02/26] readme: fix readme --- README.md | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 09e30e9d..50c09c43 100644 --- a/README.md +++ b/README.md @@ -8,16 +8,17 @@ Visit this tool at [crypto.qkation.com](https://crypto.qkation.com). Table of content: -* [Features](#features) -* [Development](#development) -* [Meta](#meta) -* [Contributing](#contributing) +- [crypto-helper](#crypto-helper) + - [Features](#features) + - [Development](#development) + - [Meta](#meta) + - [Contributing](#contributing) ![](/public/img/example.png) ![](/public/img/sha.png) ![](/public/img/jwt.png) -The crypto-helper is an online app that helps to work with the different crypto algorithms. This app can hash/hmac, encrypt/decrypt, and sign/verify the data. +The crypto-helper is a web app that helps to work with the different crypto algorithms. This app can hash/hmac, encrypt/decrypt, and sign/verify the data. All computations are performed on the client side. This tool never sends the data to any server. @@ -25,6 +26,7 @@ All computations are performed on the client side. This tool never sends the dat * Written in [Rust](https://github.com/rust-lang/rust) :crab: using [yew](https://github.com/yewstack/yew) :sparkles: * `MD5` +* `BCRYPT` * `SHA1`/`SHA256`/`SHA384`/`SHA512` * Kerberos ciphers: `AES128-CTS-HMAC-SHA1-96`/`AES256-CTS-HMAC-SHA1-96` * Kerberos HMAC: `HMAC-SHA1-96-AES128`/`HMAC-SHA1-96-AES256` @@ -55,7 +57,7 @@ export APP_HOST= # example: # export APP_HOST=https://crypto-helper.qkation.com ``` -This env variable is uses for the url generation when you click the *share by url* button. +This env variable is used for the url generation when you click the *share by url* button. 3. Run `trunk serve` in your terminal. 4. Go to http://127.0.0.1:8080 in your browser. From 3c7ec2741ce3242aa4bee53fd4fb5e8980faaafd Mon Sep 17 00:00:00 2001 From: Jujumba Date: Mon, 27 Nov 2023 13:28:45 +0100 Subject: [PATCH 03/26] argon2: impl `From` trait for Argon2 structs --- src/crypto_helper/algorithm.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index 155897db..8fe4b039 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -417,6 +417,20 @@ impl Default for Argon2Input { } } +impl From for Argon2Action { + fn from(value: bool) -> Self { + match value { + true => Argon2Action::Verify(Default::default()), + false => Argon2Action::Hash(Default::default()) + } + } +} + +impl From<&Argon2Action> for bool { + fn from(value: &Argon2Action) -> Self { + value.into() + } +} #[allow(clippy::large_enum_variant)] From d7c6abbcbc5abad7f1f032cb6d91c98b39021115 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Mon, 27 Nov 2023 13:29:10 +0100 Subject: [PATCH 04/26] argon2: add switch --- src/crypto_helper/input/argon2.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs index 1ad829b9..236e9cb0 100644 --- a/src/crypto_helper/input/argon2.rs +++ b/src/crypto_helper/input/argon2.rs @@ -1,8 +1,6 @@ -use web_sys::HtmlInputElement; -use yew::{classes, function_component, html, Callback, Html, Properties, TargetCast}; -use yew_notifications::{use_notification, Notification, NotificationType}; +use yew::{classes, function_component, html, Callback, Html, Properties}; -use crate::{crypto_helper::algorithm::Argon2Input as Argon2InputData, common::{build_byte_input, BytesFormat}}; +use crate::{crypto_helper::algorithm::{Argon2Input as Argon2InputData, Argon2Action}, common::{build_byte_input, BytesFormat, Switch}}; #[derive(PartialEq, Properties, Clone)] pub struct Argon2InputProps { @@ -12,17 +10,35 @@ pub struct Argon2InputProps { #[function_component(Argon2Input)] pub fn argon2_input(props: &Argon2InputProps) -> Html { - let data = props.input.data.clone(); + let data: Vec = props.input.data.clone(); + let input_setter = props.argon2_input_setter.clone(); - let action = props.input.action.clone(); + let action: Argon2Action = props.input.action.clone(); let setter = Callback::from(move |data| { input_setter.emit(Argon2InputData { action: action.clone(), data, }) }); + + let input_setter = props.argon2_input_setter.clone(); + let input = props.input.clone(); + let on_switch = Callback::from(move |mode: bool| { + let Argon2InputData { data, ..} = input.clone(); + input_setter.emit(Argon2InputData { + action: mode.into(), + data + }) + }); + + let switch_state = bool::from(&props.input.action); html! {
+
+ {"hash"} + + {"verify"} +
{build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("argon2".into()))}
} From a438fa3c955913b2cdd1f83f6c8d6ba92fcdd5e3 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Thu, 4 Jan 2024 19:37:07 +0100 Subject: [PATCH 05/26] argon2: impl `process_argon2` --- src/crypto_helper/algorithm.rs | 86 ++++++++++++++++++++++++------- src/crypto_helper/computations.rs | 38 ++++++++++++-- 2 files changed, 103 insertions(+), 21 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index 8fe4b039..b413b488 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -363,13 +363,30 @@ pub struct ZlibInput { #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub data: Vec, } - +#[derive(Eq, Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Default)] +pub enum Argon2Variant { + Argon2i, + Argon2d, + #[default] + Argon2id, +} +#[derive(Eq, Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Default)] +pub enum Argon2Version { + Version10, + #[default] + Version13, +} #[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct Argon2HashAction { - memory: u32, - iters: u32, - paralelism: u32, - output_len: u32, + pub memory: u32, + pub iters: u32, + pub paralelism: u32, + pub output_len: u32, + pub salt: Vec, + pub data: Vec, + pub secret: Vec, + pub variant: Argon2Variant, + pub version: Argon2Version, } #[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] @@ -384,22 +401,56 @@ pub struct Argon2Input { pub data: Vec, } -impl From for Argon2HashAction { - fn from(value: argon2::Params) -> Self { - let params = argon2::Params::DEFAULT; - Self { - memory: params.m_cost(), - iters: params.t_cost(), - paralelism: params.p_cost(), - output_len: 32 +impl From for argon2::Algorithm { + fn from(value: Argon2Variant) -> Self { + match value { + Argon2Variant::Argon2d => argon2::Algorithm::Argon2d, + Argon2Variant::Argon2i => argon2::Algorithm::Argon2i, + Argon2Variant::Argon2id => argon2::Algorithm::Argon2id, + } + } +} + +impl From for argon2::Version { + fn from(value: Argon2Version) -> Self { + match value { + Argon2Version::Version10 => argon2::Version::V0x10, + Argon2Version::Version13 => argon2::Version::V0x13, } } } +impl From<&Argon2HashAction> for argon2::Params { + fn from(value: &Argon2HashAction) -> Self { + argon2::ParamsBuilder::new() + .m_cost(value.memory) + .p_cost(value.paralelism) + .t_cost(value.iters) + .build() + .unwrap() + } +} + +impl<'a> TryFrom<&'a Argon2HashAction> for argon2::password_hash::Salt<'a> { + type Error = String; + fn try_from(hash_action: &'a Argon2HashAction) -> Result { + argon2::password_hash::Salt::from_b64( + std::str::from_utf8(&hash_action.salt).map_err(|_| "Non UTF-8 salt".to_owned())?, + ) + .map_err(|err| err.to_string()) + } +} + impl Default for Argon2HashAction { fn default() -> Self { - argon2::Params::DEFAULT.into() - } + Self { + memory: 19456, + iters: 2, + paralelism: 1, + output_len: 32, + ..Default::default() + } + } } impl Default for Argon2Action { @@ -412,7 +463,7 @@ impl Default for Argon2Input { fn default() -> Self { Self { action: Argon2Action::default(), - data: Vec::new() + data: Vec::new(), } } } @@ -421,7 +472,7 @@ impl From for Argon2Action { fn from(value: bool) -> Self { match value { true => Argon2Action::Verify(Default::default()), - false => Argon2Action::Hash(Default::default()) + false => Argon2Action::Hash(Default::default()), } } } @@ -432,7 +483,6 @@ impl From<&Argon2Action> for bool { } } - #[allow(clippy::large_enum_variant)] #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum Algorithm { diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 11390bfe..4900cc3b 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -1,6 +1,7 @@ use std::convert::TryInto; use std::io::Write; +use argon2::{PasswordHasher, PasswordVerifier}; use bcrypt::Version; use flate2::write::{ZlibDecoder, ZlibEncoder}; use flate2::Compression; @@ -10,7 +11,8 @@ use rsa::rand_core::OsRng; use rsa::Pkcs1v15Encrypt; use super::algorithm::{ - BcryptAction, BcryptInput, KrbInput, KrbInputData, KrbMode, RsaAction, RsaInput, ZlibInput, ZlibMode, Argon2Input, Argon2Action, + Argon2Action, Argon2Input, BcryptAction, BcryptInput, KrbInput, KrbInputData, KrbMode, RsaAction, RsaInput, + ZlibInput, ZlibMode, }; pub fn process_rsa(input: &RsaInput) -> Result, String> { @@ -93,5 +95,35 @@ pub fn process_zlib(input: &ZlibInput) -> Result, String> { } pub fn process_argon2(input: &Argon2Input) -> Result, String> { - todo!() -} \ No newline at end of file + match &input.action { + Argon2Action::Hash(hash_action) => { + let argon2ctx = argon2::Argon2::new( + hash_action.variant.into(), + hash_action.version.into(), + hash_action.into(), + ); + let salt: argon2::password_hash::Salt = hash_action.try_into()?; + + let bytes: Vec = argon2ctx + .hash_password(&hash_action.data, salt) + .map(|pwd| pwd.hash.unwrap()) + .map_err(|err| err.to_string())? + .as_bytes() + .into(); + + Ok(bytes) + } + Argon2Action::Verify(data) => { + let hash: argon2::PasswordHash = std::str::from_utf8(data) + .map_err(|err| err.to_string())? + .try_into() + .map_err(|err: argon2::password_hash::Error| err.to_string())?; + + if argon2::Argon2::default().verify_password(data, &hash).is_ok() { + Ok(vec![1]) + } else { + Ok(vec![0]) + } + } + } +} From 3d5b06607d1c16731dd6056ee91efb3393c8afd5 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Wed, 31 Jan 2024 19:50:15 +0100 Subject: [PATCH 06/26] argon2: fix serialization --- src/crypto_helper/algorithm.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index b413b488..9b6aa518 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -381,9 +381,12 @@ pub struct Argon2HashAction { pub memory: u32, pub iters: u32, pub paralelism: u32, - pub output_len: u32, + pub output_len: usize, + #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub salt: Vec, + #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub data: Vec, + #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub secret: Vec, pub variant: Argon2Variant, pub version: Argon2Version, @@ -392,7 +395,7 @@ pub struct Argon2HashAction { #[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] pub enum Argon2Action { Hash(Argon2HashAction), - Verify(Vec), + Verify(#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] Vec), } #[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct Argon2Input { @@ -434,21 +437,23 @@ impl From<&Argon2HashAction> for argon2::Params { impl<'a> TryFrom<&'a Argon2HashAction> for argon2::password_hash::Salt<'a> { type Error = String; fn try_from(hash_action: &'a Argon2HashAction) -> Result { - argon2::password_hash::Salt::from_b64( - std::str::from_utf8(&hash_action.salt).map_err(|_| "Non UTF-8 salt".to_owned())?, - ) - .map_err(|err| err.to_string()) + argon2::password_hash::Salt::from_b64(unsafe { std::str::from_utf8_unchecked(&hash_action.salt) }) + .map_err(|err| err.to_string()) } } impl Default for Argon2HashAction { fn default() -> Self { Self { - memory: 19456, - iters: 2, - paralelism: 1, - output_len: 32, - ..Default::default() + memory: 19456u32, + iters: 2u32, + paralelism: 1u32, + output_len: 32usize, + salt: Default::default(), + data: Default::default(), + secret: Default::default(), + variant: Default::default(), + version: Default::default(), } } } @@ -479,7 +484,10 @@ impl From for Argon2Action { impl From<&Argon2Action> for bool { fn from(value: &Argon2Action) -> Self { - value.into() + match value { + Argon2Action::Verify(_) => true, + Argon2Action::Hash(_) => false, + } } } From a4627ae5d3dde67daef8f93d1f8183cdc9e9b26e Mon Sep 17 00:00:00 2001 From: Jujumba Date: Wed, 31 Jan 2024 21:28:11 +0100 Subject: [PATCH 07/26] argon2: Add rfc link --- src/crypto_helper/info.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/crypto_helper/info.rs b/src/crypto_helper/info.rs index fdd2d414..71231bc3 100644 --- a/src/crypto_helper/info.rs +++ b/src/crypto_helper/info.rs @@ -74,7 +74,9 @@ fn get_algorithm_info(algorithm: &Algorithm) -> Html { }, Algorithm::Argon2(_) => html! { - {"Use Argon2 to encrypt/verify your data."} + {"Use Argon2 to encrypt/verify your data."} + {"RFC"} + }, } } From d3eaa094d737d36409f65b93e36ca1e0db2fd9a8 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Wed, 31 Jan 2024 23:43:20 +0100 Subject: [PATCH 08/26] argon2: input: add `set_version` closure --- src/crypto_helper/algorithm.rs | 27 +++++++++++++++++ src/crypto_helper/input/argon2.rs | 50 +++++++++++++++++++++++++++---- 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index 9b6aa518..b33fd376 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -404,6 +404,33 @@ pub struct Argon2Input { pub data: Vec, } +impl Argon2Input { + pub fn set_variant(&self, variant: Argon2Variant) -> Self { + let mut input = self.clone(); + if let Argon2Action::Hash(ref mut action) = input.action { + action.variant = variant; + } + input + } + pub fn set_version(&self, version: Argon2Version) -> Self { + let mut input = self.clone(); + if let Argon2Action::Hash(ref mut action) = input.action { + action.version = version; + } + input + } +} +impl<'a> TryFrom<&'a str> for Argon2Version { + type Error = (); // todo: proper error type + + fn try_from(value: &'a str) -> Result { + match value { + "Argon13" => Ok(Self::Version13), + "Argon10" => Ok(Self::Version10), + _ => Err(()), + } + } +} impl From for argon2::Algorithm { fn from(value: Argon2Variant) -> Self { match value { diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs index 236e9cb0..4fd1bdc5 100644 --- a/src/crypto_helper/input/argon2.rs +++ b/src/crypto_helper/input/argon2.rs @@ -1,6 +1,9 @@ use yew::{classes, function_component, html, Callback, Html, Properties}; -use crate::{crypto_helper::algorithm::{Argon2Input as Argon2InputData, Argon2Action}, common::{build_byte_input, BytesFormat, Switch}}; +use crate::{ + common::{build_byte_input, BytesFormat, Switch}, + crypto_helper::algorithm::{Argon2Action, Argon2Input as Argon2InputData, Argon2Variant, Argon2Version}, +}; #[derive(PartialEq, Properties, Clone)] pub struct Argon2InputProps { @@ -23,23 +26,58 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { let input_setter = props.argon2_input_setter.clone(); let input = props.input.clone(); - let on_switch = Callback::from(move |mode: bool| { - let Argon2InputData { data, ..} = input.clone(); + let on_hash_verify_switch = Callback::from(move |mode: bool| { + let Argon2InputData { data, .. } = input.clone(); input_setter.emit(Argon2InputData { action: mode.into(), - data + data, }) }); + let input = props.input.clone(); + let get_hash_verify_switch_state = Callback::from(move |()| -> bool { (&input.action).into() }); + + let hash_verify_switch_state = bool::from(&props.input.action); + + let input_setter = props.argon2_input_setter.clone(); + let input = props.input.clone(); + let set_version = move |event: web_sys::Event| { + let target = event.target().expect("NO TARGET"); + let version: String = js_sys::Reflect::get(target.as_ref(), &"value".into()) + .unwrap() + .as_string() + .unwrap(); - let switch_state = bool::from(&props.input.action); + let input = input.clone(); + let input = input.set_version(version.as_str().try_into().unwrap()); + log::debug!("{input:?}"); + input_setter.emit(input.clone()); + }; html! {
{"hash"} - + {"verify"}
{build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("argon2".into()))} + + { + if !get_hash_verify_switch_state.emit(()) { + html! { + <> + {"Version"} + + + } + } else { + html! { + + } + } + }
} } From b1b4a02d79a44b264c80b4f1e8c869549e87f98a Mon Sep 17 00:00:00 2001 From: Jujumba Date: Thu, 1 Feb 2024 00:05:50 +0100 Subject: [PATCH 09/26] argon2: fix `[u8]` to `String` conversion --- src/crypto_helper/algorithm.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index b33fd376..8d8e8a04 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -1,3 +1,4 @@ +use base64::engine::{general_purpose::STANDARD as B64ENCODER, Engine}; use picky::hash::HashAlgorithm; use picky::key::{PrivateKey, PublicKey}; use rsa::pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey}; @@ -464,8 +465,8 @@ impl From<&Argon2HashAction> for argon2::Params { impl<'a> TryFrom<&'a Argon2HashAction> for argon2::password_hash::Salt<'a> { type Error = String; fn try_from(hash_action: &'a Argon2HashAction) -> Result { - argon2::password_hash::Salt::from_b64(unsafe { std::str::from_utf8_unchecked(&hash_action.salt) }) - .map_err(|err| err.to_string()) + let string = B64ENCODER.encode(&hash_action.salt); + argon2::password_hash::Salt::from_b64(&string).map_err(|err| err.to_string()) } } From b0748ff0414410145ff1a167ded7a525906a4f14 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Thu, 1 Feb 2024 00:32:26 +0100 Subject: [PATCH 10/26] argon2: fixes --- src/crypto_helper/algorithm.rs | 20 +------------------- src/crypto_helper/computations.rs | 3 ++- 2 files changed, 3 insertions(+), 20 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index 8d8e8a04..e6847095 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -1,4 +1,3 @@ -use base64::engine::{general_purpose::STANDARD as B64ENCODER, Engine}; use picky::hash::HashAlgorithm; use picky::key::{PrivateKey, PublicKey}; use rsa::pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey}; @@ -398,7 +397,7 @@ pub enum Argon2Action { Hash(Argon2HashAction), Verify(#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] Vec), } -#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize, Default)] pub struct Argon2Input { pub action: Argon2Action, #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] @@ -462,14 +461,6 @@ impl From<&Argon2HashAction> for argon2::Params { } } -impl<'a> TryFrom<&'a Argon2HashAction> for argon2::password_hash::Salt<'a> { - type Error = String; - fn try_from(hash_action: &'a Argon2HashAction) -> Result { - let string = B64ENCODER.encode(&hash_action.salt); - argon2::password_hash::Salt::from_b64(&string).map_err(|err| err.to_string()) - } -} - impl Default for Argon2HashAction { fn default() -> Self { Self { @@ -492,15 +483,6 @@ impl Default for Argon2Action { } } -impl Default for Argon2Input { - fn default() -> Self { - Self { - action: Argon2Action::default(), - data: Vec::new(), - } - } -} - impl From for Argon2Action { fn from(value: bool) -> Self { match value { diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 4900cc3b..7ca8ebd9 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -102,7 +102,8 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { hash_action.version.into(), hash_action.into(), ); - let salt: argon2::password_hash::Salt = hash_action.try_into()?; + let b64 = base64::encode(&hash_action.salt); + let salt = argon2::password_hash::Salt::from_b64(&b64).unwrap(); let bytes: Vec = argon2ctx .hash_password(&hash_action.data, salt) From d326e31ac59ee87429febcbf08c7a44e718538b6 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Thu, 1 Feb 2024 20:50:56 +0100 Subject: [PATCH 11/26] info: Add `Argon2` and `Bcrypt` --- README.md | 1 + src/about.rs | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 50c09c43..73327072 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ All computations are performed on the client side. This tool never sends the dat * Written in [Rust](https://github.com/rust-lang/rust) :crab: using [yew](https://github.com/yewstack/yew) :sparkles: * `MD5` +* `Argon2` * `BCRYPT` * `SHA1`/`SHA256`/`SHA384`/`SHA512` * Kerberos ciphers: `AES128-CTS-HMAC-SHA1-96`/`AES256-CTS-HMAC-SHA1-96` diff --git a/src/about.rs b/src/about.rs index 8ac328ba..a11de27d 100644 --- a/src/about.rs +++ b/src/about.rs @@ -7,7 +7,11 @@ pub fn about() -> Html { {"Crypto-helper"} {"The crypto-helper is an online app that helps to work with the diferent crypto algorithms:"}
    +
  • {"Argon2"}
  • +
  • {"BCrypt"}
  • {"MD5"}
  • +
  • {"Argon2"}
  • +
  • {"BCRYPT"}
  • {"SHA1/SHA256/SHA384/SHA512"}
  • {"Kerberos ciphers: AES128-CTS-HMAC-SHA1-96/AES256-CTS-HMAC-SHA1-96"}
  • {"Kerberos HMAC: HMAC-SHA1-96-AES128/HMAC-SHA1-96-AES256"}
  • From a119a4922e1a32a357e2eea12033d271bbf7a9d4 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sat, 24 Feb 2024 20:57:09 +0100 Subject: [PATCH 12/26] argon2: generate random salt if empty one is supplied --- src/crypto_helper/computations.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 7ca8ebd9..81232572 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -95,6 +95,8 @@ pub fn process_zlib(input: &ZlibInput) -> Result, String> { } pub fn process_argon2(input: &Argon2Input) -> Result, String> { + use rand::RngCore; + match &input.action { Argon2Action::Hash(hash_action) => { let argon2ctx = argon2::Argon2::new( @@ -102,8 +104,18 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { hash_action.version.into(), hash_action.into(), ); - let b64 = base64::encode(&hash_action.salt); - let salt = argon2::password_hash::Salt::from_b64(&b64).unwrap(); + + let b64 = if hash_action.salt.is_empty() { + let mut rng = rand::rngs::StdRng::from_rng(rand::thread_rng()).unwrap(); + let mut bytes = [0u8; 16]; + rng.fill_bytes(&mut bytes); + base64::encode(bytes) + } else { + base64::encode(&hash_action.salt) + }; + + let salt = argon2::password_hash::Salt::from_b64(&b64) + .map_err(|err| format!("Error while building salt: {err:?}"))?; let bytes: Vec = argon2ctx .hash_password(&hash_action.data, salt) From 3253969c12d31e2614673fbc85dd0d922f79c7d8 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sun, 25 Feb 2024 21:00:44 +0100 Subject: [PATCH 13/26] argon2: fix random salt generation --- src/crypto_helper/computations.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 81232572..0447951b 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -105,9 +105,10 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { hash_action.into(), ); + log::debug!("salt: {:?}", hash_action.salt); let b64 = if hash_action.salt.is_empty() { let mut rng = rand::rngs::StdRng::from_rng(rand::thread_rng()).unwrap(); - let mut bytes = [0u8; 16]; + let mut bytes = [0u8; 24]; rng.fill_bytes(&mut bytes); base64::encode(bytes) } else { From 9c28fe85c0b75215f868b24576e3d43c36ea12c2 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sun, 25 Feb 2024 21:06:23 +0100 Subject: [PATCH 14/26] argon2: impl `TryFrom<&str>` for `Argon2Variant` --- src/crypto_helper/algorithm.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index e6847095..6c9ba493 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -440,6 +440,17 @@ impl From for argon2::Algorithm { } } } +impl TryFrom<&str> for Argon2Variant { + type Error = (); + fn try_from(value: &str) -> Result { + match value { + "Argon2i" => Ok(Self::Argon2i), + "Argon2d" => Ok(Self::Argon2d), + "Argon2id" => Ok(Self::Argon2id), + _ => Err(()), + } + } +} impl From for argon2::Version { fn from(value: Argon2Version) -> Self { From 2b6124f320a6c76c5b4f8e751fdf9e49cdd20f43 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sun, 25 Feb 2024 21:33:29 +0100 Subject: [PATCH 15/26] argon2: add salt input --- src/crypto_helper/input/argon2.rs | 76 ++++++++++++++++++------------- 1 file changed, 45 insertions(+), 31 deletions(-) diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs index 4fd1bdc5..743e8524 100644 --- a/src/crypto_helper/input/argon2.rs +++ b/src/crypto_helper/input/argon2.rs @@ -1,8 +1,9 @@ -use yew::{classes, function_component, html, Callback, Html, Properties}; +use web_sys::HtmlInputElement; +use yew::{classes, function_component, html, html::TargetCast, Callback, Html, Properties}; use crate::{ common::{build_byte_input, BytesFormat, Switch}, - crypto_helper::algorithm::{Argon2Action, Argon2Input as Argon2InputData, Argon2Variant, Argon2Version}, + crypto_helper::algorithm::{Argon2Action, Argon2HashAction, Argon2Input as Argon2InputData}, }; #[derive(PartialEq, Properties, Clone)] @@ -18,12 +19,27 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { let input_setter = props.argon2_input_setter.clone(); let action: Argon2Action = props.input.action.clone(); let setter = Callback::from(move |data| { + log::debug!("setting data: {data:?}"); input_setter.emit(Argon2InputData { action: action.clone(), data, }) }); + let data: Vec = props.input.data.clone(); + let input_setter = props.argon2_input_setter.clone(); + let action: Argon2Action = props.input.action.clone(); + + let salt_setter = Callback::from(move |salt| { + log::debug!("setting salt with data: {data:?}"); + if let Argon2Action::Hash(hash_action) = action.clone() { + input_setter.emit(Argon2InputData { + action: Argon2Action::Hash(Argon2HashAction { salt, ..hash_action }), + data: data.clone(), + }) + } + }); + let input_setter = props.argon2_input_setter.clone(); let input = props.input.clone(); let on_hash_verify_switch = Callback::from(move |mode: bool| { @@ -33,25 +49,27 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { data, }) }); + let hash_verify_switch_state = bool::from(&props.input.action); + + let input_setter = props.argon2_input_setter.clone(); let input = props.input.clone(); - let get_hash_verify_switch_state = Callback::from(move |()| -> bool { (&input.action).into() }); - let hash_verify_switch_state = bool::from(&props.input.action); + let set_version = move |event: yew::html::onchange::Event| { + let html_element: HtmlInputElement = event.target_unchecked_into(); + let input = input.set_version(html_element.value().as_str().try_into().unwrap()); + input_setter.emit(input.clone()); + }; let input_setter = props.argon2_input_setter.clone(); let input = props.input.clone(); - let set_version = move |event: web_sys::Event| { - let target = event.target().expect("NO TARGET"); - let version: String = js_sys::Reflect::get(target.as_ref(), &"value".into()) - .unwrap() - .as_string() - .unwrap(); - let input = input.clone(); - let input = input.set_version(version.as_str().try_into().unwrap()); - log::debug!("{input:?}"); + let set_variant = move |event: yew::html::onchange::Event| { + let html_element: HtmlInputElement = event.target_unchecked_into(); + let input = input.set_variant(html_element.value().as_str().try_into().unwrap()); input_setter.emit(input.clone()); }; + + let data: Vec = props.input.data.clone(); html! {
    @@ -60,24 +78,20 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { {"verify"}
    {build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("argon2".into()))} - - { - if !get_hash_verify_switch_state.emit(()) { - html! { - <> - {"Version"} - - - } - } else { - html! { - - } - } - } + {if let Argon2Action::Hash(hash_action) = &props.input.action {html! { + <> + {build_byte_input(hash_action.salt.clone(), salt_setter, Some(BytesFormat::Ascii), Some("salt".into()))} + + + + }} else {html! {}}}
    } } From 0ddeefa1b04a7a2fe16d8c536c63bb7fceb2d5ee Mon Sep 17 00:00:00 2001 From: Jujumba Date: Tue, 27 Feb 2024 16:09:29 +0100 Subject: [PATCH 16/26] argon2: remove duplicate entries in the about page --- src/about.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/about.rs b/src/about.rs index a11de27d..f6557100 100644 --- a/src/about.rs +++ b/src/about.rs @@ -10,8 +10,6 @@ pub fn about() -> Html {
  • {"Argon2"}
  • {"BCrypt"}
  • {"MD5"}
  • -
  • {"Argon2"}
  • -
  • {"BCRYPT"}
  • {"SHA1/SHA256/SHA384/SHA512"}
  • {"Kerberos ciphers: AES128-CTS-HMAC-SHA1-96/AES256-CTS-HMAC-SHA1-96"}
  • {"Kerberos HMAC: HMAC-SHA1-96-AES128/HMAC-SHA1-96-AES256"}
  • From 7539d96b1c85b9bb01c2a3af71edfabb06f9967b Mon Sep 17 00:00:00 2001 From: Jujumba Date: Tue, 27 Feb 2024 16:15:03 +0100 Subject: [PATCH 17/26] argon2: remove extra `data` field --- src/crypto_helper/algorithm.rs | 3 --- src/crypto_helper/computations.rs | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index 6c9ba493..0cd14b60 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -385,8 +385,6 @@ pub struct Argon2HashAction { #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub salt: Vec, #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] - pub data: Vec, - #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub secret: Vec, pub variant: Argon2Variant, pub version: Argon2Version, @@ -480,7 +478,6 @@ impl Default for Argon2HashAction { paralelism: 1u32, output_len: 32usize, salt: Default::default(), - data: Default::default(), secret: Default::default(), variant: Default::default(), version: Default::default(), diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 0447951b..db6d3cc8 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -105,7 +105,6 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { hash_action.into(), ); - log::debug!("salt: {:?}", hash_action.salt); let b64 = if hash_action.salt.is_empty() { let mut rng = rand::rngs::StdRng::from_rng(rand::thread_rng()).unwrap(); let mut bytes = [0u8; 24]; @@ -119,7 +118,7 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { .map_err(|err| format!("Error while building salt: {err:?}"))?; let bytes: Vec = argon2ctx - .hash_password(&hash_action.data, salt) + .hash_password(&input.data, salt) .map(|pwd| pwd.hash.unwrap()) .map_err(|err| err.to_string())? .as_bytes() From 573d23a19ea538b94fa887a7e0087eee35f9d0b9 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Tue, 27 Feb 2024 21:47:55 +0100 Subject: [PATCH 18/26] argon2: fix random salt generation and base64 padding character --- Cargo.lock | 1 + Cargo.toml | 2 +- src/crypto_helper/computations.rs | 18 ++++++------------ 3 files changed, 8 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9026aff7..c1461df8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1946,6 +1946,7 @@ version = "0.9.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d31e63ea85be51c423e52ba8f2e68a3efd53eed30203ee029dd09947333693e" dependencies = [ + "rand_chacha 0.9.0-alpha.1", "rand_core 0.9.0-alpha.1", "zerocopy", ] diff --git a/Cargo.toml b/Cargo.toml index 31eef2d3..ff826fdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ hmac-sha512 = { version = "1.1", features = ["sha384"] } rsa = "0.9" bcrypt = "0.15" flate2 = { version = "1.0", features = ["zlib"] } -rand = { version = "0.9.0-alpha.0", default-features = false, features = ["small_rng"] } +rand = { version = "0.9.0-alpha.0", features = ["small_rng"] } rand_chacha = "0.9.0-alpha.0" argon2 = "0.5" password-hash = "0.5" diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index db6d3cc8..1c729495 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use std::io::Write; use argon2::{PasswordHasher, PasswordVerifier}; +use base64::Engine; use bcrypt::Version; use flate2::write::{ZlibDecoder, ZlibEncoder}; use flate2::Compression; @@ -95,8 +96,6 @@ pub fn process_zlib(input: &ZlibInput) -> Result, String> { } pub fn process_argon2(input: &Argon2Input) -> Result, String> { - use rand::RngCore; - match &input.action { Argon2Action::Hash(hash_action) => { let argon2ctx = argon2::Argon2::new( @@ -105,20 +104,15 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { hash_action.into(), ); - let b64 = if hash_action.salt.is_empty() { - let mut rng = rand::rngs::StdRng::from_rng(rand::thread_rng()).unwrap(); - let mut bytes = [0u8; 24]; - rng.fill_bytes(&mut bytes); - base64::encode(bytes) + let salt = if hash_action.salt.is_empty() { + password_hash::SaltString::generate(OsRng::default()) } else { - base64::encode(&hash_action.salt) + password_hash::SaltString::from_b64(&base64::engine::general_purpose::STANDARD_NO_PAD.encode(&hash_action.salt)) + .map_err(|e| e.to_string())? }; - let salt = argon2::password_hash::Salt::from_b64(&b64) - .map_err(|err| format!("Error while building salt: {err:?}"))?; - let bytes: Vec = argon2ctx - .hash_password(&input.data, salt) + .hash_password(&input.data, salt.as_salt()) .map(|pwd| pwd.hash.unwrap()) .map_err(|err| err.to_string())? .as_bytes() From bc4653181b3682e7128c91560646d343b871b3e0 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Tue, 27 Feb 2024 22:07:38 +0100 Subject: [PATCH 19/26] argon2: fix salt encoding & decoding --- src/crypto_helper/computations.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 1c729495..39c24e98 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -111,14 +111,13 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { .map_err(|e| e.to_string())? }; - let bytes: Vec = argon2ctx + // Returned hash is encoded in base64, though it's not explicit and obvious + let b64 = argon2ctx .hash_password(&input.data, salt.as_salt()) .map(|pwd| pwd.hash.unwrap()) - .map_err(|err| err.to_string())? - .as_bytes() - .into(); + .map_err(|err| err.to_string())?; - Ok(bytes) + Ok(base64::engine::general_purpose::STANDARD_NO_PAD.encode(b64.as_bytes()).into_bytes()) } Argon2Action::Verify(data) => { let hash: argon2::PasswordHash = std::str::from_utf8(data) From 2d0efbcd7b1e46e9af9de8487fbf42c4a3425f42 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sat, 16 Mar 2024 22:47:34 +0100 Subject: [PATCH 20/26] argon2: fix hash computation --- src/crypto_helper/computations.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 39c24e98..5a126bff 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -111,19 +111,17 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { .map_err(|e| e.to_string())? }; - // Returned hash is encoded in base64, though it's not explicit and obvious - let b64 = argon2ctx + let hash = argon2ctx .hash_password(&input.data, salt.as_salt()) - .map(|pwd| pwd.hash.unwrap()) - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string())?.to_string(); - Ok(base64::engine::general_purpose::STANDARD_NO_PAD.encode(b64.as_bytes()).into_bytes()) + Ok(hash.into_bytes()) } Argon2Action::Verify(data) => { - let hash: argon2::PasswordHash = std::str::from_utf8(data) - .map_err(|err| err.to_string())? - .try_into() - .map_err(|err: argon2::password_hash::Error| err.to_string())?; + let b64 = base64::engine::general_purpose::STANDARD_NO_PAD.encode(data); + + let hash = argon2::PasswordHash::parse(&b64, argon2::password_hash::Encoding::B64) + .map_err(|e| e.to_string())?; if argon2::Argon2::default().verify_password(data, &hash).is_ok() { Ok(vec![1]) From ebb2ea0e0bf4ed387ee5cce4931e858fcd733396 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sat, 16 Mar 2024 22:48:34 +0100 Subject: [PATCH 21/26] argon2: fix `Default` impl for `Argon2HashAction` --- src/crypto_helper/algorithm.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index 0cd14b60..ef3d3779 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -472,11 +472,12 @@ impl From<&Argon2HashAction> for argon2::Params { impl Default for Argon2HashAction { fn default() -> Self { + use argon2::Params; Self { - memory: 19456u32, - iters: 2u32, - paralelism: 1u32, - output_len: 32usize, + memory: Params::DEFAULT_M_COST, + iters: Params::DEFAULT_T_COST, + paralelism: Params::DEFAULT_P_COST, + output_len: Params::DEFAULT_OUTPUT_LEN, salt: Default::default(), secret: Default::default(), variant: Default::default(), From 191918f14c56865a84bb2097b7a7e7c3e3a037b8 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Fri, 22 Mar 2024 14:39:01 +0100 Subject: [PATCH 22/26] argon2: fix error types --- src/crypto_helper/algorithm.rs | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index ef3d3779..3795a167 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -395,6 +395,7 @@ pub enum Argon2Action { Hash(Argon2HashAction), Verify(#[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] Vec), } + #[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize, Default)] pub struct Argon2Input { pub action: Argon2Action, @@ -402,6 +403,23 @@ pub struct Argon2Input { pub data: Vec, } +#[non_exhaustive] +#[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] +pub enum Argon2Error<'a> { + InvalidVersion(&'a str), + InvalidVariant(&'a str), +} + +impl<'a> std::fmt::Display for Argon2Error<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::InvalidVersion(version) => write!(f, "InvalidVersion({version})"), + Self::InvalidVariant(variant) => write!(f, "InvalidVariant({variant})"), + } + } +} +impl<'a> std::error::Error for Argon2Error<'a> {} + impl Argon2Input { pub fn set_variant(&self, variant: Argon2Variant) -> Self { let mut input = self.clone(); @@ -419,13 +437,13 @@ impl Argon2Input { } } impl<'a> TryFrom<&'a str> for Argon2Version { - type Error = (); // todo: proper error type + type Error = Argon2Error<'a>; fn try_from(value: &'a str) -> Result { match value { "Argon13" => Ok(Self::Version13), "Argon10" => Ok(Self::Version10), - _ => Err(()), + invalid => Err(Argon2Error::InvalidVersion(invalid)), } } } @@ -438,14 +456,14 @@ impl From for argon2::Algorithm { } } } -impl TryFrom<&str> for Argon2Variant { - type Error = (); +impl<'a> TryFrom<&'a str> for Argon2Variant { + type Error = Argon2Error<'a>; fn try_from(value: &str) -> Result { match value { "Argon2i" => Ok(Self::Argon2i), "Argon2d" => Ok(Self::Argon2d), "Argon2id" => Ok(Self::Argon2id), - _ => Err(()), + invalid => Err(Argon2Error::InvalidVariant(invalid)), } } } From 0d463497974edd5627dd2612f36641fbac98a54d Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sat, 23 Mar 2024 17:23:57 +0100 Subject: [PATCH 23/26] argon2: fix --- src/crypto_helper/algorithm.rs | 12 ++++++++---- src/crypto_helper/input/argon2.rs | 6 +++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index 3795a167..a3282a30 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -363,6 +363,7 @@ pub struct ZlibInput { #[serde(serialize_with = "serialize_bytes", deserialize_with = "deserialize_bytes")] pub data: Vec, } + #[derive(Eq, Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Default)] pub enum Argon2Variant { Argon2i, @@ -370,12 +371,14 @@ pub enum Argon2Variant { #[default] Argon2id, } + #[derive(Eq, Clone, Copy, PartialEq, Debug, Serialize, Deserialize, Default)] pub enum Argon2Version { Version10, #[default] Version13, } + #[derive(Eq, Clone, PartialEq, Debug, Serialize, Deserialize)] pub struct Argon2HashAction { pub memory: u32, @@ -421,14 +424,15 @@ impl<'a> std::fmt::Display for Argon2Error<'a> { impl<'a> std::error::Error for Argon2Error<'a> {} impl Argon2Input { - pub fn set_variant(&self, variant: Argon2Variant) -> Self { + pub fn with_variant(&self, variant: Argon2Variant) -> Self { let mut input = self.clone(); if let Argon2Action::Hash(ref mut action) = input.action { action.variant = variant; } input } - pub fn set_version(&self, version: Argon2Version) -> Self { + + pub fn with_version(&self, version: Argon2Version) -> Self { let mut input = self.clone(); if let Argon2Action::Hash(ref mut action) = input.action { action.version = version; @@ -458,7 +462,7 @@ impl From for argon2::Algorithm { } impl<'a> TryFrom<&'a str> for Argon2Variant { type Error = Argon2Error<'a>; - fn try_from(value: &str) -> Result { + fn try_from(value: &'a str) -> Result { match value { "Argon2i" => Ok(Self::Argon2i), "Argon2d" => Ok(Self::Argon2d), @@ -484,7 +488,7 @@ impl From<&Argon2HashAction> for argon2::Params { .p_cost(value.paralelism) .t_cost(value.iters) .build() - .unwrap() + .expect("argon2::ParamsBuilder should never fail") } } diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs index 743e8524..42728f89 100644 --- a/src/crypto_helper/input/argon2.rs +++ b/src/crypto_helper/input/argon2.rs @@ -56,7 +56,7 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { let set_version = move |event: yew::html::onchange::Event| { let html_element: HtmlInputElement = event.target_unchecked_into(); - let input = input.set_version(html_element.value().as_str().try_into().unwrap()); + let input = input.with_version(html_element.value().as_str().try_into().unwrap()); input_setter.emit(input.clone()); }; @@ -65,7 +65,7 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { let set_variant = move |event: yew::html::onchange::Event| { let html_element: HtmlInputElement = event.target_unchecked_into(); - let input = input.set_variant(html_element.value().as_str().try_into().unwrap()); + let input = input.with_variant(html_element.value().as_str().try_into().unwrap()); input_setter.emit(input.clone()); }; @@ -77,7 +77,7 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { {"verify"} - {build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("argon2".into()))} + {build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("password".into()))} {if let Argon2Action::Hash(hash_action) = &props.input.action {html! { <> {build_byte_input(hash_action.salt.clone(), salt_setter, Some(BytesFormat::Ascii), Some("salt".into()))} From c8f1974881f89289cfccb82ea67e7b9fd513c84b Mon Sep 17 00:00:00 2001 From: Jujumba Date: Sun, 24 Mar 2024 00:18:22 +0100 Subject: [PATCH 24/26] argon2: add hash verification --- src/crypto_helper/computations.rs | 11 ++++--- src/crypto_helper/input/argon2.rs | 49 +++++++++++++++++++++---------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index 5a126bff..be7fd74f 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -113,17 +113,16 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { let hash = argon2ctx .hash_password(&input.data, salt.as_salt()) - .map_err(|err| err.to_string())?.to_string(); + .map_err(|err| err.to_string())? + .to_string(); Ok(hash.into_bytes()) } Argon2Action::Verify(data) => { - let b64 = base64::engine::general_purpose::STANDARD_NO_PAD.encode(data); + let str = String::from_utf8(data.clone()).map_err(|e| e.to_string())?; + let hash = argon2::PasswordHash::new(&str).map_err(|e| e.to_string())?; - let hash = argon2::PasswordHash::parse(&b64, argon2::password_hash::Encoding::B64) - .map_err(|e| e.to_string())?; - - if argon2::Argon2::default().verify_password(data, &hash).is_ok() { + if argon2::Argon2::default().verify_password(&input.data, &hash).is_ok() { Ok(vec![1]) } else { Ok(vec![0]) diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs index 42728f89..31eb7dff 100644 --- a/src/crypto_helper/input/argon2.rs +++ b/src/crypto_helper/input/argon2.rs @@ -19,7 +19,6 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { let input_setter = props.argon2_input_setter.clone(); let action: Argon2Action = props.input.action.clone(); let setter = Callback::from(move |data| { - log::debug!("setting data: {data:?}"); input_setter.emit(Argon2InputData { action: action.clone(), data, @@ -31,7 +30,6 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { let action: Argon2Action = props.input.action.clone(); let salt_setter = Callback::from(move |salt| { - log::debug!("setting salt with data: {data:?}"); if let Argon2Action::Hash(hash_action) = action.clone() { input_setter.emit(Argon2InputData { action: Argon2Action::Hash(Argon2HashAction { salt, ..hash_action }), @@ -40,6 +38,19 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { } }); + let data: Vec = props.input.data.clone(); + let input_setter = props.argon2_input_setter.clone(); + let action: Argon2Action = props.input.action.clone(); + + let hash_setter = Callback::from(move |hash: Vec| { + if let Argon2Action::Verify(_) = action.clone() { + input_setter.emit(Argon2InputData { + action: Argon2Action::Verify(hash), + data: data.clone(), + }) + } + }); + let input_setter = props.argon2_input_setter.clone(); let input = props.input.clone(); let on_hash_verify_switch = Callback::from(move |mode: bool| { @@ -78,20 +89,26 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { {"verify"} {build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("password".into()))} - {if let Argon2Action::Hash(hash_action) = &props.input.action {html! { - <> - {build_byte_input(hash_action.salt.clone(), salt_setter, Some(BytesFormat::Ascii), Some("salt".into()))} - - - - }} else {html! {}}} + {match &props.input.action { + Argon2Action::Hash(hash_action) => html! { + <> + {build_byte_input(hash_action.salt.clone(), salt_setter, Some(BytesFormat::Ascii), Some("salt".into()))} + + + + }, + Argon2Action::Verify(hash) => html! { + <> + {build_byte_input(hash.clone(), hash_setter, Some(BytesFormat::Ascii), Some("hash".into()))} + + }}} } } From 74fb406845dd97ba0d64a7e09ae063c6fdad4b91 Mon Sep 17 00:00:00 2001 From: Jujumba Date: Tue, 26 Mar 2024 22:31:20 +0100 Subject: [PATCH 25/26] argon2: run formatter --- src/crypto_helper.rs | 2 +- src/crypto_helper/algorithm.rs | 1 - src/crypto_helper/input/argon2.rs | 9 ++++----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/crypto_helper.rs b/src/crypto_helper.rs index 0e9e0dc2..d84e33fb 100644 --- a/src/crypto_helper.rs +++ b/src/crypto_helper.rs @@ -16,7 +16,7 @@ use yew::{function_component, html, use_effect_with, use_state, Callback, Html}; use yew_hooks::{use_clipboard, use_local_storage, use_location}; use yew_notifications::{use_notification, Notification, NotificationType}; -use self::computations::{process_krb_cipher, process_krb_hmac, process_rsa, process_zlib, process_argon2}; +use self::computations::{process_argon2, process_krb_cipher, process_krb_hmac, process_rsa, process_zlib}; use crate::crypto_helper::computations::process_bcrypt; use crate::url_query_params::generate_crypto_helper_link; diff --git a/src/crypto_helper/algorithm.rs b/src/crypto_helper/algorithm.rs index a3282a30..f1b873fc 100644 --- a/src/crypto_helper/algorithm.rs +++ b/src/crypto_helper/algorithm.rs @@ -338,7 +338,6 @@ pub enum ZlibMode { Compress, Decompress, } - impl From for bool { fn from(mode: ZlibMode) -> Self { match mode { diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs index 31eb7dff..26aa1132 100644 --- a/src/crypto_helper/input/argon2.rs +++ b/src/crypto_helper/input/argon2.rs @@ -1,10 +1,9 @@ use web_sys::HtmlInputElement; -use yew::{classes, function_component, html, html::TargetCast, Callback, Html, Properties}; +use yew::html::TargetCast; +use yew::{classes, function_component, html, Callback, Html, Properties}; -use crate::{ - common::{build_byte_input, BytesFormat, Switch}, - crypto_helper::algorithm::{Argon2Action, Argon2HashAction, Argon2Input as Argon2InputData}, -}; +use crate::common::{build_byte_input, BytesFormat, Switch}; +use crate::crypto_helper::algorithm::{Argon2Action, Argon2HashAction, Argon2Input as Argon2InputData}; #[derive(PartialEq, Properties, Clone)] pub struct Argon2InputProps { From 64e50b57a700a4915907ce5cb21568ae8fd7b580 Mon Sep 17 00:00:00 2001 From: Pavlo Myroniuk Date: Wed, 27 Mar 2024 13:16:32 +0200 Subject: [PATCH 26/26] feat(crypto-helper): update rust toolchain and inproved argon2 ui; --- rust-toolchain.toml | 2 +- src/crypto_helper/computations.rs | 8 +++++--- src/crypto_helper/input/argon2.rs | 26 +++++++++++++------------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 8336e05b..e89a6138 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.76.0" +channel = "1.77.0" components = [ "rustfmt", "clippy" ] diff --git a/src/crypto_helper/computations.rs b/src/crypto_helper/computations.rs index be7fd74f..bd4ec1df 100644 --- a/src/crypto_helper/computations.rs +++ b/src/crypto_helper/computations.rs @@ -105,10 +105,12 @@ pub fn process_argon2(input: &Argon2Input) -> Result, String> { ); let salt = if hash_action.salt.is_empty() { - password_hash::SaltString::generate(OsRng::default()) + password_hash::SaltString::generate(OsRng) } else { - password_hash::SaltString::from_b64(&base64::engine::general_purpose::STANDARD_NO_PAD.encode(&hash_action.salt)) - .map_err(|e| e.to_string())? + password_hash::SaltString::from_b64( + &base64::engine::general_purpose::STANDARD_NO_PAD.encode(&hash_action.salt), + ) + .map_err(|e| e.to_string())? }; let hash = argon2ctx diff --git a/src/crypto_helper/input/argon2.rs b/src/crypto_helper/input/argon2.rs index 26aa1132..15171bfe 100644 --- a/src/crypto_helper/input/argon2.rs +++ b/src/crypto_helper/input/argon2.rs @@ -13,8 +13,6 @@ pub struct Argon2InputProps { #[function_component(Argon2Input)] pub fn argon2_input(props: &Argon2InputProps) -> Html { - let data: Vec = props.input.data.clone(); - let input_setter = props.argon2_input_setter.clone(); let action: Argon2Action = props.input.action.clone(); let setter = Callback::from(move |data| { @@ -90,18 +88,20 @@ pub fn argon2_input(props: &Argon2InputProps) -> Html { {build_byte_input(data, setter, Some(BytesFormat::Ascii), Some("password".into()))} {match &props.input.action { Argon2Action::Hash(hash_action) => html! { - <> +
    {build_byte_input(hash_action.salt.clone(), salt_setter, Some(BytesFormat::Ascii), Some("salt".into()))} - - - +
    + + +
    +
    }, Argon2Action::Verify(hash) => html! { <>