summaryrefslogtreecommitdiffstats
path: root/openpgp/src/packet/key.rs
diff options
context:
space:
mode:
Diffstat (limited to 'openpgp/src/packet/key.rs')
-rw-r--r--openpgp/src/packet/key.rs70
1 files changed, 70 insertions, 0 deletions
diff --git a/openpgp/src/packet/key.rs b/openpgp/src/packet/key.rs
index 787c5101..626239fb 100644
--- a/openpgp/src/packet/key.rs
+++ b/openpgp/src/packet/key.rs
@@ -1213,6 +1213,76 @@ impl<R> Key4<SecretParts, R>
}.into())
}
+ /// Generates a new ECC key over `curve`.
+ ///
+ /// If `for_signing` is false a ECDH key, if it's true either a
+ /// EdDSA or ECDSA key is generated. Giving `for_signing == true` and
+ /// `curve == Cv25519` will produce an error. Likewise
+ /// `for_signing == false` and `curve == Ed25519` will produce an error.
+ pub fn generate_ecc(for_signing: bool, curve: Curve) -> Result<Self> {
+ use crate::crypto::backend::{Backend, interface::Asymmetric};
+
+ let (pk_algo, public, secret) = match (curve, for_signing) {
+ (Curve::Ed25519, true) => {
+ let (secret, public) = Backend::ed25519_generate_key()?;
+
+ (
+ PublicKeyAlgorithm::EdDSA,
+ mpi::PublicKey::EdDSA {
+ curve: Curve::Ed25519,
+ q: mpi::MPI::new_compressed_point(&public),
+ },
+ mpi::SecretKeyMaterial::EdDSA {
+ scalar: secret.into(),
+ },
+ )
+ },
+
+ (Curve::Cv25519, false) => {
+ let (mut secret, public) = Backend::x25519_generate_key()?;
+
+ // Clamp the X25519 secret key scalar.
+ //
+ // X25519 does the clamping implicitly, but OpenPGP's ECDH over
+ // Curve25519 requires the secret to be clamped. To increase
+ // compatibility with OpenPGP implementations that do not
+ // implicitly clamp the secrets before use, we do that before we
+ // store the secrets in OpenPGP data structures.
+ Backend::x25519_clamp_secret(&mut secret);
+
+ // Reverse the scalar.
+ //
+ // X25519 stores the secret as opaque byte string
+ // representing a little-endian scalar. OpenPGP's
+ // ECDH over Curve25519 on the other hand stores it as
+ // big-endian scalar, as was customary in OpenPGP.
+ // See
+ // https://lists.gnupg.org/pipermail/gnupg-devel/2018-February/033437.html.
+ secret.reverse();
+
+ (
+ PublicKeyAlgorithm::ECDH,
+ mpi::PublicKey::ECDH {
+ curve: Curve::Cv25519,
+ q: mpi::MPI::new_compressed_point(&public),
+ hash: crate::crypto::ecdh::default_ecdh_kdf_hash(
+ &Curve::Cv25519),
+ sym: crate::crypto::ecdh::default_ecdh_kek_cipher(
+ &Curve::Cv25519),
+ },
+ mpi::SecretKeyMaterial::ECDH {
+ scalar: secret.into(),
+ },
+ )
+ },
+
+ (curve, for_signing) =>
+ Self::generate_ecc_backend(for_signing, curve)?,
+ };
+
+ Self::with_secret(crate::now(), pk_algo, public, secret.into())
+ }
+
/// Generates a new DSA key with a public modulus of size `p_bits`.
///
/// Note: In order to comply with FIPS 186-4, and to increase