2013-04-15 4 views
6

У меня есть двоичный файл:Проверка подписи с использованием go.crypto/OpenPGP

foo.bin 

Этот файл был подписан с помощью ключа GPG для создания:

foo.bin.sig 

У меня есть файл, содержащий открытый ключ, который использовался для подписи двоичного файла.

Что я хотел бы сделать, так это проверить эту подпись, используя Go.

Я читал документы go.crypto/openpgp, и они не особенно полезны для этого варианта использования.

Проверка будет выполнена на удаленной машине. В идеале я бы хотел избежать использования брелка на машине, которая будет запускать этот код. Открытый ключ может тривиально храниться в самом исполняемом файле ... если я смогу решить, как выполнить эту проверку.

шаги, которые я думаю, что мне нужно сделать это следующим образом:

  • создать объект, который представляет только открытый ключ
  • Открыть как двоичный файл и подпись и передать его в какой-то функции проверки

Вопрос в первую очередь заключается в следующем: как написать эту функцию проверки, используя только открытый ключ?

+0

Я не совсем понимаю ваши требования. Можно ли заменить проверку gpg другими методами, такими как SHA256/MD5/RSA ...? –

+0

Согласно википедии, подпись openpgp является сигнатурой хэша файла. Подпись выполняется с использованием rsa или dsa, и хеш может быть выполнен с использованием многих алгоритмов. Я думаю, вам нужно понять файл '.sig', чтобы проверить подпись. Затем пакет [crypto] (http://golang.org/pkg/crypto/) должен иметь все необходимые методы. Если вы нашли документацию об определении файла .sig (я не нашел его), разместите его здесь. Я тоже хотел бы это увидеть. – user983716

ответ

4

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 

Если файл, который вы подписали очень большой, вы можете изменить код немного, чтобы не нагружать его в памяти.

+0

В моем случае подпись и открытый ключ были бронированы, поэтому мне нужно было использовать пакет «armor» для декодирования соответствующих блоков: https://gist.github.com/FZambia/f91ddffb1a2b776d56e1988c6048e4d8 –

Смежные вопросы