Golang pgp without secring - go

I have an app that uses gpg secret keys and prompts for a password to read it. Here's the way I do that (based on an example I found elsewhere:
func Decrypt(publicKeyring string, secretKeyring string, key string, password string) (string, error) {
var entity *openpgp.Entity
var entityList openpgp.EntityList
keyringFileBuffer, err := os.Open(secretKeyring)
if err != nil {
return "", err
}
defer keyringFileBuffer.Close()
entityList, err = openpgp.ReadKeyRing(keyringFileBuffer)
if err != nil {
return "", err
}
entity = entityList[0]
passphraseByte := []byte(password)
entity.PrivateKey.Decrypt(passphraseByte)
for _, subkey := range entity.Subkeys {
subkey.PrivateKey.Decrypt(passphraseByte)
}
dec, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return "", err
}
// Decrypt it with the contents of the private key
md, err := openpgp.ReadMessage(bytes.NewBuffer(dec), entityList, nil, nil)
if err != nil {
return "", err
}
bytes, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
return "", err
}
decStr := string(bytes)
return decStr, nil
}
The assumption made here is that the user has a KeyRin which is passed, and the default value for this is the secring, like so:
viper.SetDefault("gpgsecretkeyring", home+"/.gnupg/secring.gpg")
However,
I was getting reports that some users on macs were struggling to get the app working, and the reason was they didn't know how to define the secring.
It seems newer versions of GnuPG have deprecated the secring.
https://www.gnupg.org/faq/whats-new-in-2.1.html#nosecring
I have no idea how to read the secret key using golang.org/x/crypto/openpgp at this point. Are there any examples of the best way to do this?

GnuPG 2.1 introduced two changes:
Merging the secring.gpg into the pubring.gpg file, you should be able to read the secret keys from the pubring.gpg file.
For new installations, the new keybox format is used, which is not supported by the go library (as of today, at least). Old installations (thus, with keyrings in the old format), are not automatically merged.
If you want to use GnuPG's keyring, directly call GnuPG. If you want to use Go's library, don't mess with GnuPG's keyring files and store your own copy of the keys.

I got sick of dealing with this, so I've decided it's easier to just shell out to gpg -dq from the os.Exec. Sample:
package gpg
import (
"bytes"
"encoding/base64"
"os/exec"
)
func Decrypt(key string) (string, error) {
var cmd exec.Cmd
var output bytes.Buffer
gpgCmd, err := exec.LookPath("gpg")
if err != nil {
return "", err
}
cmd.Path = gpgCmd
cmd.Args = []string{"--decrypt", "--quiet"}
dec, err := base64.StdEncoding.DecodeString(key)
if err != nil {
return "", err
}
// return the reader interface for dec (byte array)
d := bytes.NewReader(dec)
// pipe d to gpg commands stdin
cmd.Stdin = d
cmd.Stdout = &output
if err := cmd.Run(); err != nil {
return "", err
}
// return the output from the gpg command
return output.String(), nil
}

Related

Golang crypto/rsa problem decrypting text using private key from PEM file

