【问题标题】:Verifying a signature using go.crypto/openpgp使用 go.crypto/openpgp 验证签名
【发布时间】:2013-04-15 04:33:41
【问题描述】:

我有一个二进制文件:

foo.bin

此文件已使用 gpg 密钥签名以创建:

foo.bin.sig

我有一个包含用于签署二进制文件的公钥的文件。

我想做的是能够使用 Go 来验证这个签名。

我正在阅读 go.crypto/openpgp 文档,它们对这个用例并不是特别有用。

验证将在远程计算机上完成。理想情况下,我想避免在运行此代码的机器上使用密钥环。公钥可以简单地存储在可执行文件本身中......如果我能弄清楚如何完成此验证。

我认为我需要做的步骤如下:

  • 创建仅代表公钥的实体
  • 打开二进制文件和签名并将其传递给某个验证函数

问题主要是:如何仅使用公钥编写此验证函数?

【问题讨论】:

  • 我不清楚您的要求。 gpg密钥验证可以用SHA256/MD5/RSA...等其他方法代替吗?
  • 根据维基百科,openpgp 签名是文件哈希的签名。签名使用 rsa 或 dsa 完成,散列可以使用许多算法完成。我认为您需要了解.sig 文件来验证签名。那么crypto 包应该有你需要的所有方法。如果你找到关于 .sig 文件定义的文档(我没找到),请放在这里。我也想看看。

标签: go openpgp


【解决方案1】:

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

如果您已签名的文件很大,您可能需要稍微更改代码以避免将其加载到内存中。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-11
  • 2011-09-22
  • 2012-08-22
  • 2012-01-16
  • 1970-01-01
相关资源
最近更新 更多