diff options
author | Justus Winter <justus@sequoia-pgp.org> | 2023-07-18 12:56:05 +0200 |
---|---|---|
committer | Justus Winter <justus@sequoia-pgp.org> | 2023-07-19 11:45:49 +0200 |
commit | 4fef5e28650b287d0c43f944b2f864f7d33aa8a9 (patch) | |
tree | 9a17e6247e2110e8d2a700c2cf953633cefb3a58 | |
parent | 191f1e030ad70919e57f967a3d49f4607aa61010 (diff) |
openpgp: Implement Key::generate_elgamal.
-rw-r--r-- | openpgp/NEWS | 1 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/botan/asymmetric.rs | 13 | ||||
-rw-r--r-- | openpgp/src/crypto/backend/interface.rs | 13 | ||||
-rw-r--r-- | openpgp/src/packet/key.rs | 20 |
4 files changed, 47 insertions, 0 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS index 3b16475d..e156a64f 100644 --- a/openpgp/NEWS +++ b/openpgp/NEWS @@ -31,6 +31,7 @@ - The RustCrypto backend now supports DSA. - crypto::SessionKey::as_protected - packet::Key::generate_dsa + - packet::Key::generate_elgamal - parse::PacketParser::start_hashing - parse::PacketParserBuilder::automatic_hashing - types::AEADAlgorithm::GCM diff --git a/openpgp/src/crypto/backend/botan/asymmetric.rs b/openpgp/src/crypto/backend/botan/asymmetric.rs index 04495a40..f3351570 100644 --- a/openpgp/src/crypto/backend/botan/asymmetric.rs +++ b/openpgp/src/crypto/backend/botan/asymmetric.rs @@ -127,6 +127,19 @@ impl Asymmetric for super::Backend { public.get_field("y")?.try_into()?, secret.get_field("x")?.try_into()?)) } + + fn elgamal_generate_key(p_bits: usize) + -> Result<(MPI, MPI, MPI, ProtectedMPI)> + { + let mut rng = RandomNumberGenerator::new_userspace()?; + let q_bits = if p_bits <= 1024 { 160 } else { 256 }; + let secret = Privkey::create_elgamal(p_bits, q_bits, &mut rng)?; + let public = secret.pubkey()?; + Ok((public.get_field("p")?.try_into()?, + public.get_field("g")?.try_into()?, + public.get_field("y")?.try_into()?, + secret.get_field("x")?.try_into()?)) + } } // CONFIDENTIALITY: Botan clears the MPIs after use. diff --git a/openpgp/src/crypto/backend/interface.rs b/openpgp/src/crypto/backend/interface.rs index 9a939bc4..25b4cd37 100644 --- a/openpgp/src/crypto/backend/interface.rs +++ b/openpgp/src/crypto/backend/interface.rs @@ -1,6 +1,7 @@ //! The crypto-backend abstraction. use crate::{ + Error, Result, crypto::{ mem::Protected, @@ -80,4 +81,16 @@ pub trait Asymmetric { /// public key `y`, and the secret key `x`. fn dsa_generate_key(p_bits: usize) -> Result<(MPI, MPI, MPI, MPI, ProtectedMPI)>; + + /// Generates an ElGamal key pair. + /// + /// `p_bits` denotes the desired size of the parameter `p`. + /// Returns a tuple containing the parameters `p`, `g`, the public + /// key `y`, and the secret key `x`. + fn elgamal_generate_key(p_bits: usize) + -> Result<(MPI, MPI, MPI, ProtectedMPI)> { + let _ = p_bits; + Err(Error::UnsupportedPublicKeyAlgorithm( + PublicKeyAlgorithm::ElGamalEncrypt).into()) + } } diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs index 3b9f3b48..c8c9621e 100644 --- a/openpgp/src/packet/key.rs +++ b/openpgp/src/packet/key.rs @@ -1215,6 +1215,24 @@ impl<R> Key4<SecretParts, R> public_mpis, private_mpis.into()) } + + /// Generates a new ElGamal key with a public modulus of size `p_bits`. + /// + /// Note: ElGamal is no longer well supported in cryptographic + /// libraries and should be avoided. + pub fn generate_elgamal(p_bits: usize) -> Result<Self> { + use crate::crypto::backend::{Backend, interface::Asymmetric}; + + let (p, g, y, x) = Backend::elgamal_generate_key(p_bits)?; + let public_mpis = mpi::PublicKey::ElGamal { p, g, y }; + let private_mpis = mpi::SecretKeyMaterial::ElGamal { x }; + + Self::with_secret( + crate::now(), + PublicKeyAlgorithm::ElGamalEncrypt, + public_mpis, + private_mpis.into()) + } } impl<P, R> Key4<P, R> @@ -2102,6 +2120,8 @@ mod tests { Key4::generate_ecc(false, cv).ok() }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| { Key4::generate_rsa(b).ok() + })).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| { + Key4::generate_elgamal(b).ok() })); for key in keys.into_iter() { |