So i'm building a basic generator/encryptor/decryptor for RSA keys in Golang.
I have four main functions.
GenKeys() generates the key pair using rsa.GenerateKey, then writes this private key to a pem file.
GetKeys() Gets the private key from the pem file.
Encrypt() Encrypts a string manually entered into the console and then spits out the ciphertext
Decrypt() Takes in the cipher text and decrypts it, using the GetKeys function to get the private key from the pem file.
The GenKeys function works fine. And the Encrypt function works fine. Entering a string and spitting out a cipher text.
But I get crypto/rsa: decryption error when I run the decrypt flag.
Tried:
The private key is identical when I gen the key to when i Import it again from the pem file.
Ive tried the different decryption methods included in the crypto package.
I've tried just importing the ciphertext directly from the encrypt method into the decrypt, just in case there was a problem when spitting it out to console.
To note:
This worked when I only wrote the private key to memory, instead of spitting it out to a file, which tells me that something is going wrong when importing the key again from the pem file. But I cant figure out what.
Please if somebody could look through my code and tell me if im missing something I'd be eternaly grateful.
main.go
func main() {
var action = flag.String("action", "", "Whether to decrypt or encrypt")
flag.Parse()
task := *action
var err error
if task == "gen" {
//gen the priv key and write to file
err = services.GenKeys()
if err != nil {
fmt.Println("Could not generate keys:", err)
}
}
if task == "encrypt" {
//Get key from file
privateKey, err := services.GetKeys()
if err != nil {
fmt.Println("Could not retrieve key file", err)
return
}
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter the text you would like to encrypt: ")
text, _ := reader.ReadString('\n')
cipherText, err := services.Encrypt(&privateKey.PublicKey, text)
if err != nil {
fmt.Println("Could not encrypt", err)
return
}
fmt.Printf("Encrypted message: %x", cipherText)
}
if task == "decrypt" {
//Get key from file
privateKey, err := services.GetKeys()
if err != nil {
fmt.Println("Could not retrieve key file", err)
}
reader := bufio.NewReader(os.Stdin)
fmt.Println("Please enter the cypher text you would like to decrypt: ")
text, _ := reader.ReadString('\n')
decryptedText, err := services.Decrypt(privateKey, []byte(text))
if err != nil {
fmt.Println("Could not decrypt text", err.Error())
return
}
fmt.Println("decrypted text: ", string(decryptedText))
}
}
crypto_service.go
func Encrypt(pub *rsa.PublicKey, text string) ([]byte, error) {
encryptedBytes, err := rsa.EncryptOAEP(
sha256.New(),
rand.Reader,
pub,
[]byte(text),
nil)
if err != nil {
return nil, err
}
return encryptedBytes, nil
}
func Decrypt(privKey *rsa.PrivateKey, cipherText []byte) ([]byte, error) {
decryptedBytes, err := rsa.DecryptOAEP(sha256.New(), nil, privKey, cipherText, nil)
if err != nil {
return nil, err
}
return decryptedBytes, nil
}
gen_keys_service.go
func GenKeys() error {
privKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return err
}
privFile, err := os.Create("private_key.pem")
if err != nil {
return err
}
pemData := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(privKey),
}
err = pem.Encode(privFile, pemData)
if err != nil {
return err
}
privFile.Close()
fmt.Println("Your keys have been written to private_key.pem")
return nil
}
func GetKeys() (*rsa.PrivateKey, error) {
file, err := os.Open("private_key.pem")
if err != nil {
return nil, err
}
defer file.Close()
//Create a byte slice (pemBytes) the size of the file size
pemFileInfo, _ := file.Stat()
var size = pemFileInfo.Size()
pemBytes := make([]byte, size)
//Create new reader for the file and read into pemBytes
buffer := bufio.NewReader(file)
_, err = buffer.Read(pemBytes)
if err != nil {
return nil, err
}
//Now decode the byte slice
data, _ := pem.Decode(pemBytes)
if data == nil {
return nil, errors.New("could not read pem file")
}
privKeyImport, err := x509.ParsePKCS1PrivateKey(data.Bytes)
if err != nil {
return nil, err
}
return privKeyImport, nil
}
Oh and heres the format of my pem file:
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEApX2AUrhtH3FHSds3JAWmBDZcSwixydY/M52WmWfqDmQDRc6X
V4FqLyiEIMSq3Z7zOR9GH4a2Ps3HPlTvJa2EGkgKDk7hVRWlocbQvRsdSk/aEZ7U
O0SgB6s0H2/9MdWsXaJHADuUJYlSgG+VH7vf5uIi4w8OKNfmHfB7uJQJByb4+8jg
rzMFgmFyEUnWOgUh3dXtdV1XD5BPQiDk2D8vYR8JUjK9uWHVMaR2y51uK3vNZHmR
/ce1g36Gzhl5aRfUqJ8gWLCsJ42VEDHznz04YvrH/DRrcuSb/65JlpQMOKr9wdf/
/sILXkeEylifeZoUENRbgIz5UCyyQtTrfCMcDwIDAQABAoIBAQCBVx41CKlY2rsh
0TA+eh+vySDHECuMGWPaHn92tE2tI6OfKoEERkRMSTlDNxJoFfP4oCW5PBsx6Lih
UdZ7Nys5MzaQyju4uStzziSUuB1jWBeSj/VFwTPl6nvZWjike2C06cDeQLJfx/zw
HsWJQNgU5obnuXuSlnLm0W6Q6zpHGH/GdtS6O5kLjLySgb87xDTivdKEH5iqUNRe
fs6WTJpsKsT92lT/AcO/QUuw7sK/GSW2spnzO8xF4ZdQhjj72NkWqa/K/ncfKhuk
eI/+1HPvSru+nOJts6j3Xd98EQbIDBVZLArl6gB49B6UsEogAYgRJAs5mIIHzxRS
YfiQckzRAoGBAMijQPc+ygZ9pTNLOCi7zHQtHHOj8lMGuqQKTFsDIxVGI7Iy6tm/
CQbbpZiQiDoskCSJq3pWcydu+csDmdq/PrTJ4yuJMAgUaOItvuNu5vS3nOGPiJBl
0zDERW2GA0jcE4STreVM5GR3kOgNG8EIbmjVC1eQqhKK7a0+kPbYqYBnAoGBANMn
e6VcmL19WNIEYHyXLdCOaPj7LOMmAA2SNRA7V4YkaXbgRSHmnHboHEVzytSJH9gY
mmZ9+8dkq9n+ODi1vn2hCR9TIJHapn8aWHOqgnZesJ2xThV78S8Kp8jZD4lx8Ejy
5t3TMVIZ6hQXWfkQjpKs3QAXJszrZR0Cb0sJOp4ZAoGAVb3mmoKbxXBWc/g2NLok
4pUQrp6mhTK/+jBodxB9Iq9Ju/KkiI9qJSMivnMttGas5uBqhqqBJZ34Y/jS/Dd0
bcBFM6q5+wn11IqmI/2V94isI3y6aLMLMLD/1pFJwA5EzQhrbS2SARlTtMc9UB3x
SR2abj5lX+09KycsvkDTFwsCgYEAhG4b509W4GlQHo/uL9XlPwtCHP3zXhdEKz7K
lv6Q2ynVF2B7G1L2SME0kf6YdIn39eEgXS2gjqK+AX+mpTKfYU1xWjsZj0CR8d+F
IC4Nms2yeYRtU54jWvyU1KwGSY6zRB1L3E4LfdGQ9L7ciA/xS16tUNQ0Wos8JGCV
inskT2kCgYBg4zzkUAmQ75hlRsM0r7ezrx4xt8GHrlxwOTeQYgVcymiSSMXVITNI
ByBfs+wqV7PrXjM69xPdV/CHczFcA7g/M0o0CJZhWead403knjZmGFlZypvWskOT
aK4nArJ0zaS7FGhCe24QORYZPGjCzg7dLKhKDvK1PB4ogRVo4dDckA==
-----END RSA PRIVATE KEY-----
In the encryption part the ciphertext is displayed hex encoded. If it is entered hex encoded in the decryption part, it must be hex decoded accordingly, which is missing in the posted code. The hex decoding can be done with the hex package.
Also, as mentioned in Peter's comment, the trailing newline must be removed, e.g. with strings.TrimSuffix(). Alternatively, fmt.Scan() or bufio.Scanner can be used instead of bufio.Reader. The last two options do not return the trailing newline.
Possible implementation (for simplicity without exception handling):
...
var text string
fmt.Println("Please enter the ciphertext you would like to decrypt: ")
fmt.Scan(&text)
textHexDec, _ := hex.DecodeString(text)
decryptedText, _ := Decrypt(privateKey, textHexDec)
fmt.Println("Decrypted text: ", string(decryptedText))
...

