Repository: randombit/botan
Pull request #2520 (2020-11-28 13:04:33)

Add Private_Key::public_key


Patch:
diff --git a/src/lib/prov/pkcs11/p11_ecdh.cpp b/src/lib/prov/pkcs11/p11_ecdh.cpp
index bd598143a..82f09e4cd 100644
--- a/src/lib/prov/pkcs11/p11_ecdh.cpp
+++ b/src/lib/prov/pkcs11/p11_ecdh.cpp
@@ -32,6 +32,11 @@ ECDH_PrivateKey PKCS11_ECDH_PrivateKey::export_key() const
    return ECDH_PrivateKey(rng, domain(), BigInt::decode(priv_key));
    }
 
+std::unique_ptr<Public_Key> PKCS11_ECDH_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new ECDH_PublicKey(domain(), public_point()));
+   }
+
 secure_vector<uint8_t> PKCS11_ECDH_PrivateKey::private_key_bits() const
    {
    return export_key().private_key_bits();
diff --git a/src/lib/prov/pkcs11/p11_ecdh.h b/src/lib/prov/pkcs11/p11_ecdh.h
index bbef9a3e5..aa2975a42 100644
--- a/src/lib/prov/pkcs11/p11_ecdh.h
+++ b/src/lib/prov/pkcs11/p11_ecdh.h
@@ -93,6 +93,8 @@ class BOTAN_PUBLIC_API(2,0) PKCS11_ECDH_PrivateKey final : public virtual PKCS11
          return "ECDH";
          }
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       inline std::vector<uint8_t> public_value() const override
          {
          return public_point().encode(PointGFp::UNCOMPRESSED);
diff --git a/src/lib/prov/pkcs11/p11_ecdsa.cpp b/src/lib/prov/pkcs11/p11_ecdsa.cpp
index eebb13020..f35da4892 100644
--- a/src/lib/prov/pkcs11/p11_ecdsa.cpp
+++ b/src/lib/prov/pkcs11/p11_ecdsa.cpp
@@ -52,6 +52,11 @@ secure_vector<uint8_t> PKCS11_ECDSA_PrivateKey::private_key_bits() const
    return export_key().private_key_bits();
    }
 
+std::unique_ptr<Public_Key> PKCS11_ECDSA_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new ECDSA_PublicKey(domain(), public_point()));
+   }
+
 namespace {
 
 class PKCS11_ECDSA_Signature_Operation final : public PK_Ops::Signature
diff --git a/src/lib/prov/pkcs11/p11_ecdsa.h b/src/lib/prov/pkcs11/p11_ecdsa.h
index 82721a466..ccf07a513 100644
--- a/src/lib/prov/pkcs11/p11_ecdsa.h
+++ b/src/lib/prov/pkcs11/p11_ecdsa.h
@@ -105,6 +105,8 @@ class BOTAN_PUBLIC_API(2,0) PKCS11_ECDSA_PrivateKey final : public PKCS11_EC_Pri
       /// @return the exported ECDSA private key
       ECDSA_PrivateKey export_key() const;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       secure_vector<uint8_t> private_key_bits() const override;
 
       bool check_key(RandomNumberGenerator&, bool) const override;
diff --git a/src/lib/prov/pkcs11/p11_rsa.cpp b/src/lib/prov/pkcs11/p11_rsa.cpp
index 93147fee2..eb990b19a 100644
--- a/src/lib/prov/pkcs11/p11_rsa.cpp
+++ b/src/lib/prov/pkcs11/p11_rsa.cpp
@@ -106,6 +106,17 @@ RSA_PrivateKey PKCS11_RSA_PrivateKey::export_key() const
                          , BigInt::decode(n));
    }
 
