diff options
Diffstat (limited to 'openpgp')
-rw-r--r-- | openpgp/Cargo.toml | 6 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/botan.rs | 5 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/botan/kdf.rs | 31 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/cng.rs | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/cng/kdf.rs | 20 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/interface.rs | 23 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle.rs | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/nettle/kdf.rs | 25 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/openssl.rs | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/openssl/kdf.rs | 31 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/rust.rs | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/rust/kdf.rs | 20 |
12 files changed, 161 insertions, 4 deletions
diff --git a/openpgp/Cargo.toml b/openpgp/Cargo.toml index 22f91b19..49bf4452 100644 --- a/openpgp/Cargo.toml +++ b/openpgp/Cargo.toml @@ -81,6 +81,8 @@ ecdsa = { version = "0.16", optional = true, features = ["hazmat", "arithmetic"] # std::error::Error. ed25519 = { version = "2", default-features = false, features = ["std"], optional = true } ed25519-dalek = { version = "2", features = ["rand_core", "zeroize"], optional = true } +generic-array = { version = "0.14.4", optional = true } +hkdf = { version = "0.12", optional = true } idea = { version = "0.5", optional = true, features = ["zeroize"] } md-5 = { version = "0.10", features = ["oid"], optional = true } num-bigint-dig = { version = "0.8", default-features = false, optional = true } @@ -119,11 +121,11 @@ crypto-rust = [ "md-5", "num-bigint-dig", "ripemd", "rsa", "sha2", "sha1collisiondetection/digest-trait", "sha1collisiondetection/oid", "twofish", "typenum", "x25519-dalek", "p256", - "rand_core", "rand_core/getrandom", "ecdsa", "aes-gcm", "dsa" + "rand_core", "rand_core/getrandom", "ecdsa", "aes-gcm", "dsa", "hkdf" ] crypto-cng = [ "cipher", "eax", "winapi", "win-crypto-ng", "ed25519", "ed25519-dalek", - "num-bigint-dig", "aes-gcm", "rand_core" + "num-bigint-dig", "aes-gcm", "rand_core", "hkdf", "sha2" ] crypto-openssl = ["openssl", "openssl-sys"] crypto-botan = ["botan/botan3"] diff --git a/openpgp/src/crypto/backend/botan.rs b/openpgp/src/crypto/backend/botan.rs index 3f1ab906..568802de 100644 --- a/openpgp/src/crypto/backend/botan.rs +++ b/openpgp/src/crypto/backend/botan.rs @@ -1,11 +1,14 @@ //! Implementation of Sequoia crypto API using the Botan cryptographic library. -use crate::types::*; +use crate::{ + types::*, +}; pub mod aead; pub mod asymmetric; pub mod ecdh; pub mod hash; +pub mod kdf; pub mod symmetric; pub struct Backend(()); diff --git a/openpgp/src/crypto/backend/botan/kdf.rs b/openpgp/src/crypto/backend/botan/kdf.rs new file mode 100644 index 00000000..942165e2 --- /dev/null +++ b/openpgp/src/crypto/backend/botan/kdf.rs @@ -0,0 +1,31 @@ +use crate::{ + Result, + crypto::{ + SessionKey, + backend::interface::Kdf, + }, +}; + +impl Kdf for super::Backend { + fn hkdf_sha256(ikm: &SessionKey, salt: Option<&[u8]>, info: &[u8], + okm: &mut SessionKey) + -> Result<()> + { + assert!(okm.len() <= 255 * 32); + + const NO_SALT: [u8; 32] = [0; 32]; + let salt = salt.unwrap_or(&NO_SALT); + + // XXX: It'd be nice to write that directly to `okm`, but botan-rs + // does not have such an interface. + let okm_heap: SessionKey = + botan::kdf("HKDF(SHA-256)", okm.len(), &*ikm, salt, info)? + .into(); + + // XXX: Now copy the secret. + let l = okm.len().min(okm_heap.len()); + okm[..l].copy_from_slice(&okm_heap[..l]); + + Ok(()) + } +} diff --git a/openpgp/src/crypto/backend/cng.rs b/openpgp/src/crypto/backend/cng.rs index 9f43958f..557a34c3 100644 --- a/openpgp/src/crypto/backend/cng.rs +++ b/openpgp/src/crypto/backend/cng.rs @@ -8,6 +8,7 @@ pub mod aead; pub mod asymmetric; pub mod ecdh; pub mod hash; +pub mod kdf; pub mod symmetric; pub struct Backend(()); diff --git a/openpgp/src/crypto/backend/cng/kdf.rs b/openpgp/src/crypto/backend/cng/kdf.rs new file mode 100644 index 00000000..ac98a496 --- /dev/null +++ b/openpgp/src/crypto/backend/cng/kdf.rs @@ -0,0 +1,20 @@ +use hkdf::Hkdf; +use sha2::Sha256; + +use crate::{ + Result, + crypto::{ + SessionKey, + backend::interface::Kdf, + }, +}; + +impl Kdf for super::Backend { + fn hkdf_sha256(ikm: &SessionKey, salt: Option<&[u8]>, info: &[u8], + okm: &mut SessionKey) + -> Result<()> + { + Ok(Hkdf::<Sha256>::new(salt, &ikm).expand(info, okm) + .map_err(|e| crate::Error::InvalidOperation(e.to_string()))?) + } +} diff --git a/openpgp/src/crypto/backend/interface.rs b/openpgp/src/crypto/backend/interface.rs index bf6f876a..bc7c7f4b 100644 --- a/openpgp/src/crypto/backend/interface.rs +++ b/openpgp/src/crypto/backend/interface.rs @@ -4,6 +4,7 @@ use crate::{ Error, Result, crypto::{ + SessionKey, mem::Protected, mpi::{MPI, ProtectedMPI}, }, @@ -11,7 +12,7 @@ use crate::{ }; /// Abstracts over the cryptographic backends. -pub trait Backend: Asymmetric { +pub trait Backend: Asymmetric + Kdf { /// Returns a short, human-readable description of the backend. /// /// This starts with the name of the backend, possibly a version, @@ -105,3 +106,23 @@ mod tests { assert_ne!(secret.as_ref(), public); } } + +/// Key-Derivation-Functions. +pub trait Kdf { + /// HKDF instantiated with SHA256. + /// + /// Used to derive message keys from session keys, and key + /// encapsulating keys from S2K mechanisms. In both cases, using + /// a KDF that includes algorithm information in the given `info` + /// provides key space separation between cipher algorithms and + /// modes. + /// + /// `salt`, if given, SHOULD be 32 bytes of salt matching the + /// digest size of the hash function. If it is not give, 32 zeros + /// are used instead. + /// + /// `okm` must not be larger than 255 * 32 (the size of the hash + /// digest). + fn hkdf_sha256(ikm: &SessionKey, salt: Option<&[u8]>, info: &[u8], + okm: &mut SessionKey) -> Result<()>; +} diff --git a/openpgp/src/crypto/backend/nettle.rs b/openpgp/src/crypto/backend/nettle.rs index c0cb767f..04fef2eb 100644 --- a/openpgp/src/crypto/backend/nettle.rs +++ b/openpgp/src/crypto/backend/nettle.rs @@ -8,6 +8,7 @@ pub mod aead; pub mod asymmetric; pub mod ecdh; pub mod hash; +pub mod kdf; pub mod symmetric; pub struct Backend(()); diff --git a/openpgp/src/crypto/backend/nettle/kdf.rs b/openpgp/src/crypto/backend/nettle/kdf.rs new file mode 100644 index 00000000..a016a3a3 --- /dev/null +++ b/openpgp/src/crypto/backend/nettle/kdf.rs @@ -0,0 +1,25 @@ +use nettle::{ + kdf::hkdf, + hash::Sha256, +}; + +use crate::{ + Result, + crypto::{ + SessionKey, + backend::interface::Kdf, + }, +}; + +impl Kdf for super::Backend { + fn hkdf_sha256(ikm: &SessionKey, salt: Option<&[u8]>, info: &[u8], + okm: &mut SessionKey) + -> Result<()> + { + assert!(okm.len() <= 255 * 32); + const NO_SALT: [u8; 32] = [0; 32]; + let salt = salt.unwrap_or(&NO_SALT); + hkdf::<Sha256>(&ikm[..], salt, info, okm); + Ok(()) + } +} diff --git a/openpgp/src/crypto/backend/openssl.rs b/openpgp/src/crypto/backend/openssl.rs index aabf94cf..2bea302b 100644 --- a/openpgp/src/crypto/backend/openssl.rs +++ b/openpgp/src/crypto/backend/openssl.rs @@ -6,6 +6,7 @@ pub mod aead; pub mod asymmetric; pub mod ecdh; pub mod hash; +pub mod kdf; pub mod symmetric; pub struct Backend(()); diff --git a/openpgp/src/crypto/backend/openssl/kdf.rs b/openpgp/src/crypto/backend/openssl/kdf.rs new file mode 100644 index 00000000..11c48667 --- /dev/null +++ b/openpgp/src/crypto/backend/openssl/kdf.rs @@ -0,0 +1,31 @@ +use openssl::{ + md::Md, + pkey::Id, + pkey_ctx::PkeyCtx, +}; + +use crate::{ + Result, + crypto::{ + SessionKey, + backend::interface::Kdf, + }, +}; + +impl Kdf for super::Backend { + fn hkdf_sha256(ikm: &SessionKey, salt: Option<&[u8]>, info: &[u8], + okm: &mut SessionKey) + -> Result<()> + { + let mut pkey = PkeyCtx::new_id(Id::HKDF)?; + pkey.derive_init()?; + pkey.set_hkdf_md(Md::sha256())?; + pkey.set_hkdf_key(&ikm)?; + if let Some(salt) = salt { + pkey.set_hkdf_salt(salt)?; + } + pkey.add_hkdf_info(info)?; + pkey.derive(Some(okm))?; + Ok(()) + } +} diff --git a/openpgp/src/crypto/backend/rust.rs b/openpgp/src/crypto/backend/rust.rs index e373dba3..27370e82 100644 --- a/openpgp/src/crypto/backend/rust.rs +++ b/openpgp/src/crypto/backend/rust.rs @@ -10,6 +10,7 @@ pub mod aead; pub mod asymmetric; pub mod ecdh; pub mod hash; +pub mod kdf; pub mod symmetric; pub struct Backend(()); diff --git a/openpgp/src/crypto/backend/rust/kdf.rs b/openpgp/src/crypto/backend/rust/kdf.rs new file mode 100644 index 00000000..ac98a496 --- /dev/null +++ b/openpgp/src/crypto/backend/rust/kdf.rs @@ -0,0 +1,20 @@ +use hkdf::Hkdf; +use sha2::Sha256; + +use crate::{ + Result, + crypto::{ + SessionKey, + backend::interface::Kdf, + }, +}; + +impl Kdf for super::Backend { + fn hkdf_sha256(ikm: &SessionKey, salt: Option<&[u8]>, info: &[u8], + okm: &mut SessionKey) + -> Result<()> + { + Ok(Hkdf::<Sha256>::new(salt, &ikm).expand(info, okm) + .map_err(|e| crate::Error::InvalidOperation(e.to_string()))?) + } +} |