6

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?

4

1 に答える 1

6

openpgp API は使用するのが最も簡単ではありませんが、私はそれを試してみました (しゃれを意図しました)。ここに私が思いついたものがあります:

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
}

リクエストに応じて、公開鍵をコードに入れました。そのようにテストできます:

$ go run testpgp.go foo.bin foo.bin.sig

署名したファイルが非常に大きい場合は、メモリに読み込まれないようにコードを少し変更することをお勧めします。

于 2013-12-30T13:10:20.223 に答える