+std::unique_ptr<Public_Key> PKCS11_RSA_PrivateKey::public_key() const
+   {
+   auto p = get_attribute_value(AttributeType::Prime1);
+   auto q = get_attribute_value(AttributeType::Prime2);
+   auto e = get_attribute_value(AttributeType::PublicExponent);
+
+   BigInt n = BigInt::decode(p) * BigInt::decode(q);
+
+   return std::unique_ptr<Public_Key>(new RSA_PublicKey(n, BigInt::decode(e)));
+   }
+
 secure_vector<uint8_t> PKCS11_RSA_PrivateKey::private_key_bits() const
    {
    return export_key().private_key_bits();
diff --git a/src/lib/prov/pkcs11/p11_rsa.h b/src/lib/prov/pkcs11/p11_rsa.h
index 41d9bc134..e3b557f94 100644
--- a/src/lib/prov/pkcs11/p11_rsa.h
+++ b/src/lib/prov/pkcs11/p11_rsa.h
@@ -200,6 +200,8 @@ class BOTAN_PUBLIC_API(2,0) PKCS11_RSA_PrivateKey final :
 
       secure_vector<uint8_t> private_key_bits() const override;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       std::unique_ptr<PK_Ops::Decryption>
          create_decryption_op(RandomNumberGenerator& rng,
                               const std::string& params,
diff --git a/src/lib/prov/tpm/tpm.h b/src/lib/prov/tpm/tpm.h
index 8a25458b7..d5fe929c3 100644
--- a/src/lib/prov/tpm/tpm.h
+++ b/src/lib/prov/tpm/tpm.h
@@ -138,7 +138,7 @@ class BOTAN_PUBLIC_API(2,0) TPM_PrivateKey final : public Private_Key
       /**
       * Returns a copy of the public key
       */
-      std::unique_ptr<Public_Key> public_key() const;
+      std::unique_ptr<Public_Key> public_key() const override;
 
       std::vector<uint8_t> export_blob() const;
 
diff --git a/src/lib/pubkey/curve25519/curve25519.cpp b/src/lib/pubkey/curve25519/curve25519.cpp
index 515fdc5e6..a06e700c4 100644
--- a/src/lib/pubkey/curve25519/curve25519.cpp
+++ b/src/lib/pubkey/curve25519/curve25519.cpp
@@ -87,6 +87,11 @@ Curve25519_PrivateKey::Curve25519_PrivateKey(const AlgorithmIdentifier&,
    curve25519_basepoint(m_public.data(), m_private.data());
    }
 
+std::unique_ptr<Public_Key> Curve25519_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new Curve25519_PublicKey(public_value()));
+   }
+
 secure_vector<uint8_t> Curve25519_PrivateKey::private_key_bits() const
    {
    return DER_Encoder().encode(m_private, OCTET_STRING).get_contents();
diff --git a/src/lib/pubkey/curve25519/curve25519.h b/src/lib/pubkey/curve25519/curve25519.h
index c2f8f42b3..99860630e 100644
--- a/src/lib/pubkey/curve25519/curve25519.h
+++ b/src/lib/pubkey/curve25519/curve25519.h
@@ -88,6 +88,8 @@ class BOTAN_PUBLIC_API(2,0) Curve25519_PrivateKey final : public Curve25519_Publ
 
       secure_vector<uint8_t> private_key_bits() const override;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       bool check_key(RandomNumberGenerator& rng, bool strong) const override;
 
       std::unique_ptr<PK_Ops::Key_Agreement>
diff --git a/src/lib/pubkey/dh/dh.cpp b/src/lib/pubkey/dh/dh.cpp
index e4b6e825e..77ac19da4 100644
--- a/src/lib/pubkey/dh/dh.cpp
+++ b/src/lib/pubkey/dh/dh.cpp
@@ -66,6 +66,11 @@ DH_PrivateKey::DH_PrivateKey(const AlgorithmIdentifier& alg_id,
       }
    }
 
+std::unique_ptr<Public_Key> DH_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new DH_PublicKey(get_group(), get_y()));
+   }
+
 /*
 * Return the public value for key agreement
 */
