summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-06-26 13:27:20 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-06-26 13:27:20 +0200
commitf44e788d7aefc1f781b17798115849b88cc6aa5a (patch)
tree521c94432a324bbc8a0a0a91f019d6c0e7ccd326
parentc4397071a3b72f64ba73e770cdbe72255abddbc6 (diff)
parent4a3175477712f889db04dbf9061231d109f0fc9c (diff)
Merge branch 'crypto-refresh-argon2' into crypto-refresh
-rw-r--r--Cargo.lock60
-rw-r--r--openpgp/Cargo.toml1
-rw-r--r--openpgp/src/crypto/s2k.rs56
-rw-r--r--openpgp/src/parse.rs12
-rw-r--r--openpgp/src/serialize.rs6
5 files changed, 130 insertions, 5 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 60a8724b..19ddf72d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -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),