Golang decrypt PGP from openpgp.js

Need a help here with a symmetric PGP decryption in Golang, I've been trying to run symmetrical decryption on an encrypted hex generated on OpenPGP.js, unfortunately, no success to decrypt in Golang. This is the encryption in JS.
const openpgp = require('openpgp')
async function main() {
let options = {
message: openpgp.message.fromBinary(new Uint8Array([0x01, 0x01, 0x01])), // input as Message object
passwords: ['secret stuff'], // multiple passwords possible
armor: false // don't ASCII armor (for Uint8Array output)
}
const cypher_text = await openpgp.encrypt(options)
const encrypted = cypher_text.message.packets.write()
console.log(Buffer.from(encrypted).toString('hex'))
options = {
message: await openpgp.message.read(encrypted), // parse encrypted bytes
passwords: ['secret stuff'], // decrypt with password
format: 'binary' // output as Uint8Array
}
const decrypted = await openpgp.decrypt(options)
console.log(decrypted.data)
}
main()
console.log >>
c32e040903088c4db97456263252e0ef4f42627301e0ba3323b141a9ebd0476e5fe848d3c2b6021c8c06581ae2d19f7cd23b011b4b3a68758cb6fb12287db2a9ab6fdfad97670ae995e4deb7ca313d0aa705d264850adefb20353b263fc32ff8dc571f6dce8b722ddbdf40a907
Uint8Array [ 1, 1, 1 ]
My code is based on the following GIST https://gist.github.com/jyap808/8250124
package main
import (
"bytes"
"errors"
"io/ioutil"
"log"
"golang.org/x/crypto/openpgp/armor"
"golang.org/x/crypto/openpgp/packet"
"golang.org/x/crypto/openpgp"
)
func main() {
password := []byte("secret stuff")
packetConfig := &packet.Config{
DefaultCipher: packet.CipherAES256,
}
cypherHex := []byte("c32e040903088c4db97456263252e0ef4f42627301e0ba3323b141a9ebd0476e5fe848d3c2b6021c8c06581ae2d19f7cd23b011b4b3a68758cb6fb12287db2a9ab6fdfad97670ae995e4deb7ca313d0aa705d264850adefb20353b263fc32ff8dc571f6dce8b722ddbdf40a907")
encbuf := bytes.NewBuffer(nil)
w, err := armor.Encode(encbuf, openpgp.SignatureType, nil)
if err != nil {
log.Fatal(err)
}
w.Write(cypherHex)
encbuf.Read(cypherHex)
w.Close()
log.Println(encbuf)
decbuf := bytes.NewBuffer([]byte(encbuf.String()))
armorBlock, err := armor.Decode(decbuf)
if err != nil {
log.Fatalf("Failed on decode %+v\n", err)
}
failed := false
prompt := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
if failed {
return nil, errors.New("decryption failed")
}
return password, nil
}
md, err := openpgp.ReadMessage(armorBlock.Body, nil, prompt, packetConfig)
if err != nil {
log.Fatalf("Failed on read message %+v\n", err)
}
plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
log.Fatalf("Failed on read all body %+v\n", err)
}
log.Println(plaintext)
}
I noticed after log the encbuf that the armored key is kind of incomplete
2020/01/24 22:51:54 jcwYWU5
OTVlNGRlYjdjYTMxM2QwYWE3MDVkMjY0ODUwYWRlZmIyMDM1M2IyNjNmYzMyZmY4
ZGM1NzFmNmRjZThiNzIyZGRiZGY0MGE5MDc=
=9ciH
-----END PGP SIGNATURE-----
Update: Trying to decrypt without armor as well, if fails with EOF
import (
"bytes"
"io/ioutil"
"log"
"golang.org/x/crypto/openpgp"
"golang.org/x/crypto/openpgp/packet"
)
func main() {
password := []byte("secret stuff")
packetConfig := &packet.Config{
DefaultCipher: packet.CipherAES128,
}
cypherHex := []byte("c32e040903088c4db97456263252e0ef4f42627301e0ba3323b141a9ebd0476e5fe848d3c2b6021c8c06581ae2d19f7cd23b011b4b3a68758cb6fb12287db2a9ab6fdfad97670ae995e4deb7ca313d0aa705d264850adefb20353b263fc32ff8dc571f6dce8b722ddbdf40a907")
encbuf := bytes.NewBuffer(nil)
encbuf.Read(cypherHex)
prompt := func(keys []openpgp.Key, symmetric bool) ([]byte, error) {
return password, nil
}
md, err := openpgp.ReadMessage(encbuf, nil, prompt, packetConfig)
if err != nil {
log.Fatalf("Failed on read message %+v\n", err)
}
plaintext, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
log.Fatalf("Failed on read all body %+v\n", err)
}
log.Println(plaintext)
}
First, you're not decoding the hex-encoded ciphertext. Use the encoding/hex package to decode the data:
ct, err := hex.DecodeString(`c32e040903088c4db97456263252e0ef4f42627301e0ba3323b141a9ebd0476e5fe848d3c2b6021c8c06581ae2d19f7cd23b011b4b3a68758cb6fb12287db2a9ab6fdfad97670ae995e4deb7ca313d0aa705d264850adefb20353b263fc32ff8dc571f6dce8b722ddbdf40a907`)
if err != nil {
log.Fatal(err)
}
Next problem is that you're incorrectly creating the bytes.Buffer. You're putting no data into the buffer, then calling the Read method which does nothing (and of you did initialize it with data, Read would "read" all the data out before you decrypt it anyway). The buffer could be initialized with the data, or filled using the Write method -- in this case you only need an io.Reader and can use bytes.NewReader.
r := bytes.NewReader(ct)
Finally, you now have 3 0x01 bytes, which you can see more clearly using a better formatting:
d, err := ioutil.ReadAll(md.UnverifiedBody)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%#v\n", d)
https://play.golang.org/p/Y3VqADQvEIH