diff --git a/src/lib/pubkey/dh/dh.h b/src/lib/pubkey/dh/dh.h
index e3aa0d2c5..bb6d5dae4 100644
--- a/src/lib/pubkey/dh/dh.h
+++ b/src/lib/pubkey/dh/dh.h
@@ -70,6 +70,8 @@ class BOTAN_PUBLIC_API(2,0) DH_PrivateKey final : public DH_PublicKey,
       DH_PrivateKey(RandomNumberGenerator& rng, const DL_Group& grp,
                     const BigInt& x = 0);
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       std::unique_ptr<PK_Ops::Key_Agreement>
          create_key_agreement_op(RandomNumberGenerator& rng,
                                  const std::string& params,
diff --git a/src/lib/pubkey/dsa/dsa.cpp b/src/lib/pubkey/dsa/dsa.cpp
index 5c0d048c9..a135bc962 100644
--- a/src/lib/pubkey/dsa/dsa.cpp
+++ b/src/lib/pubkey/dsa/dsa.cpp
@@ -67,6 +67,11 @@ bool DSA_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const
    return KeyPair::signature_consistency_check(rng, *this, "EMSA1(SHA-256)");
    }
 
+std::unique_ptr<Public_Key> DSA_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new DSA_PublicKey(get_group(), get_y()));
+   }
+
 namespace {
 
 /**
diff --git a/src/lib/pubkey/dsa/dsa.h b/src/lib/pubkey/dsa/dsa.h
index b219a1cf3..1834737b5 100644
--- a/src/lib/pubkey/dsa/dsa.h
+++ b/src/lib/pubkey/dsa/dsa.h
@@ -74,6 +74,8 @@ class BOTAN_PUBLIC_API(2,0) DSA_PrivateKey final : public DSA_PublicKey,
                      const DL_Group& group,
                      const BigInt& private_key = 0);
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       bool check_key(RandomNumberGenerator& rng, bool strong) const override;
 
       std::unique_ptr<PK_Ops::Signature>
diff --git a/src/lib/pubkey/ecdh/ecdh.cpp b/src/lib/pubkey/ecdh/ecdh.cpp
index e7e49a74f..74c385fcf 100644
--- a/src/lib/pubkey/ecdh/ecdh.cpp
+++ b/src/lib/pubkey/ecdh/ecdh.cpp
@@ -17,6 +17,11 @@
 
 namespace Botan {
 
+std::unique_ptr<Public_Key> ECDH_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new ECDH_PublicKey(domain(), public_point()));
+   }
+
 namespace {
 
 /**
diff --git a/src/lib/pubkey/ecdh/ecdh.h b/src/lib/pubkey/ecdh/ecdh.h
index f88955ac4..4be7e656c 100644
--- a/src/lib/pubkey/ecdh/ecdh.h
+++ b/src/lib/pubkey/ecdh/ecdh.h
@@ -89,6 +89,8 @@ class BOTAN_PUBLIC_API(2,0) ECDH_PrivateKey final : public ECDH_PublicKey,
                       const BigInt& x = 0) :
          EC_PrivateKey(rng, domain, x) {}
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       std::vector<uint8_t> public_value() const override
          { return ECDH_PublicKey::public_value(PointGFp::UNCOMPRESSED); }
 
diff --git a/src/lib/pubkey/ecdsa/ecdsa.cpp b/src/lib/pubkey/ecdsa/ecdsa.cpp
index 11ec37ff4..96c1b7751 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.cpp
+++ b/src/lib/pubkey/ecdsa/ecdsa.cpp
@@ -109,6 +109,11 @@ uint8_t ECDSA_PublicKey::recovery_param(const std::vector<uint8_t>& msg,
    throw Internal_Error("Could not determine ECDSA recovery parameter");
    }
 
+std::unique_ptr<Public_Key> ECDSA_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new ECDSA_PublicKey(domain(), public_point()));
+   }
+
 bool ECDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
                                  bool strong) const
    {
diff --git a/src/lib/pubkey/ecdsa/ecdsa.h b/src/lib/pubkey/ecdsa/ecdsa.h
index 8423a9c20..2bdb9e79b 100644
--- a/src/lib/pubkey/ecdsa/ecdsa.h
+++ b/src/lib/pubkey/ecdsa/ecdsa.h
@@ -106,6 +106,8 @@ class BOTAN_PUBLIC_API(2,0) ECDSA_PrivateKey final : public ECDSA_PublicKey,
 
       bool check_key(RandomNumberGenerator& rng, bool) const override;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       std::unique_ptr<PK_Ops::Signature>
          create_signature_op(RandomNumberGenerator& rng,
                              const std::string& params,
diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.cpp b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
index 26045be6b..f4331677b 100644
--- a/src/lib/pubkey/ecgdsa/ecgdsa.cpp
+++ b/src/lib/pubkey/ecgdsa/ecgdsa.cpp
@@ -14,6 +14,11 @@
 
 namespace Botan {
 
+std::unique_ptr<Public_Key> ECGDSA_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new ECGDSA_PublicKey(domain(), public_point()));
+   }
+
 bool ECGDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
                                  bool strong) const
    {
diff --git a/src/lib/pubkey/ecgdsa/ecgdsa.h b/src/lib/pubkey/ecgdsa/ecgdsa.h
index 31d0e2be5..cf9f09de2 100644
--- a/src/lib/pubkey/ecgdsa/ecgdsa.h
+++ b/src/lib/pubkey/ecgdsa/ecgdsa.h
@@ -83,6 +83,8 @@ class BOTAN_PUBLIC_API(2,0) ECGDSA_PrivateKey final : public ECGDSA_PublicKey,
                        const BigInt& x = 0) :
          EC_PrivateKey(rng, domain, x, true) {}
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       bool check_key(RandomNumberGenerator& rng, bool) const override;
 
       std::unique_ptr<PK_Ops::Signature>
diff --git a/src/lib/pubkey/ecies/ecies.cpp b/src/lib/pubkey/ecies/ecies.cpp
index a8c277b3a..dcdf318c1 100644
--- a/src/lib/pubkey/ecies/ecies.cpp
+++ b/src/lib/pubkey/ecies/ecies.cpp
@@ -40,6 +40,11 @@ class ECIES_PrivateKey final : public EC_PrivateKey, public PK_Key_Agreement_Key
          return "ECIES";
          }
 
+      std::unique_ptr<Public_Key> public_key() const override
+         {
+         return m_key.public_key();
+         }
+
       std::unique_ptr<PK_Ops::Key_Agreement>
          create_key_agreement_op(RandomNumberGenerator& rng,
                                  const std::string& params,
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.cpp b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
index 3321a713d..d232e35e4 100644
--- a/src/lib/pubkey/eckcdsa/eckcdsa.cpp
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.cpp
@@ -17,6 +17,11 @@
 
 namespace Botan {
 
+std::unique_ptr<Public_Key> ECKCDSA_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new ECKCDSA_PublicKey(domain(), public_point()));
+   }
+
 bool ECKCDSA_PrivateKey::check_key(RandomNumberGenerator& rng,
                                  bool strong) const
    {
diff --git a/src/lib/pubkey/eckcdsa/eckcdsa.h b/src/lib/pubkey/eckcdsa/eckcdsa.h
index aa04cb146..924f56c4c 100644
--- a/src/lib/pubkey/eckcdsa/eckcdsa.h
+++ b/src/lib/pubkey/eckcdsa/eckcdsa.h
@@ -85,6 +85,8 @@ class BOTAN_PUBLIC_API(2,0) ECKCDSA_PrivateKey final : public ECKCDSA_PublicKey,
 
       bool check_key(RandomNumberGenerator& rng, bool) const override;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       std::unique_ptr<PK_Ops::Signature>
          create_signature_op(RandomNumberGenerator& rng,
                              const std::string& params,
diff --git a/src/lib/pubkey/ed25519/ed25519.h b/src/lib/pubkey/ed25519/ed25519.h
index 97ed023f2..65bee1353 100644
--- a/src/lib/pubkey/ed25519/ed25519.h
+++ b/src/lib/pubkey/ed25519/ed25519.h
@@ -83,6 +83,8 @@ class BOTAN_PUBLIC_API(2,2) Ed25519_PrivateKey final : public Ed25519_PublicKey,
 
       secure_vector<uint8_t> private_key_bits() const override;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       bool check_key(RandomNumberGenerator& rng, bool strong) const override;
 
       std::unique_ptr<PK_Ops::Signature>
diff --git a/src/lib/pubkey/ed25519/ed25519_key.cpp b/src/lib/pubkey/ed25519/ed25519_key.cpp
index c4b260c4c..ad8646111 100644
--- a/src/lib/pubkey/ed25519/ed25519_key.cpp
+++ b/src/lib/pubkey/ed25519/ed25519_key.cpp
@@ -87,6 +87,11 @@ Ed25519_PrivateKey::Ed25519_PrivateKey(const AlgorithmIdentifier&,
    ed25519_gen_keypair(m_public.data(), m_private.data(), bits.data());
    }
 
+std::unique_ptr<Public_Key> Ed25519_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new Ed25519_PublicKey(get_public_key()));
+   }
+
 secure_vector<uint8_t> Ed25519_PrivateKey::private_key_bits() const
    {
    secure_vector<uint8_t> bits(&m_private[0], &m_private[32]);
diff --git a/src/lib/pubkey/elgamal/elgamal.cpp b/src/lib/pubkey/elgamal/elgamal.cpp
index 6f8019723..73e091d0a 100644
--- a/src/lib/pubkey/elgamal/elgamal.cpp
+++ b/src/lib/pubkey/elgamal/elgamal.cpp
@@ -50,6 +50,11 @@ ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id,
    m_y = m_group.power_g_p(m_x, m_group.p_bits());
    }
 
+std::unique_ptr<Public_Key> ElGamal_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(get_group(), get_y()));
+   }
+
 /*
 * Check Private ElGamal Parameters
 */
diff --git a/src/lib/pubkey/elgamal/elgamal.h b/src/lib/pubkey/elgamal/elgamal.h
index e4d932f6a..4147f5037 100644
--- a/src/lib/pubkey/elgamal/elgamal.h
+++ b/src/lib/pubkey/elgamal/elgamal.h
@@ -74,6 +74,8 @@ class BOTAN_PUBLIC_API(2,0) ElGamal_PrivateKey final : public ElGamal_PublicKey,
                          const DL_Group& group,
                          const BigInt& priv_key = 0);
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       std::unique_ptr<PK_Ops::Decryption>
          create_decryption_op(RandomNumberGenerator& rng,
                               const std::string& params,
diff --git a/src/lib/pubkey/gost_3410/gost_3410.cpp b/src/lib/pubkey/gost_3410/gost_3410.cpp
index d1f8fc786..f378a7998 100644
--- a/src/lib/pubkey/gost_3410/gost_3410.cpp
+++ b/src/lib/pubkey/gost_3410/gost_3410.cpp
@@ -109,6 +109,11 @@ GOST_3410_PrivateKey::GOST_3410_PrivateKey(RandomNumberGenerator& rng,
                            std::to_string(p_bits));
    }
 
