summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-06-22 13:07:40 +0200
committerJustus Winter <justus@sequoia-pgp.org>2024-03-13 10:59:08 +0100
commit2170670fbbec94f923cd5c861f7225880e849d86 (patch)
treeac4e059c228989d7028a9c579828a88959e3f4e6
parentb36754f8c6d233b9df4ce9e1fc55e41d29c291d3 (diff)
openpgp: Implement SHA3.
- CNG doesn't currently implement this on commonly deployed installations. As this is not a high priority algorithm, we don't implement it using RustCrypto when the CNG backend is selected, but simply signal no support.
-rw-r--r--Cargo.lock20
-rw-r--r--openpgp/Cargo.toml2
-rw-r--r--openpgp/NEWS2
-rw-r--r--openpgp/src/crypto/backend/botan/hash.rs4
-rw-r--r--openpgp/src/crypto/backend/cng/hash.rs11
-rw-r--r--openpgp/src/crypto/backend/nettle/hash.rs8
-rw-r--r--openpgp/src/crypto/backend/openssl/hash.rs2
-rw-r--r--openpgp/src/crypto/backend/rust/hash.rs6
-rw-r--r--openpgp/src/crypto/hash.rs14
-rw-r--r--openpgp/src/policy.rs10
-rw-r--r--openpgp/src/types/mod.rs20
11 files changed, 95 insertions, 4 deletions
diff --git a/Cargo.lock b/Cargo.lock
index f9cb2069..da83576e 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1590,6 +1590,15 @@ dependencies = [
]
[[package]]
+name = "keccak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
+dependencies = [
+ "cpufeatures",
+]
+
+[[package]]
name = "lalrpop"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2684,6 +2693,7 @@ dependencies = [
"rust-argon2",
"sha1collisiondetection",
"sha2",
+ "sha3",
"thiserror",
"twofish",
"typenum",
@@ -2759,6 +2769,16 @@ dependencies = [
]
[[package]]
+name = "sha3"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
+dependencies = [
+ "digest",
+ "keccak",
+]
+
+[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml
index a74c1311..dc5547de 100644
--- a/openpgp/Cargo.toml
+++ b/openpgp/Cargo.toml
@@ -90,6 +90,7 @@ rand_core = { version = "0.6", optional = true }
ripemd = { version = "0.1", features = ["oid"], optional = true }
rsa = { version = "0.9.0", optional = true }
sha2 = { version = "0.10", features = ["oid"], optional = true }
+sha3 = { version = "0.10", features = ["oid"], optional = true }
twofish = { version = "0.7", optional = true, features = ["zeroize"] }
typenum = { version = "1.12.0", optional = true }
x25519-dalek = { version = "2", optional = true, default-features = false, features = ["static_secrets", "zeroize"] }
@@ -120,6 +121,7 @@ crypto-rust = [
"dep:cast5", "dep:cfb-mode", "dep:cipher", "dep:des", "dep:digest",
"dep:eax", "dep:ecb", "dep:ed25519", "dep:ed25519-dalek", "dep:idea",
"dep:md-5", "dep:num-bigint-dig", "dep:ripemd", "dep:rsa", "dep:sha2",
+ "dep:sha3",
"sha1collisiondetection/digest-trait", "sha1collisiondetection/oid",
"dep:twofish", "dep:typenum", "dep:x25519-dalek", "dep:p256",
"dep:rand", "rand?/getrandom", "dep:rand_core", "rand_core?/getrandom",
diff --git a/openpgp/NEWS b/openpgp/NEWS
index 06ea3106..cfef24c0 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -12,6 +12,8 @@
We have also used the opportunity to clean up our API. Most
programs should only require minor adjustments.
** New functionality
+ - HashAlgorithm::SHA3_256
+ - HashAlgorithm::SHA3_512
* Changes in 1.19.0
** Notable fixes
- Key4::import_secret_cv25519 will now clamp some bits of the given
diff --git a/openpgp/src/crypto/backend/botan/hash.rs b/openpgp/src/crypto/backend/botan/hash.rs
index 0e02b5dd..7f5934e3 100644
--- a/openpgp/src/crypto/backend/botan/hash.rs
+++ b/openpgp/src/crypto/backend/botan/hash.rs
@@ -48,6 +48,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA256 => true,
HashAlgorithm::SHA384 => true,
HashAlgorithm::SHA512 => true,
+ HashAlgorithm::SHA3_256 => true,
+ HashAlgorithm::SHA3_512 => true,
HashAlgorithm::RipeMD => true,
HashAlgorithm::MD5 => true,
HashAlgorithm::Private(_) => false,
@@ -82,6 +84,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA256 => Ok("SHA-256"),
HashAlgorithm::SHA384 => Ok("SHA-384"),
HashAlgorithm::SHA512 => Ok("SHA-512"),
+ HashAlgorithm::SHA3_256 => Ok("SHA-3(256)"),
+ HashAlgorithm::SHA3_512 => Ok("SHA-3(512)"),
HashAlgorithm::MD5 => Ok("MD5"),
HashAlgorithm::RipeMD => Ok("RIPEMD-160"),
HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) =>
diff --git a/openpgp/src/crypto/backend/cng/hash.rs b/openpgp/src/crypto/backend/cng/hash.rs
index 301ac0c6..e71789d1 100644
--- a/openpgp/src/crypto/backend/cng/hash.rs
+++ b/openpgp/src/crypto/backend/cng/hash.rs
@@ -84,6 +84,12 @@ impl TryFrom<HashAlgorithm> for cng::HashAlgorithmId {
HashAlgorithm::SHA512 => cng::HashAlgorithmId::Sha512,
HashAlgorithm::MD5 => cng::HashAlgorithmId::Md5,
+ // SHA3 support is on the horizon, see
+ // https://blogs.windows.com/windows-insider/2023/03/23/announcing-windows-11-insider-preview-build-25324/
+ HashAlgorithm::SHA3_256 |
+ HashAlgorithm::SHA3_512 =>
+ return Err(Error::UnsupportedHashAlgorithm(value)),
+
HashAlgorithm::SHA224 |
HashAlgorithm::RipeMD |
HashAlgorithm::Private(_) |
@@ -119,6 +125,11 @@ impl HashAlgorithm {
HashAlgorithm::SHA512 => true,
HashAlgorithm::MD5 => true,
+ // SHA3 support is on the horizon, see
+ // https://blogs.windows.com/windows-insider/2023/03/23/announcing-windows-11-insider-preview-build-25324/
+ HashAlgorithm::SHA3_256 |
+ HashAlgorithm::SHA3_512 => false,
+
HashAlgorithm::SHA224 |
HashAlgorithm::RipeMD |
HashAlgorithm::Private(_) |
diff --git a/openpgp/src/crypto/backend/nettle/hash.rs b/openpgp/src/crypto/backend/nettle/hash.rs
index 4bf1535e..3e9d12a6 100644
--- a/openpgp/src/crypto/backend/nettle/hash.rs
+++ b/openpgp/src/crypto/backend/nettle/hash.rs
@@ -29,6 +29,8 @@ impl_digest_for!(nettle::hash::Sha224, SHA224);
impl_digest_for!(nettle::hash::Sha256, SHA256);
impl_digest_for!(nettle::hash::Sha384, SHA384);
impl_digest_for!(nettle::hash::Sha512, SHA512);
+impl_digest_for!(nettle::hash::Sha3_256, SHA3_256);
+impl_digest_for!(nettle::hash::Sha3_512, SHA3_512);
impl_digest_for!(nettle::hash::insecure_do_not_use::Sha1, SHA1);
impl_digest_for!(nettle::hash::insecure_do_not_use::Md5, MD5);
impl_digest_for!(nettle::hash::insecure_do_not_use::Ripemd160, RipeMD);
@@ -42,6 +44,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA256 => true,
HashAlgorithm::SHA384 => true,
HashAlgorithm::SHA512 => true,
+ HashAlgorithm::SHA3_256 => true,
+ HashAlgorithm::SHA3_512 => true,
HashAlgorithm::RipeMD => true,
HashAlgorithm::MD5 => true,
HashAlgorithm::Private(_) => false,
@@ -59,7 +63,7 @@ impl HashAlgorithm {
///
/// [`HashAlgorithm::is_supported`]: HashAlgorithm::is_supported()
pub(crate) fn new_hasher(self) -> Result<Box<dyn Digest>> {
- use nettle::hash::{Sha224, Sha256, Sha384, Sha512};
+ use nettle::hash::{Sha224, Sha256, Sha384, Sha512, Sha3_256, Sha3_512};
use nettle::hash::insecure_do_not_use::{
Sha1,
Md5,
@@ -72,6 +76,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA256 => Ok(Box::new(Sha256::default())),
HashAlgorithm::SHA384 => Ok(Box::new(Sha384::default())),
HashAlgorithm::SHA512 => Ok(Box::new(Sha512::default())),
+ HashAlgorithm::SHA3_256 => Ok(Box::new(Sha3_256::default())),
+ HashAlgorithm::SHA3_512 => Ok(Box::new(Sha3_512::default())),
HashAlgorithm::MD5 => Ok(Box::new(Md5::default())),
HashAlgorithm::RipeMD => Ok(Box::new(Ripemd160::default())),
HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) =>
diff --git a/openpgp/src/crypto/backend/openssl/hash.rs b/openpgp/src/crypto/backend/openssl/hash.rs
index b4f6d816..e8db9373 100644
--- a/openpgp/src/crypto/backend/openssl/hash.rs
+++ b/openpgp/src/crypto/backend/openssl/hash.rs
@@ -73,6 +73,8 @@ fn get_md(algo: HashAlgorithm) -> Option<MessageDigest> {
SHA384 => Nid::SHA384,
SHA512 => Nid::SHA512,
SHA224 => Nid::SHA224,
+ SHA3_256 => Nid::SHA3_256,
+ SHA3_512 => Nid::SHA3_512,
HashAlgorithm::Private(_) |
HashAlgorithm::Unknown(_) => return None,
};
diff --git a/openpgp/src/crypto/backend/rust/hash.rs b/openpgp/src/crypto/backend/rust/hash.rs
index 069dfc79..ed3a3704 100644
--- a/openpgp/src/crypto/backend/rust/hash.rs
+++ b/openpgp/src/crypto/backend/rust/hash.rs
@@ -37,6 +37,8 @@ impl_digest_for!(sha2::Sha224, SHA224);
impl_digest_for!(sha2::Sha256, SHA256);
impl_digest_for!(sha2::Sha384, SHA384);
impl_digest_for!(sha2::Sha512, SHA512);
+impl_digest_for!(sha3::Sha3_256, SHA3_256);
+impl_digest_for!(sha3::Sha3_512, SHA3_512);
impl HashAlgorithm {
/// Whether Sequoia supports this algorithm.
@@ -47,6 +49,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA256 => true,
HashAlgorithm::SHA384 => true,
HashAlgorithm::SHA512 => true,
+ HashAlgorithm::SHA3_256 => true,
+ HashAlgorithm::SHA3_512 => true,
HashAlgorithm::RipeMD => true,
HashAlgorithm::MD5 => true,
HashAlgorithm::Private(_) => false,
@@ -73,6 +77,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA256 => Ok(Box::new(sha2::Sha256::new())),
HashAlgorithm::SHA384 => Ok(Box::new(sha2::Sha384::new())),
HashAlgorithm::SHA512 => Ok(Box::new(sha2::Sha512::new())),
+ HashAlgorithm::SHA3_256 => Ok(Box::new(sha3::Sha3_256::new())),
+ HashAlgorithm::SHA3_512 => Ok(Box::new(sha3::Sha3_512::new())),
HashAlgorithm::RipeMD => Ok(Box::new(ripemd::Ripemd160::new())),
HashAlgorithm::MD5 => Ok(Box::new(md5::Md5::new())),
HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) =>
diff --git a/openpgp/src/crypto/hash.rs b/openpgp/src/crypto/hash.rs
index 79a31f8a..7bd9a9e1 100644
--- a/openpgp/src/crypto/hash.rs
+++ b/openpgp/src/crypto/hash.rs
@@ -96,6 +96,18 @@ const ASN1_OID_SHA512: &[u8] = &[
0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40,
];
+/// ASN.1 OID for SHA3-256
+const ASN1_OID_SHA3_256: &[u8] = &[
+ 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x08, 0x05, 0x00, 0x04, 0x20
+];
+
+/// ASN.1 OID for SHA3-512.
+const ASN1_OID_SHA3_512: &[u8] = &[
+ 0x30, 0x51, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x0a, 0x05, 0x00, 0x04, 0x40
+];
+
lazy_static::lazy_static! {
/// List of hashes that the signer may produce.
/// This list is ordered by the preference so that the most preferred
@@ -234,6 +246,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA256 => Ok(ASN1_OID_SHA256),
HashAlgorithm::SHA384 => Ok(ASN1_OID_SHA384),
HashAlgorithm::SHA512 => Ok(ASN1_OID_SHA512),
+ HashAlgorithm::SHA3_256 => Ok(ASN1_OID_SHA3_256),
+ HashAlgorithm::SHA3_512 => Ok(ASN1_OID_SHA3_512),
HashAlgorithm::MD5 => Ok(ASN1_OID_MD5),
HashAlgorithm::RipeMD => Ok(ASN1_OID_RIPEMD160),
HashAlgorithm::Private(_) | HashAlgorithm::Unknown(_) =>
diff --git a/openpgp/src/policy.rs b/openpgp/src/policy.rs
index 9ea4fcb2..0ed9b919 100644
--- a/openpgp/src/policy.rs
+++ b/openpgp/src/policy.rs
@@ -626,7 +626,7 @@ impl<'a> From<&'a StandardPolicy<'a>> for Option<&'a dyn Policy> {
// Signatures that require a hash with collision Resistance and second
// Pre-image Resistance. See the documentation for HashAlgoSecurity
// for more details.
-a_cutoff_list!(CollisionResistantHashCutoffList, HashAlgorithm, 12,
+a_cutoff_list!(CollisionResistantHashCutoffList, HashAlgorithm, 15,
[
REJECT, // 0. Not assigned.
Some(Timestamp::Y1997M2), // 1. MD5
@@ -640,11 +640,14 @@ a_cutoff_list!(CollisionResistantHashCutoffList, HashAlgorithm, 12,
ACCEPT, // 9. SHA384
ACCEPT, // 10. SHA512
ACCEPT, // 11. SHA224
+ ACCEPT, // 12. SHA3-256
+ REJECT, // 13. Reserved.
+ ACCEPT, // 14. SHA3-512
]);
// Signatures that *only* require a hash with Second Pre-image
// Resistance. See the documentation for HashAlgoSecurity for more
// details.
-a_cutoff_list!(SecondPreImageResistantHashCutoffList, HashAlgorithm, 12,
+a_cutoff_list!(SecondPreImageResistantHashCutoffList, HashAlgorithm, 15,
[
REJECT, // 0. Not assigned.
Some(Timestamp::Y2004M2), // 1. MD5
@@ -658,6 +661,9 @@ a_cutoff_list!(SecondPreImageResistantHashCutoffList, HashAlgorithm, 12,
ACCEPT, // 9. SHA384
ACCEPT, // 10. SHA512
ACCEPT, // 11. SHA224
+ ACCEPT, // 12. SHA3-256
+ REJECT, // 13. Reserved.
+ ACCEPT, // 14. SHA3-512
]);
a_cutoff_list!(SubpacketTagCutoffList, SubpacketTag, 38,
diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs
index 50813cc7..6caea951 100644
--- a/openpgp/src/types/mod.rs
+++ b/openpgp/src/types/mod.rs
@@ -1339,6 +1339,10 @@ pub enum HashAlgorithm {
SHA512,
/// 224-bit version of SHA2
SHA224,
+ /// 256-bit version of SHA3
+ SHA3_256,
+ /// 512-bit version of SHA3
+ SHA3_512,
/// Private hash algorithm identifier.
Private(u8),
/// Unknown hash algorithm identifier.
@@ -1346,7 +1350,7 @@ pub enum HashAlgorithm {
}
assert_send_and_sync!(HashAlgorithm);
-const HASH_ALGORITHM_VARIANTS: [HashAlgorithm; 7] = [
+const HASH_ALGORITHM_VARIANTS: [HashAlgorithm; 9] = [
HashAlgorithm::MD5,
HashAlgorithm::SHA1,
HashAlgorithm::RipeMD,
@@ -1354,6 +1358,8 @@ const HASH_ALGORITHM_VARIANTS: [HashAlgorithm; 7] = [
HashAlgorithm::SHA384,
HashAlgorithm::SHA512,
HashAlgorithm::SHA224,
+ HashAlgorithm::SHA3_256,
+ HashAlgorithm::SHA3_512,
];
impl Default for HashAlgorithm {
@@ -1374,6 +1380,8 @@ impl From<u8> for HashAlgorithm {
9 => HashAlgorithm::SHA384,
10 => HashAlgorithm::SHA512,
11 => HashAlgorithm::SHA224,
+ 12 => HashAlgorithm::SHA3_256,
+ 14 => HashAlgorithm::SHA3_512,
100..=110 => HashAlgorithm::Private(u),
u => HashAlgorithm::Unknown(u),
}
@@ -1390,6 +1398,8 @@ impl From<HashAlgorithm> for u8 {
HashAlgorithm::SHA384 => 9,
HashAlgorithm::SHA512 => 10,
HashAlgorithm::SHA224 => 11,
+ HashAlgorithm::SHA3_256 => 12,
+ HashAlgorithm::SHA3_512 => 14,
HashAlgorithm::Private(u) => u,
HashAlgorithm::Unknown(u) => u,
}
@@ -1414,6 +1424,10 @@ impl FromStr for HashAlgorithm {
Ok(HashAlgorithm::SHA512)
} else if s.eq_ignore_ascii_case("SHA224") {
Ok(HashAlgorithm::SHA224)
+ } else if s.eq_ignore_ascii_case("SHA3-256") {
+ Ok(HashAlgorithm::SHA3_256)
+ } else if s.eq_ignore_ascii_case("SHA3-512") {
+ Ok(HashAlgorithm::SHA3_512)
} else {
Err(())
}
@@ -1430,6 +1444,8 @@ impl fmt::Display for HashAlgorithm {
HashAlgorithm::SHA384 => f.write_str("SHA384"),
HashAlgorithm::SHA512 => f.write_str("SHA512"),
HashAlgorithm::SHA224 => f.write_str("SHA224"),
+ HashAlgorithm::SHA3_256 => f.write_str("SHA3-256"),
+ HashAlgorithm::SHA3_512 => f.write_str("SHA3-512"),
HashAlgorithm::Private(u) =>
f.write_fmt(format_args!("Private/Experimental hash algorithm {}", u)),
HashAlgorithm::Unknown(u) =>
@@ -1466,6 +1482,8 @@ impl HashAlgorithm {
HashAlgorithm::SHA384 => Ok("SHA384"),
HashAlgorithm::SHA512 => Ok("SHA512"),
HashAlgorithm::SHA224 => Ok("SHA224"),
+ HashAlgorithm::SHA3_256 => Ok("SHA3-256"),
+ HashAlgorithm::SHA3_512 => Ok("SHA3-512"),
HashAlgorithm::Private(_) =>
Err(Error::UnsupportedHashAlgorithm(*self).into()),
HashAlgorithm::Unknown(_) =>