Encrypting/Decrypting JWE with Jose in Go

I'm trying to create a JWE decryption function but having trouble determining how to use the Go Jose interface for doing so. I've factored the encryption using passphrase (I prefer a passphrase for this use case):
token := jwt.NewWithClaims(
jwt.SigningMethodHS256,
claims,
)
ss, err := token.SignedString("thisisatestpassphraserighthere")
if err != nil {
panic("COULD_NOT_GENERATE")
return
}
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
publicKey := &privateKey.PublicKey
encrypter, err := jose.NewEncrypter(
jose.A128CBC_HS256,
jose.Recipient{Algorithm: jose.RSA_OAEP, Key: publicKey},
nil,
)
if err != nil {
return
}
object, err := encrypter.Encrypt([]byte(ss))
if err != nil {
errRes = s.Error(codes.Internal, err, nil)
return
}
key, err := object.CompactSerialize()
if err != nil {
errRes = s.Error(codes.Internal, err, nil)
return
}
fmt.Println(key)
The above code creates a JWT, encodes it, compacts it and returns the key. It's not however totally clear how to decrypt it with the passphrase now.
There is an example for JWE on the Jose docs: https://godoc.org/gopkg.in/square/go-jose.v2#example-Encrypter--Encrypt
So I've factored this:
object, err = jose.ParseEncrypted(Key)
if err != nil {
panic(err)
}
decrypted, err := object.Decrypt(...)
Inside the ellipses I'm not sure what to put though. I can't seem to determine how to pass in a key based on passphrase.
I was doing a few things wrong it seems. First of all rsa.GenerateKey uses a randomized value. This was totally wrong :-p the following is how you can encrypt a JWT into a JWE using a token:
rcpt := jose.Recipient{
Algorithm: jose.PBES2_HS256_A128KW,
Key: "mypassphrase",
PBES2Count: 4096,
PBES2Salt: []byte{ your salt... },
}
enc, err := jose.NewEncrypter(jose.A128CBC_HS256, rcpt, nil)
if err != nil {
panic("oops")
}
jewPlaintextToken, err := enc.Encrypt(jwtToken)
if err != nil {
panic("oops")
}
key, err := object.CompactSerialize()
if err != nil {
panic("oops")
}
This is how you decrypt:
// Decrypt the receive key
jwe, err := jose.ParseEncrypted(jewPlaintextToken)
if err != nil {
panic("oops")
}
decryptedKey, err := jwe.Decrypt("mypassphrase")
if err != nil {
panic("oops")
}
If anyone sees any major problems/security issues with this method, please mention it.
Inside the ellipses I'm not sure what to put though. I can't seem to determine how to pass in a key based on passphrase.
From the JWE example in the documentation, you must pass the private key. See the below part for decryption
https://godoc.org/gopkg.in/square/go-jose.v2#JSONWebEncryption.Decrypt
// Generate a public/private key pair to use for this example.
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
panic(err)
}
// Parse the serialized, encrypted JWE object. An error would indicate that
// the given input did not represent a valid message.
object, err = ParseEncrypted(serialized)
if err != nil {
panic(err)
}
// Now we can decrypt and get back our original plaintext. An error here
// would indicate the the message failed to decrypt, e.g. because the auth
// tag was broken or the message was tampered with.
decrypted, err := object.Decrypt(privateKey)
if err != nil {
panic(err)
}
fmt.Printf(string(decrypted))

