goencryptionecdsaecdh

Golang Extract ECDH Private Key


I know that ECDH private key is a superset of public key. The task is to extract private key ecdh.

Here is the way how to generate PublicKey:

    import (
        "crypto/ecdh"
        "crypto/rand"
        "crypto/ecdsa"
        "crypto/x509"
        "encoding/base64"
        "encoding/pem"
        "fmt"
)


func main() {

        alicePrivateKey, err := ecdh.P256().GenerateKey(rand.Reader)
        alicePublicKey, err := MarshalECDHPublicKey(alicePrivateKey.PublicKey())  
        if err != nil {
                fmt.Errorf("failed to marshal public key into PKIX format")
        }

        fmt.Printf("alicePubK => %s\n", alicePublicKey)

    clientECDSAPubKey, err := UnmarshalECDSAPublicKey(alicePublicKey)
    if err != nil {
       panic(err)
    }
    println(clientECDSAPubKey)
    println("no error")

}  

func MarshalECDHPublicKey(pk *ecdh.PublicKey) (string, error) {
        ecdhSKBytes, err := x509.MarshalPKIXPublicKey(pk)
        if err != nil {
                return "", fmt.Errorf("failed to marshal public key into PKIX format")
        }
        ecdhSKPEMBlock := pem.EncodeToMemory(
                &pem.Block{
                        Type:  "PUBLIC KEY",
                        Bytes: ecdhSKBytes,
                },
        )

        return base64.StdEncoding.EncodeToString(ecdhSKPEMBlock), nil
}

Solution

  • I am assuming you want to extract ecdh private key in pem format just like you did with the public key. Extracting private key from the public key isn't possible (computationally not feasible). I've implemented the UnmarshalECDSAPublicKey function for you (better renamed as MarshalECDHPrivateKey)

    // MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form.
    //
    // The following key types are currently supported: *rsa.PrivateKey,
    // *ecdsa.PrivateKey, ed25519.PrivateKey (not a pointer), and *ecdh.PrivateKey.
    // Unsupported key types result in an error.
    //
    // This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
    func UnmarshalECDSAPublicKey(alicePrivateKey *ecdh.PrivateKey) (string, error) {
        ecdhSKBytes, err := x509.MarshalPKCS8PrivateKey(alicePrivateKey)
        if err != nil {
            return "", fmt.Errorf("failed to marshal private key into PKIX format")
        }
    
        ecdhSKPEMBlock := pem.EncodeToMemory(
            &pem.Block{
                Type:  "PRIVATE KEY",
                Bytes: ecdhSKBytes,
            },
        )
        return string(ecdhSKPEMBlock), nil
    }
    

    As others pointed in the comments about MarshalECDHPublicKey function, you don't need to encode again with base64.StdEncoding.EncodeToString(ecdhSKPEMBlock) as pem.EncodeToMemory does the same, you can just convert that to string.