+std::unique_ptr<Public_Key> GOST_3410_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new GOST_3410_PublicKey(domain(), public_point()));
+   }
+
 namespace {
 
 BigInt decode_le(const uint8_t msg[], size_t msg_len)
diff --git a/src/lib/pubkey/gost_3410/gost_3410.h b/src/lib/pubkey/gost_3410/gost_3410.h
index 9eedaf122..ffce3ef97 100644
--- a/src/lib/pubkey/gost_3410/gost_3410.h
+++ b/src/lib/pubkey/gost_3410/gost_3410.h
@@ -90,6 +90,8 @@ class BOTAN_PUBLIC_API(2,0) GOST_3410_PrivateKey final :
                            const EC_Group& domain,
                            const BigInt& x = 0);
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       AlgorithmIdentifier pkcs8_algorithm_identifier() const override
          { return EC_PublicKey::algorithm_identifier(); }
 
diff --git a/src/lib/pubkey/mce/mceliece.h b/src/lib/pubkey/mce/mceliece.h
index 255898b63..3ac48aeb4 100644
--- a/src/lib/pubkey/mce/mceliece.h
+++ b/src/lib/pubkey/mce/mceliece.h
@@ -116,6 +116,8 @@ class BOTAN_PUBLIC_API(2,0) McEliece_PrivateKey final : public virtual McEliece_
 
       secure_vector<uint8_t> private_key_bits() const override;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       bool operator==(const McEliece_PrivateKey & other) const;
 
       bool operator!=(const McEliece_PrivateKey& other) const { return !(*this == other); }