How to add expiry to JWE token?

I'm using Jose library to create JWE's. I have successfully managed to create and parse JWE. JWT has fields like exp, iat which help in invalidating token after a certain period of time.How can I set expiry on JWE ?
Here's what I've tried, without exp:
package main
import (
jose "gopkg.in/square/go-jose.v2"
)
// len(key) is 32
func CreateJWE(value, key string)(string, error){
encrypter, err := jose.NewEncrypter(jose.A256GCM, jose.Recipient{Algorithm: jose.A256GCMKW, Key: []byte(key)}, nil)
if err != nil {
return "", err
}
object, err := encrypter.Encrypt([]byte(value)])
if err != nil {
return "", err
}
return object.FullSerialize(), nil
}
func ParseJWE(jwe, key string)(string, error){
object, err := jose.ParseEncrypted(jwe)
if err != nil {
return "", err
}
b, err := (*object).Decrypt(key)
return string(b), err
}
JWEs do not have expiration
u should use JWT for resolve it
look at this Q&A in github
and this stackoverflow question, it's for python but i tell it for reading and open ur mind about this subject

Verifying a signature using go.crypto/openpgp

I have a binary file:
foo.bin
This file has been signed using a gpg key to create:
foo.bin.sig
I have a file containing the public key that was used to sign the binary file.
What I'd like to do is to be able to verify this signature using Go.
I was reading the go.crypto/openpgp docs and they aren't particularly helpful for this use case.
The verification will be done on a remote machine. Ideally I'd like to avoid using the keyring on the machine that will run this code. The public key can trivially be stored in the executable itself... if I can work out how to get this verification done.
The steps that I think I need to do are as follows:
Create an Entity that represents only the public key
Open both the binary file and the signature and pass it to some verification function
The question primarily is: how do I write this verification function using just a public key?
The openpgp API is not the most straightforward to use, but I gave it a go (pun intended), and here 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's 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 test it like that :
$ go run testpgp.go foo.bin foo.bin.sig
If the file you have signed is very big, you may want to change the code a little bit to avoid loading it in memory.

Resources