2013-04-15 15 views
6

Ho un file binario:Verifica di una firma utilizzando go.crypto/OpenPGP

foo.bin 

Questo file è stato firmato con una chiave gpg per creare:

foo.bin.sig 

Ho un file che contiene il chiave pubblica che è stata utilizzata per firmare il file binario.

Quello che mi piacerebbe fare è essere in grado di verificare questa firma usando Go.

Stavo leggendo i documenti go.crypto/openpgp e non sono particolarmente utili per questo caso d'uso.

La verifica verrà eseguita su una macchina remota. Idealmente mi piacerebbe evitare di usare il portachiavi sulla macchina che eseguirà questo codice. La chiave pubblica può essere banalmente archiviata nell'eseguibile stesso ... se riesco a capire come ottenere questa verifica.

I passi che penso ho bisogno di fare sono i seguenti:

  • Creare un'entità che rappresenta solo la chiave sia il file binario
  • Aprire pubblica e la firma e passarlo a qualche funzione di verifica

La domanda è principalmente: come posso scrivere questa funzione di verifica utilizzando solo una chiave pubblica?

+0

Non sono sicuro del tuo fabbisogno. La verifica della chiave gpg può essere sostituita con altri metodi come SHA256/MD5/RSA ...? –

+0

Secondo wikipedia, una firma openpgp è una firma dell'hash del file. La firma viene eseguita usando rsa o dsa e l'hash può essere fatto usando molti algoritmi. Penso che tu abbia bisogno di capire il file '.sig' per verificare la firma. Quindi il pacchetto [crypto] (http://golang.org/pkg/crypto/) dovrebbe avere tutti i metodi necessari. Se si trova la documentazione sulla definizione del file .sig (non l'ho trovata), inserirla qui. Mi piacerebbe vederlo anche io. – user983716

risposta

4

Il OpenPGP API non è il più facile da usare, ma mi ha dato un andare (gioco di parole), e qui è quello che mi si avvicinò con:

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 
} 

Come richiesto, ho messo la chiave pubblica nel codice. È possibile verificare in quel modo:

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

Se il file che avete firmato è molto grande, si consiglia di modificare il codice un po 'per evitare di caricare in memoria.

+0

Nel mio caso la firma e la chiave pubblica erano blindate quindi ho dovuto usare il pacchetto 'armor' per decodificare i blocchi corrispondenti: https://gist.github.com/FZambia/f91ddffb1a2b776d56e1988c6048e4d8 –