diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-06-26 13:27:20 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2023-06-26 13:27:20 +0200 |
commit | f44e788d7aefc1f781b17798115849b88cc6aa5a (patch) | |
tree | 521c94432a324bbc8a0a0a91f019d6c0e7ccd326 | |
parent | c4397071a3b72f64ba73e770cdbe72255abddbc6 (diff) | |
parent | 4a3175477712f889db04dbf9061231d109f0fc9c (diff) |
Merge branch 'crypto-refresh-argon2' into crypto-refresh
-rw-r--r-- | Cargo.lock | 60 | ||||
-rw-r--r-- | openpgp/Cargo.toml | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/s2k.rs | 56 | ||||
-rw-r--r-- | openpgp/src/parse.rs | 12 | ||||
-rw-r--r-- | openpgp/src/serialize.rs | 6 |
5 files changed, 130 insertions, 5 deletions
@@ -65,6 +65,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] name = "ascii-canvas" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -109,6 +121,12 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" @@ -161,6 +179,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq 0.2.5", +] + +[[package]] name = "block-buffer" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -435,6 +464,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "constant_time_eq" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" + +[[package]] name = "core-foundation" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2179,6 +2220,18 @@ dependencies = [ ] [[package]] +name = "rust-argon2" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50162d19404029c1ceca6f6980fe40d45c8b369f6f44446fa14bb39573b5bb9" +dependencies = [ + "base64 0.13.1", + "blake2b_simd", + "constant_time_eq 0.1.5", + "crossbeam-utils", +] + +[[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2275,7 +2328,7 @@ dependencies = [ name = "sequoia-autocrypt" version = "0.25.1" dependencies = [ - "base64", + "base64 0.21.0", "sequoia-openpgp", ] @@ -2321,7 +2374,7 @@ name = "sequoia-net" version = "0.27.0" dependencies = [ "anyhow", - "base64", + "base64 0.21.0", "futures-util", "http", "hyper", @@ -2347,7 +2400,7 @@ dependencies = [ "aes", "aes-gcm", "anyhow", - "base64", + "base64 0.21.0", "block-padding", "blowfish", "botan", @@ -2393,6 +2446,7 @@ dependencies = [ "ripemd", "rpassword", "rsa", + "rust-argon2", "sha-1", "sha1collisiondetection", "sha2 0.10.6", diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml index 4d2f1ae6..523086b1 100644 --- a/openpgp/Cargo.toml +++ b/openpgp/Cargo.toml @@ -45,6 +45,7 @@ nettle = { version = "7.3", optional = true } once_cell = "1" regex = "1" regex-syntax = "0.6" +rust-argon2 = "1" sha1collisiondetection = { version = "0.2.3", default-features = false, features = ["std"] } thiserror = "1.0.2" xxhash-rust = { version = "0.8", features = ["xxh3"] } diff --git a/openpgp/src/crypto/s2k.rs b/openpgp/src/crypto/s2k.rs index 9b7c24d6..1717caff 100644 --- a/openpgp/src/crypto/s2k.rs +++ b/openpgp/src/crypto/s2k.rs @@ -6,6 +6,8 @@ //! //! [Section 3.7 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-3.7 +use std::convert::TryInto; + use crate::Error; use crate::Result; use crate::HashAlgorithm; @@ -35,6 +37,18 @@ use quickcheck::{Arbitrary, Gen}; #[non_exhaustive] #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub enum S2K { + /// Argon2 Memory-Hard Password Hashing Function. + Argon2 { + /// The salt. + salt: [u8; 16], + /// Number of passes. + t: u8, + /// Degree of parallelism. + p: u8, + /// Exponent of memory size. + m: u8, + }, + /// Repeatently hashes the password with a public `salt` value. Iterated { /// Hash used for key derivation. @@ -167,6 +181,27 @@ impl S2K { -> Result<SessionKey> { #[allow(deprecated)] match self { + &S2K::Argon2 { salt, t, p, m, } => { + let config = argon2::Config { + time_cost: t.into(), + lanes: p.into(), + mem_cost: 2u32.checked_pow(m.into()) + .ok_or_else(|| Error::InvalidArgument( + format!("Argon2 memory parameter out of bounds: {}", + m)))?, + hash_length: key_size.try_into() + .map_err(|_| Error::InvalidArgument( + format!("key size parameter out of bounds: {}", + key_size)))?, + thread_mode: argon2::ThreadMode::Parallel, + variant: argon2::Variant::Argon2id, + ..argon2::Config::default() + }; + password.map(|password| { + Ok(argon2::hash_raw(password, &salt, &config)? + .into()) + }) + }, &S2K::Simple { hash } | &S2K::Salted { hash, .. } | &S2K::Iterated { hash, .. } => password.map(|string| { let mut hash = hash.context()?; @@ -183,6 +218,7 @@ impl S2K { hash.update(&zeros[..]); match self { + &S2K::Argon2 { .. } => unreachable!("handled above"), &S2K::Simple { .. } => { hash.update(string); } @@ -248,6 +284,7 @@ impl S2K { Simple { .. } | Salted { .. } | Iterated { .. } + | Argon2 { .. } => true, S2K::Private { .. } | S2K::Unknown { .. } @@ -353,6 +390,11 @@ impl fmt::Display for S2K { salt[4], salt[5], salt[6], salt[7], hash_bytes)) } + S2K::Argon2 { salt, t, p, m, } => { + write!(f, + "Argon2id with t: {}, p: {}, m: 2^{}, salt: {}", + t, p, m, crate::fmt::hex::encode(salt)) + }, S2K::Private { tag, parameters } => if let Some(p) = parameters.as_ref() { write!(f, "Private/Experimental S2K {}:{:?}", tag, p) @@ -375,7 +417,7 @@ impl Arbitrary for S2K { use crate::arbitrary_helper::*; #[allow(deprecated)] - match gen_arbitrary_from_range(0..7, g) { + match gen_arbitrary_from_range(0..8, g) { 0 => S2K::Simple{ hash: HashAlgorithm::arbitrary(g) }, 1 => S2K::Salted{ hash: HashAlgorithm::arbitrary(g), @@ -394,6 +436,16 @@ impl Arbitrary for S2K { }, hash_bytes: S2K::nearest_hash_count(Arbitrary::arbitrary(g)), }, + 7 => S2K::Argon2 { + salt: { + let mut salt = [0u8; 16]; + arbitrary_slice(g, &mut salt); + salt + }, + t: Arbitrary::arbitrary(g), + p: Arbitrary::arbitrary(g), + m: Arbitrary::arbitrary(g), + }, 3 => S2K::Private { tag: gen_arbitrary_from_range(100..111, g), parameters: Some(arbitrary_bounded_vec(g, 200).into()), @@ -403,7 +455,7 @@ impl Arbitrary for S2K { parameters: Some(arbitrary_bounded_vec(g, 200).into()), }, 5 => S2K::Unknown { - tag: gen_arbitrary_from_range(4..100, g), + tag: gen_arbitrary_from_range(5..100, g), parameters: Some(arbitrary_bounded_vec(g, 200).into()), }, 6 => S2K::Unknown { diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs index aa112630..894bfb89 100644 --- a/openpgp/src/parse.rs +++ b/openpgp/src/parse.rs @@ -1157,6 +1157,18 @@ impl S2K { hash_bytes: S2K::decode_count(php.parse_u8("s2k_count")?), } }, + 4 => S2K::Argon2 { + salt: { + let mut b = [0u8; 16]; + let b_len = b.len(); + b.copy_from_slice( + &php.parse_bytes("argon2_salt", b_len)?); + b + }, + t: php.parse_u8("argon2_t")?, + p: php.parse_u8("argon2_p")?, + m: php.parse_u8("argon2_m")?, + }, 100..=110 => S2K::Private { tag: s2k, parameters: if let Some(l) = s2k_len { diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs index 4d7b4466..846a3c72 100644 --- a/openpgp/src/serialize.rs +++ b/openpgp/src/serialize.rs @@ -1329,6 +1329,11 @@ impl Marshal for S2K { w.write_all(&salt[..])?; w.write_all(&[S2K::encode_count(hash_bytes)?])?; } + S2K::Argon2 { salt, t, p, m, } => { + w.write_all(&[4])?; + w.write_all(salt)?; + w.write_all(&[*t, *p, *m])?; + }, S2K::Private { tag, parameters } | S2K::Unknown { tag, parameters} => { w.write_all(&[*tag])?; @@ -1349,6 +1354,7 @@ impl MarshalInto for S2K { &S2K::Simple{ .. } => 2, &S2K::Salted{ .. } => 2 + 8, &S2K::Iterated{ .. } => 2 + 8 + 1, + S2K::Argon2 { .. } => 20, S2K::Private { parameters, .. } | S2K::Unknown { parameters, .. } => 1 + parameters.as_ref().map(|p| p.len()).unwrap_or(0), |