3

I have ECC_SECG_P256K1 Public key PEM File generated by AWS KMS.

I want to convert pem public key into ethereum address by Go.

How can I get it?

Sample Pem Data

-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjgRz1kswP5KV4diFvYGegDVjeTIABq0a
82r4T41Wz94LDApF9OGyZsUSoQ59gaEVQark4mEQGQqV9HHQzlPavQ==
-----END PUBLIC KEY-----

I tried this code.(x,y returned nil)

var pemData = []byte(`MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjgRz1kswP5KV4diFvYGegDVjeTIABq0a82r4T41Wz94LDApF9OGyZsUSoQ59gaEVQark4mEQGQqV9HHQzlPavQ==`)
x,y := elliptic.UnmarshalCompressed(elliptic.P256(),pemData)
pubkey := elliptic.Marshal(secp256k1.S256(), x, y)
1
  • PEM certificates are quite complicated to parse. I'd recommend to look for a specific library to decode it. In javascript I'd use OpenPGPjs.
    – Ismael
    Commented Dec 2, 2022 at 5:44

1 Answer 1

2
+50

If this key is generated by some of the supported curves by the default lib, you can use ParsePKIXPublicKey directly to parse it. However, Secp256k1 curve is not supported by the default lib. So my solution was to copy the code from the lib and manually get x and y. I then use goethereum crypto lib to get the address and check if point is on the curve.

import (
    "crypto/ecdsa"
    "crypto/x509/pkix"
    "encoding/asn1"
    "encoding/hex"
    "encoding/pem"
    "fmt"
    "math/big"
    crypto "github.com/ethereum/go-ethereum/crypto"
)

type publicKeyInfo struct {
    Raw       asn1.RawContent
    Algorithm pkix.AlgorithmIdentifier
    PublicKey asn1.BitString
}
func main() {
    pemData := []byte(`-----BEGIN PUBLIC KEY-----
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEjgRz1kswP5KV4diFvYGegDVjeTIABq0a
82r4T41Wz94LDApF9OGyZsUSoQ59gaEVQark4mEQGQqV9HHQzlPavQ==
-----END PUBLIC KEY-----`)
    // better to read directly from file:
    // pemData, err := os.ReadFile("your_pub_file.pem") // just pass the file name
    // if err != nil {
    //  fmt.Print(err)
    // }
    block, _ := pem.Decode(pemData)
    if block == nil {
        panic("failed to parse PEM block containing the public key")
    }
    var pki publicKeyInfo
    asn1.Unmarshal(block.Bytes, &pki)
    asn1Data := pki.PublicKey.RightAlign()
    _, x, y := asn1Data[0], asn1Data[1:33], asn1Data[33:]
    fmt.Println("x and y : ", hex.EncodeToString(x), hex.EncodeToString(y))
    x_big := new(big.Int)
    x_big.SetBytes(x)
    y_big := new(big.Int)
    y_big.SetBytes(y)
    pubkey := ecdsa.PublicKey{Curve: crypto.S256(), X: x_big, Y: y_big}
    address := crypto.PubkeyToAddress(pubkey)
    isOnCurve := crypto.S256().IsOnCurve(pubkey.X, pubkey.Y)
    fmt.Println("Is the point on curve ? ", isOnCurve)
    fmt.Println("address: ", address)
}

The output:

x and y :  8e0473d64b303f9295e1d885bd819e80356379320006ad1af36af84f8d56cfde 0b0c0a45f4e1b266c512a10e7d81a11541aae4e26110190a95f471d0ce53dabd
Is the point on curve ?  true
address:  0x7D6bbc553e34C171Ab13fd0251bd496dCC069a1d
1
  • Just to add in the context: The OID string in this pem file is "1.2.840.10045.2.1" and the supported list is probably from here: github.com/golang/go/blob/… Whenever I tried the default ParsePKIXPublicKey it always throws x509: unsupported elliptic curve. That's the reason for the manually crafted code. I'm not sure when they will add new curve
    – minhhn2910
    Commented Dec 27, 2022 at 11:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.