diff --git a/src/lib/pubkey/mce/mceliece_key.cpp b/src/lib/pubkey/mce/mceliece_key.cpp
index 9db90112f..f0bd8e61d 100644
--- a/src/lib/pubkey/mce/mceliece_key.cpp
+++ b/src/lib/pubkey/mce/mceliece_key.cpp
@@ -292,6 +292,13 @@ bool McEliece_PrivateKey::operator==(const McEliece_PrivateKey & other) const
    return true;
    }
 
+std::unique_ptr<Public_Key> McEliece_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new McEliece_PublicKey(
+                                         get_public_matrix(),
+                                         get_t(), get_code_length()));
+   }
+
 bool McEliece_PublicKey::operator==(const McEliece_PublicKey& other) const
    {
    if(m_public_matrix != other.m_public_matrix)
diff --git a/src/lib/pubkey/pk_keys.h b/src/lib/pubkey/pk_keys.h
index 404cd683f..38b902cf3 100644
--- a/src/lib/pubkey/pk_keys.h
+++ b/src/lib/pubkey/pk_keys.h
@@ -1,6 +1,6 @@
 /*
 * PK Key Types
-* (C) 1999-2007 Jack Lloyd
+* (C) 1999-2007,2018 Jack Lloyd
 *
 * Botan is released under the Simplified BSD License (see license.txt)
 */
@@ -28,7 +28,7 @@ enum Signature_Format { IEEE_1363, DER_SEQUENCE };
 class BOTAN_PUBLIC_API(2,0) Public_Key
    {
    public:
-      Public_Key() =default;
+      Public_Key() = default;
       Public_Key(const Public_Key& other) = default;
       Public_Key& operator=(const Public_Key& other) = default;
       virtual ~Public_Key() = default;
@@ -192,6 +192,14 @@ class BOTAN_PUBLIC_API(2,0) Private_Key : public virtual Public_Key
       */
       virtual secure_vector<uint8_t> private_key_bits() const = 0;
 
+      /**
+      * Allocate a new object for the public key associated with this
+      * private key.
+      *
+      * @return public key
+      */
+      virtual std::unique_ptr<Public_Key> public_key() const = 0;
+
       /**
       * @return PKCS #8 private key encoding for this key object
       */
diff --git a/src/lib/pubkey/rsa/rsa.cpp b/src/lib/pubkey/rsa/rsa.cpp
index b7d05e456..8899c9a63 100644
--- a/src/lib/pubkey/rsa/rsa.cpp
+++ b/src/lib/pubkey/rsa/rsa.cpp
@@ -313,6 +313,11 @@ RSA_PrivateKey::RSA_PrivateKey(RandomNumberGenerator& rng,
                         std::move(d1), std::move(d2), std::move(c));
    }
 
+std::unique_ptr<Public_Key> RSA_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new RSA_PublicKey(get_n(), get_e()));
+   }
+
 /*
 * Check Private RSA Parameters
 */
