summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-07-18 12:56:05 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-07-19 11:45:49 +0200
commit4fef5e28650b287d0c43f944b2f864f7d33aa8a9 (patch)
tree9a17e6247e2110e8d2a700c2cf953633cefb3a58
parent191f1e030ad70919e57f967a3d49f4607aa61010 (diff)
openpgp: Implement Key::generate_elgamal.
-rw-r--r--openpgp/NEWS1
-rw-r--r--openpgp/src/crypto/backend/botan/asymmetric.rs13
-rw-r--r--openpgp/src/crypto/backend/interface.rs13
-rw-r--r--openpgp/src/packet/key.rs20
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() {