...

Source file src/github.com/jedisct1/go-minisign/minisign.go

Documentation: github.com/jedisct1/go-minisign

     1  package minisign
     2  
     3  import (
     4  	"encoding/base64"
     5  	"errors"
     6  	"io/ioutil"
     7  	"strings"
     8  
     9  	"golang.org/x/crypto/blake2b"
    10  	"golang.org/x/crypto/ed25519"
    11  )
    12  
    13  type PublicKey struct {
    14  	SignatureAlgorithm [2]byte
    15  	KeyId              [8]byte
    16  	PublicKey          [32]byte
    17  }
    18  
    19  type Signature struct {
    20  	UntrustedComment   string
    21  	SignatureAlgorithm [2]byte
    22  	KeyId              [8]byte
    23  	Signature          [64]byte
    24  	TrustedComment     string
    25  	GlobalSignature    [64]byte
    26  }
    27  
    28  func NewPublicKey(publicKeyStr string) (PublicKey, error) {
    29  	var publicKey PublicKey
    30  	bin, err := base64.StdEncoding.DecodeString(publicKeyStr)
    31  	if err != nil || len(bin) != 42 {
    32  		return publicKey, errors.New("Invalid encoded public key")
    33  	}
    34  	copy(publicKey.SignatureAlgorithm[:], bin[0:2])
    35  	copy(publicKey.KeyId[:], bin[2:10])
    36  	copy(publicKey.PublicKey[:], bin[10:42])
    37  	return publicKey, nil
    38  }
    39  
    40  func DecodePublicKey(in string) (PublicKey, error) {
    41  	var publicKey PublicKey
    42  	lines := strings.SplitN(in, "\n", 2)
    43  	if len(lines) < 2 {
    44  		return publicKey, errors.New("Incomplete encoded public key")
    45  	}
    46  	return NewPublicKey(lines[1])
    47  }
    48  
    49  func trimCarriageReturn(input string) string {
    50  	return strings.TrimRight(input, "\r")
    51  }
    52  
    53  func DecodeSignature(in string) (Signature, error) {
    54  	var signature Signature
    55  	lines := strings.SplitN(in, "\n", 4)
    56  	if len(lines) < 4 {
    57  		return signature, errors.New("Incomplete encoded signature")
    58  	}
    59  	signature.UntrustedComment = trimCarriageReturn(lines[0])
    60  	bin1, err := base64.StdEncoding.DecodeString(lines[1])
    61  	if err != nil || len(bin1) != 74 {
    62  		return signature, errors.New("Invalid encoded signature")
    63  	}
    64  	signature.TrustedComment = trimCarriageReturn(lines[2])
    65  	bin2, err := base64.StdEncoding.DecodeString(lines[3])
    66  	if err != nil || len(bin2) != 64 {
    67  		return signature, errors.New("Invalid encoded signature")
    68  	}
    69  	copy(signature.SignatureAlgorithm[:], bin1[0:2])
    70  	copy(signature.KeyId[:], bin1[2:10])
    71  	copy(signature.Signature[:], bin1[10:74])
    72  	copy(signature.GlobalSignature[:], bin2)
    73  	return signature, nil
    74  }
    75  
    76  func NewPublicKeyFromFile(file string) (PublicKey, error) {
    77  	var publicKey PublicKey
    78  	bin, err := ioutil.ReadFile(file)
    79  	if err != nil {
    80  		return publicKey, err
    81  	}
    82  	return DecodePublicKey(string(bin))
    83  }
    84  
    85  func NewSignatureFromFile(file string) (Signature, error) {
    86  	var signature Signature
    87  	bin, err := ioutil.ReadFile(file)
    88  	if err != nil {
    89  		return signature, err
    90  	}
    91  	return DecodeSignature(string(bin))
    92  }
    93  
    94  func (publicKey *PublicKey) Verify(bin []byte, signature Signature) (bool, error) {
    95  	if publicKey.SignatureAlgorithm != [2]byte{'E', 'd'} {
    96  		return false, errors.New("Incompatible signature algorithm")
    97  	}
    98  	prehashed := false
    99  	if signature.SignatureAlgorithm[0] == 0x45 && signature.SignatureAlgorithm[1] == 0x64 {
   100  		prehashed = false
   101  	} else if signature.SignatureAlgorithm[0] == 0x45 && signature.SignatureAlgorithm[1] == 0x44 {
   102  		prehashed = true
   103  	} else {
   104  		return false, errors.New("Unsupported signature algorithm")
   105  	}
   106  	if publicKey.KeyId != signature.KeyId {
   107  		return false, errors.New("Incompatible key identifiers")
   108  	}
   109  	if !strings.HasPrefix(signature.TrustedComment, "trusted comment: ") {
   110  		return false, errors.New("Unexpected format for the trusted comment")
   111  	}
   112  
   113  	if prehashed {
   114  		h, _ := blake2b.New512(nil)
   115  		h.Write(bin)
   116  		bin = h.Sum(nil)
   117  	}
   118  	if !ed25519.Verify(ed25519.PublicKey(publicKey.PublicKey[:]), bin, signature.Signature[:]) {
   119  		return false, errors.New("Invalid signature")
   120  	}
   121  	if !ed25519.Verify(ed25519.PublicKey(publicKey.PublicKey[:]), append(signature.Signature[:], []byte(signature.TrustedComment)[17:]...), signature.GlobalSignature[:]) {
   122  		return false, errors.New("Invalid global signature")
   123  	}
   124  	return true, nil
   125  }
   126  
   127  func (publicKey *PublicKey) VerifyFromFile(file string, signature Signature) (bool, error) {
   128  	bin, err := ioutil.ReadFile(file)
   129  	if err != nil {
   130  		return false, err
   131  	}
   132  	return publicKey.Verify(bin, signature)
   133  }
   134  

View as plain text