Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get ECPublicKey from ECPrivateKey #1230

Open
k-x7 opened this issue Sep 13, 2024 · 2 comments
Open

Get ECPublicKey from ECPrivateKey #1230

k-x7 opened this issue Sep 13, 2024 · 2 comments

Comments

@k-x7
Copy link

k-x7 commented Sep 13, 2024

Hi

I would like to request support for getting an ECPublicKey from an ECPrivateKey when the private key is provided in PKCS8EncodedKeySpec instance, using the keyFactory.generatePublic method.

Issue:

I am currently working with EC keys and have been able to successfully derive the public key from the private key in other languages (Python, Go). However, I am unable to achieve this in Java/Kotlin due to the current restrictions in the available key specifications (ECPublicKeySpec and X509EncodedKeySpec).

Currently If I try the following code:

   val privateKey64 = "MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCAMM3sUprvk/VVF3vXhYcY0Vi9Ay1UPd4GLoBV/htAf2w=="

    val decodedKey = Base64.getDecoder().decode(privateKey64)
    val keySpec = PKCS8EncodedKeySpec(decodedKey)
    val keyFactory = KeyFactory.getInstance("EC")
    val privateKey: PrivateKey = keyFactory.generatePrivate(keySpec)
    val publicKey = keyFactory.generatePublic(keySpec)

    println("Private Key: ${privateKey.encoded.encodeBase64()}")
    println("Public Key: ${publicKey.encoded.encodeBase64()}")

it will throw an exception: java.security.spec.InvalidKeySpecException: Must use ECPublicKeySpec or X509EncodedKeySpec; was java.security.spec.PKCS8EncodedKeySpec

In this case both the private key and the algorithm already exist in keySpec, generating the public key should be possible.

Proposal:

When PKCS8EncodedKeySpec used with engineGeneratePublic try to get the private key and generate the public key from it:

    @Override
    protected PublicKey engineGeneratePublic(KeySpec keySpec) throws InvalidKeySpecException {
        if (keySpec == null) {
            throw new InvalidKeySpecException("keySpec == null");
        }

        if (keySpec instanceof ECPublicKeySpec) {
            return new OpenSSLECPublicKey((ECPublicKeySpec) keySpec);
        } else if (keySpec instanceof X509EncodedKeySpec) {
            return OpenSSLKey.getPublicKey((X509EncodedKeySpec) keySpec, NativeConstants.EVP_PKEY_EC);
        } else if (keySpec instanceof PKCS8EncodedKeySpec) {
            return OpenSSLKey.getPublicFromPrivate(...)
        }
        throw new InvalidKeySpecException("Must use ECPublicKeySpec or X509EncodedKeySpec; was "
                + keySpec.getClass().getName());
    }

This my current workaround: stackoverflow

Other languages, libraries:

Python Cryptography

private_key = serialization.load_der_private_key(
    private_key_der,
    password=None,
    backend=default_backend()
)

public_key = private_key.public_key()

Go

    privateKey, err := x509.ParsePKCS8PrivateKey(privKeyDER)
    if err != nil {
        log.Fatalf("Error parsing EC private key: %v", err)
    }

    k, ok := privateKey.(*ecdsa.PrivateKey)
    if !ok {
        panic("not ecdsa")
    }

   k.Public()
@prbprbprb
Copy link
Collaborator

When PKCS8EncodedKeySpec used with engineGeneratePublic try to get the private key and generate the public key from it

I don't think we can abuse the API that way, it's certainly not what it was intended to do and is potentially quite dangerous.

There's a 1:1 mapping between KeySpecs and their Keys, and the difference between PKCS#8 and X.509 encodings helps prevent errors where developers mix up keys. But if calling getPublic() on a private KeySpec "just works" and derives a public key, for any class of keys, then it would mask such errors.

@k-x7
Copy link
Author

k-x7 commented Sep 17, 2024

I was not aware of the 1:1 mapping

How do you suggest to get the public key from the private key without using an extra dependence like BouncyCastle by using conscrypt as security provider?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants