| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 | 
							- // Copyright (C) 2015 The Syncthing Authors.
 
- //
 
- // This Source Code Form is subject to the terms of the Mozilla Public
 
- // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 
- // You can obtain one at https://mozilla.org/MPL/2.0/.
 
- // Package signature provides simple methods to create and verify signatures
 
- // in PEM format.
 
- package signature
 
- import (
 
- 	"crypto/ecdsa"
 
- 	"crypto/elliptic"
 
- 	"crypto/sha256"
 
- 	"crypto/x509"
 
- 	"encoding/asn1"
 
- 	"encoding/pem"
 
- 	"errors"
 
- 	"fmt"
 
- 	"io"
 
- 	"math/big"
 
- 	"github.com/syncthing/syncthing/lib/rand"
 
- )
 
- // GenerateKeys returns a new key pair, with the private and public key
 
- // encoded in PEM format.
 
- func GenerateKeys() (privKey []byte, pubKey []byte, err error) {
 
- 	// Generate a new key pair
 
- 	key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
 
- 	if err != nil {
 
- 		return nil, nil, err
 
- 	}
 
- 	// Marshal the private key
 
- 	bs, err := x509.MarshalECPrivateKey(key)
 
- 	if err != nil {
 
- 		return nil, nil, err
 
- 	}
 
- 	// Encode it in PEM format
 
- 	privKey = pem.EncodeToMemory(&pem.Block{
 
- 		Type:  "EC PRIVATE KEY",
 
- 		Bytes: bs,
 
- 	})
 
- 	// Marshal the public key
 
- 	bs, err = x509.MarshalPKIXPublicKey(&key.PublicKey)
 
- 	if err != nil {
 
- 		return nil, nil, err
 
- 	}
 
- 	// Encode it in PEM format
 
- 	pubKey = pem.EncodeToMemory(&pem.Block{
 
- 		Type:  "EC PUBLIC KEY",
 
- 		Bytes: bs,
 
- 	})
 
- 	return
 
- }
 
- // Sign computes the hash of data and signs it with the private key, returning
 
- // a signature in PEM format.
 
- func Sign(privKeyPEM []byte, data io.Reader) ([]byte, error) {
 
- 	// Parse the private key
 
- 	key, err := loadPrivateKey(privKeyPEM)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	// Hash the reader data
 
- 	hash, err := hashReader(data)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	// Sign the hash
 
- 	r, s, err := ecdsa.Sign(rand.Reader, key, hash)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	// Marshal the signature using ASN.1
 
- 	sig, err := marshalSignature(r, s)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	// Encode it in a PEM block
 
- 	bs := pem.EncodeToMemory(&pem.Block{
 
- 		Type:  "SIGNATURE",
 
- 		Bytes: sig,
 
- 	})
 
- 	return bs, nil
 
- }
 
- // Verify computes the hash of data and compares it to the signature using the
 
- // given public key. Returns nil if the signature is correct.
 
- func Verify(pubKeyPEM []byte, signature []byte, data io.Reader) error {
 
- 	// Parse the public key
 
- 	key, err := loadPublicKey(pubKeyPEM)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	// Parse the signature
 
- 	block, _ := pem.Decode(signature)
 
- 	if block == nil || block.Bytes == nil {
 
- 		return errors.New("unsupported signature format")
 
- 	}
 
- 	r, s, err := unmarshalSignature(block.Bytes)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	// Compute the hash of the data
 
- 	hash, err := hashReader(data)
 
- 	if err != nil {
 
- 		return err
 
- 	}
 
- 	// Verify the signature
 
- 	if !ecdsa.Verify(key, hash, r, s) {
 
- 		return errors.New("incorrect signature")
 
- 	}
 
- 	return nil
 
- }
 
- // hashReader returns the SHA256 hash of the reader
 
- func hashReader(r io.Reader) ([]byte, error) {
 
- 	h := sha256.New()
 
- 	if _, err := io.Copy(h, r); err != nil {
 
- 		return nil, err
 
- 	}
 
- 	hash := []byte(fmt.Sprintf("%x", h.Sum(nil)))
 
- 	return hash, nil
 
- }
 
- // loadPrivateKey returns the ECDSA private key structure for the given PEM
 
- // data.
 
- func loadPrivateKey(bs []byte) (*ecdsa.PrivateKey, error) {
 
- 	block, _ := pem.Decode(bs)
 
- 	return x509.ParseECPrivateKey(block.Bytes)
 
- }
 
- // loadPublicKey returns the ECDSA public key structure for the given PEM
 
- // data.
 
- func loadPublicKey(bs []byte) (*ecdsa.PublicKey, error) {
 
- 	// Decode and parse the public key PEM block
 
- 	block, _ := pem.Decode(bs)
 
- 	if block == nil || block.Bytes == nil {
 
- 		return nil, errors.New("unsupported public key format")
 
- 	}
 
- 	intf, err := x509.ParsePKIXPublicKey(block.Bytes)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	// It should be an ECDSA public key
 
- 	pk, ok := intf.(*ecdsa.PublicKey)
 
- 	if !ok {
 
- 		return nil, errors.New("unsupported public key format")
 
- 	}
 
- 	return pk, nil
 
- }
 
- // A wrapper around the signature integers so that we can marshal and
 
- // unmarshal them.
 
- type signature struct {
 
- 	R, S *big.Int
 
- }
 
- // marhalSignature returns ASN.1 encoded bytes for the given integers,
 
- // suitable for PEM encoding.
 
- func marshalSignature(r, s *big.Int) ([]byte, error) {
 
- 	sig := signature{
 
- 		R: r,
 
- 		S: s,
 
- 	}
 
- 	bs, err := asn1.Marshal(sig)
 
- 	if err != nil {
 
- 		return nil, err
 
- 	}
 
- 	return bs, nil
 
- }
 
- // unmarshalSignature returns the R and S integers from the given ASN.1
 
- // encoded signature.
 
- func unmarshalSignature(sig []byte) (r *big.Int, s *big.Int, err error) {
 
- 	var ts signature
 
- 	_, err = asn1.Unmarshal(sig, &ts)
 
- 	if err != nil {
 
- 		return nil, nil, err
 
- 	}
 
- 	return ts.R, ts.S, nil
 
- }
 
 
  |