xrl
xrl

Reputation: 2244

How to load DSA PublicKey using go stdlib

I have a PEM encoded DSA public key. I need this DSA key so I can verify incoming data. But I have yet to figure out how to load the key using go crypto library (I am not a crypto expert but from what I'm reading online, DSA is not a popular choice anymore).

I can decode the PEM in to its bytes. Which, from what I understand, are DER-encoded ASN.1. How can I put the PEM blocks in to a golang dsa.PublicKey?

Here's a runnable sample: http://play.golang.org/p/8Ma2qwhT31

The code:

package main

import "fmt"
import "encoding/pem"
import "encoding/asn1"
import "crypto/dsa"

var signingPubKey = []byte(`-----BEGIN PUBLIC KEY-----
MIICIDANBgkqhkiG9w0BAQEFAAOCAg0AMIICCAKCAgEApSmU3y4DzPhjnpOrdpPs
cIosWJ4zSV8h02b0abLW6nk7cnb5jSwBZKLrryAlF4vs+cF1mtMYjX0QKtEYq2V6
WVDnoXj3BeLYVbhsHuvxYmwXmAkNsSnhMfSCxsck9y6zuNeH0ovzBD90nISIJw+c
VAnUt0dzc7YKjBqThHRAvi8HoGZlzB7Ryb8ePSW+Mfr4jcH3Mio5T0OH3HTavN6Y
zpnohzQo0blwtwEXZOwrNPjQNrSigdPDrtvM32+hLTIJ75Z2NbIRLBjNlwznu7dQ
Asb/AiPTHXihxCRDm+dH70dps5JfT5Zg9LKsPhANk6fNK3e4wdN89ybQsBaswp9h
xzORVD3UiG4LuqP4LMCadjoEazShEiiveeRBgyiFlIldybuPwSq/gUuFveV5Jnqt
txNG6DnJBlIeYhVlA25XDMjxnJ3w6mi/pZyn9ZR9+hFic7Nm1ra7hRUoigfD/lS3
3AsDoRLy0xZqCWGRUbkhlo9VjDxo5znjv870Td1/+fp9QzSaESPfFAUBFcykDXIU
f1nVeKAkmhkEC9/jGF+VpUsuRV3pjjrLMcuI3+IimfWhWK1C56JJakfT3WB6nwY3
A92g4fyVGaWFKfj83tTNL2rzMkfraExPEP+VGesr8b/QMdBlZRR4WEYG3ObD2v/7
jgOS2Ol4gq8/QdNejP5J4wsCAQM=
-----END PUBLIC KEY-----`)

func main() {
    block, _ := pem.Decode(signingPubKey)
    if block == nil {
        fmt.Errorf("expected block to be non-nil", block)
        return
    }

    var pubkey dsa.PublicKey

    _,err := asn1.Unmarshal(block.Bytes, &pubkey)
    if (err != nil ){
        fmt.Errorf("could not unmarshall data: `%s`", err)
    }

    fmt.Printf("public key param P: %d\n", pubkey.Parameters.P)
    fmt.Printf("public key param Q: %d\n", pubkey.Parameters.Q)
    fmt.Printf("public key param G: %d\n", pubkey.Parameters.G)
    fmt.Printf("public key Y: %d\n", pubkey.Y)

    fmt.Printf("done")
}

Which outputs nil for all values, so obviously the Unmarshal call isn't doing what I want (or something is wrong earlier in the pipeline).

Upvotes: 1

Views: 513

Answers (1)

Gru
Gru

Reputation: 965

I know this is an old question, as there has been no answer for this and I couldn't find anything similar, here is my implementation


pubKeyPath := "./pubKey.pem"
pubKeyBytes, err := ioutil.ReadFile(pubKeyPath)

if err != nil {
   fmt.Println("Something went wrong when reading the file. Failed with", err)
}

pubBlock, _ := pem.Decode(pubKeyBytes)

// This returns a *dsa.PublicKey, but your IDE might complain
// that its not.
pubKey, err := x509.ParsePKIXPublicKey(pubBlock.Bytes)

// So, type assert:
dsaPubKey, ok := pubKey.(*dsa.PublicKey)

if !ok {
   fmt.Println("Failed to type assert")
}

// Verify something with the Public key
type Person struct {
  email  string 
}

// Assuming that a similar instance of the struct was used for signing
person := Person{ email: "[email protected]" }
personByteArray, _ := json.Marshal(person)

// r and s are what you get after signing. Using it here to verify
fmt.Println(dsa.Verify(dsaPubKey, personByteArray, r, s))

The above implementation reads the contents of the public key everytime the code is run.

If you are generating an executable and would like the contents of the public key to be embedded in the binary when you run go build, use the embed package available in go's stdlib

import _ from "embed"

//go:embed pubKey.pem
var pubKeyBytes []byte  

The above code snippet will load the public key as bytes at compile time. This will enable us to read from the file system only once!

Upvotes: 1

Related Questions