The openpgp API is not the easiest to use, but I gave it a pass (pun intended) and this is what I came up with:
package main import ( "bytes" "code.google.com/p/go.crypto/openpgp/packet" "encoding/hex" "errors" "fmt" "io/ioutil" "os" ) // gpg --export YOURKEYID --export-options export-minimal,no-export-attributes | hexdump /dev/stdin -v -e '/1 "%02X"' var publicKeyHex string = "99[VERY LONG HEX STRING]B6" func main() { if len(os.Args) != 3 { fmt.Println("Usage: " + os.Args[0] + " <file> <signature file>") return } err := checkSig(os.Args[1], os.Args[2]) if err != nil { fmt.Println("Invalid signature : ") fmt.Println(err) } else { fmt.Println("Valid signature") } } func checkSig(fileName string, sigFileName string) error { // First, get the content of the file we have signed fileContent, err := ioutil.ReadFile(fileName) if err != nil { return err } // Get a Reader for the signature file sigFile, err := os.Open(sigFileName) if err != nil { return err } defer func() { if err := sigFile.Close(); err != nil { panic(err) } }() // Read the signature file pack, err := packet.Read(sigFile) if err != nil { return err } // Was it really a signature file ? If yes, get the Signature signature, ok := pack.(*packet.Signature) if !ok { return errors.New(os.Args[2] + " is not a valid signature file.") } // For convenience, we have the key in hexadecimal, convert it to binary publicKeyBin, err := hex.DecodeString(publicKeyHex) if err != nil { return err } // Read the key pack, err = packet.Read(bytes.NewReader(publicKeyBin)) if err != nil { return err } // Was it really a public key file ? If yes, get the PublicKey publicKey, ok := pack.(*packet.PublicKey) if !ok { return errors.New("Invalid public key.") } // Get the hash method used for the signature hash := signature.Hash.New() // Hash the content of the file (if the file is big, that where you have to change the code to avoid getting the whole file in memory, by reading and writting in small chunks) _, err = hash.Write(fileContent) if err != nil { return err } // Check the signature err = publicKey.VerifySignature(hash, signature) if err != nil { return err } return nil }
As requested, I put the public key in the code. You can check it as follows:
$ go run testpgp.go foo.bin foo.bin.sig
If the file you signed is very large, you can change the code a bit so as not to load it into memory.
source share