diff --git a/src/lib/pubkey/rsa/rsa.h b/src/lib/pubkey/rsa/rsa.h
index 2a02c89d5..ccea7c310 100644
--- a/src/lib/pubkey/rsa/rsa.h
+++ b/src/lib/pubkey/rsa/rsa.h
@@ -124,6 +124,8 @@ class BOTAN_PUBLIC_API(2,0) RSA_PrivateKey final : public Private_Key, public RS
       RSA_PrivateKey(RandomNumberGenerator& rng,
                      size_t bits, size_t exp = 65537);
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       bool check_key(RandomNumberGenerator& rng, bool) const override;
 
       /**
diff --git a/src/lib/pubkey/sm2/sm2.cpp b/src/lib/pubkey/sm2/sm2.cpp
index a73823448..67dbacce9 100644
--- a/src/lib/pubkey/sm2/sm2.cpp
+++ b/src/lib/pubkey/sm2/sm2.cpp
@@ -22,6 +22,11 @@ std::string SM2_PublicKey::algo_name() const
    return "SM2";
    }
 
+std::unique_ptr<Public_Key> SM2_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(new SM2_Signature_PublicKey(domain(), public_point()));
+   }
+
 bool SM2_PrivateKey::check_key(RandomNumberGenerator& rng,
                                bool strong) const
    {
diff --git a/src/lib/pubkey/sm2/sm2.h b/src/lib/pubkey/sm2/sm2.h
index 7b5f38858..2341ed861 100644
--- a/src/lib/pubkey/sm2/sm2.h
+++ b/src/lib/pubkey/sm2/sm2.h
@@ -89,6 +89,8 @@ class BOTAN_PUBLIC_API(2,2) SM2_PrivateKey final :
 
       bool check_key(RandomNumberGenerator& rng, bool) const override;
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       std::unique_ptr<PK_Ops::Signature>
          create_signature_op(RandomNumberGenerator& rng,
                              const std::string& params,
diff --git a/src/lib/pubkey/xmss/xmss.h b/src/lib/pubkey/xmss/xmss.h
index af8e8a41e..566f58282 100644
--- a/src/lib/pubkey/xmss/xmss.h
+++ b/src/lib/pubkey/xmss/xmss.h
@@ -314,6 +314,8 @@ class BOTAN_PUBLIC_API(2,0) XMSS_PrivateKey final : public virtual XMSS_PublicKe
 
       bool stateful_operation() const override { return true; }
 
+      std::unique_ptr<Public_Key> public_key() const override;
+
       /**
        * Retrieves the last unused leaf index of the private key. Reusing a leaf
        * by utilizing leaf indices lower than the last unused leaf index will
diff --git a/src/lib/pubkey/xmss/xmss_privatekey.cpp b/src/lib/pubkey/xmss/xmss_privatekey.cpp
index c497be003..5d2171266 100644
--- a/src/lib/pubkey/xmss/xmss_privatekey.cpp
+++ b/src/lib/pubkey/xmss/xmss_privatekey.cpp
@@ -390,6 +390,12 @@ secure_vector<uint8_t> XMSS_PrivateKey::raw_private_key() const
    return result;
    }
 
+std::unique_ptr<Public_Key> XMSS_PrivateKey::public_key() const
+   {
+   return std::unique_ptr<Public_Key>(
+      new XMSS_PublicKey(xmss_oid(), root(), public_seed()));
+   }
+
 std::unique_ptr<PK_Ops::Signature>
 XMSS_PrivateKey::create_signature_op(RandomNumberGenerator&,
                                      const std::string&,
diff --git a/src/lib/pubkey/xmss/xmss_wots.h b/src/lib/pubkey/xmss/xmss_wots.h
index d85e889bf..060d54711 100644
--- a/src/lib/pubkey/xmss/xmss_wots.h
+++ b/src/lib/pubkey/xmss/xmss_wots.h
@@ -536,6 +536,11 @@ class XMSS_WOTS_PrivateKey final : public virtual XMSS_WOTS_PublicKey,
          set_key_data(generate(private_seed));
          }
 
+      std::unique_ptr<Public_Key> public_key() const override
+         {
+         throw Not_Implemented("Not possible to derive WOTS public key from private key");
+         }
+
       /**
        * Retrieves the i-th WOTS private key using pseudo random key
        * (re-)generation.


Test patch:
diff --git a/src/tests/test_pubkey.cpp b/src/tests/test_pubkey.cpp
index 703f7360f..3e3001a86 100644
--- a/src/tests/test_pubkey.cpp
+++ b/src/tests/test_pubkey.cpp
@@ -667,6 +667,12 @@ std::vector<Test::Result> PK_Key_Generation_Test::run()
          std::unique_ptr<Botan::Private_Key> key_p =
             Botan::create_private_key(algo_name(), Test::rng(), param, prov);
 
+         if(key_p == nullptr)
+            {
+            result.test_failure("create_private_key returned null, should throw instead");
+            continue;
+            }
+
          const Botan::Private_Key& key = *key_p;
 
          try
@@ -678,6 +684,14 @@ std::vector<Test::Result> PK_Key_Generation_Test::run()
          result.test_gte("Key has reasonable estimated strength (lower)", key.estimated_strength(), 64);
          result.test_lt("Key has reasonable estimated strength (upper)", key.estimated_strength(), 512);
 
+         std::unique_ptr<Botan::Public_Key> public_key = key.public_key();
+
+         result.test_eq("public_key has same name", public_key->algo_name(), key.algo_name());
+
+         result.test_eq("public_key has same encoding",
+                        Botan::X509::PEM_encode(key),
+                        Botan::X509::PEM_encode(*public_key));
+
          // Test PEM public key round trips OK
          try
             {