2013-04-15 15 views
6

Tôi có một tập tin nhị phân:Thẩm định chữ ký sử dụng go.crypto/OpenPGP

foo.bin 

Tập tin này đã được ký kết dùng một khoá GPG để tạo ra:

foo.bin.sig 

Tôi có một tập tin có chứa các khóa công khai được sử dụng để ký tên tệp nhị phân.

Điều tôi muốn làm là có thể xác minh chữ ký này bằng Go.

Tôi đã đọc tài liệu go.crypto/openpgp và chúng không đặc biệt hữu ích cho trường hợp sử dụng này.

Quá trình xác minh sẽ được thực hiện trên máy từ xa. Lý tưởng nhất là tôi muốn tránh sử dụng keyring trên máy sẽ chạy mã này. Khóa công khai có thể được lưu trữ một cách trivially trong bản thân thực thi ... nếu tôi có thể tìm ra cách thực hiện xác minh này.

Các bước mà tôi nghĩ rằng tôi cần phải làm như sau:

  • Tạo một Entity mà chỉ đại diện cho cộng đồng quan trọng
  • mở cả các tập tin nhị phân và chữ ký và vượt qua nó để một số chức năng xác minh

Câu hỏi chủ yếu là: làm cách nào để viết chức năng xác minh này chỉ sử dụng khóa công khai?

+0

Tôi không rõ ràng về yêu cầu của bạn. Có thể thay thế khóa gpg bằng các phương thức khác như SHA256/MD5/RSA ... không? –

+0

Theo wikipedia, chữ ký openpgp là chữ ký của hàm băm của tệp. Chữ ký được thực hiện bằng cách sử dụng rsa hoặc dsa và băm có thể được thực hiện bằng cách sử dụng nhiều thuật toán. Tôi nghĩ bạn cần hiểu tệp '.sig' để xác minh chữ ký. Sau đó, gói [crypto] (http://golang.org/pkg/crypto/) sẽ có tất cả các phương thức bạn cần. Nếu bạn tìm thấy tài liệu về định nghĩa tệp .sig (tôi không tìm thấy), vui lòng đặt nó ở đây. Tôi cũng muốn thấy điều đó. – user983716

Trả lời

4

Các OpenPGP API không phải là đơn giản nhất để sử dụng, nhưng tôi đã cho nó một đi (ý định chơi chữ), và đây là những gì tôi đã đưa ra:

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 
} 

Theo yêu cầu, tôi đặt khóa công khai trong mã. Bạn có thể kiểm tra nó như thế:

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

Nếu tập tin bạn đã đăng nhập là rất lớn, bạn có thể muốn thay đổi mã một chút để tránh tải nó trong bộ nhớ.

+0

Trong trường hợp chữ ký của tôi và khóa công khai được bọc thép nên tôi cần sử dụng gói 'armor' để giải mã các khối tương ứng: https://gist.github.com/FZambia/f91ddffb1a2b776d56e1988c6048e4d8 –