2013-04-15 16 views
6

Mam plik binarny:Weryfikacja podpisu używając go.crypto/OpenPGP

foo.bin 

Ten plik został podpisany przy użyciu klucza gpg utworzyć:

foo.bin.sig 

Mam plik zawierający klucz publiczny, który został użyty do podpisania pliku binarnego.

Chciałbym móc zweryfikować ten podpis za pomocą polecenia Go.

Czytałem dokumentację go.crypto/openpgp i nie są one szczególnie pomocne w tym przypadku użycia.

Weryfikacja zostanie przeprowadzona na zdalnym komputerze. Idealnie chciałbym uniknąć użycia keyring na komputerze, który uruchomi ten kod. Klucz publiczny może być banalnie przechowywany w samym pliku wykonywalnym ... jeśli mogę się dowiedzieć, jak wykonać tę weryfikację.

Kroki, które myślę, że trzeba zrobić to w następujący sposób:

  • Tworzenie podmiotu, który reprezentuje tylko kluczową
  • otwarty zarówno plik binarny publicznego oraz podpis i przekazać go do jakiejś funkcji weryfikacyjnej

Pytanie przede wszystkim brzmi: w jaki sposób mogę napisać tę funkcję weryfikacji za pomocą tylko klucza publicznego?

+0

Nie mam jasności co do Twojego wymagania. Czy weryfikację klucza gpg można zastąpić innymi metodami, takimi jak SHA256/MD5/RSA ...? –

+0

Zgodnie z wikipedia, podpis openpgp jest sygnaturą skrótu pliku. Podpis jest wykonywany przy użyciu rsa lub dsa, a hash można wykonać za pomocą wielu algorytmów. Myślę, że musisz zrozumieć plik '.sig', aby zweryfikować podpis. Wtedy pakiet [crypto] (http://golang.org/pkg/crypto/) powinien mieć wszystkie potrzebne metody. Jeśli znajdziesz dokumentację dotyczącą definicji pliku .sig (nie znalazłem tego), umieść go tutaj. Też chciałbym to zobaczyć. – user983716

Odpowiedz

4

openpgp API nie jest najbardziej proste w użyciu, ale dałem mu szansę (gra słów nie przeznaczonych), i oto co wymyśliłem:

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 
} 

Zgodnie z wnioskiem, kładę klucz publiczny w kodzie. Można przetestować go tak:

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

Jeśli plik został podpisany jest bardzo duża, może chcesz zmienić kod trochę, aby uniknąć ładowania go w pamięci.

+0

W moim przypadku podpis i klucz publiczny były zbrojone, więc musiałem użyć pakietu 'pancerz' do zdekodowania odpowiednich bloków: https://gist.github.com/FZambia/f91ddffb1a2b776d56e1988c6048e4d8 –