Reputation: 2244
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
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