github.com/hoffie/larasync@v0.0.0-20151025221940-0384d2bddcef/helpers/crypto/signer.go (about)

     1  package crypto
     2  
     3  import (
     4  	"crypto/sha512"
     5  	"errors"
     6  	"hash"
     7  	"io"
     8  	"os"
     9  
    10  	"github.com/agl/ed25519"
    11  )
    12  
    13  const (
    14  	// PrivateKeySize denotes how many bytes a private key needs (binary encoded)
    15  	PrivateKeySize = ed25519.PrivateKeySize
    16  	// PublicKeySize denotes how many bytes a pubkey needs (binary encoded)
    17  	PublicKeySize = ed25519.PublicKeySize
    18  	// SignatureSize denotes how many bytes a sig needs (binary encoded)
    19  	SignatureSize = ed25519.SignatureSize
    20  )
    21  
    22  // SigningWriter is Writer which secures written
    23  // data with a signature.
    24  type SigningWriter struct {
    25  	hash    hash.Hash
    26  	writer  io.Writer
    27  	privKey [PrivateKeySize]byte
    28  }
    29  
    30  // NewSigningWriter returns a new SigningWriter instance.
    31  func NewSigningWriter(key [PrivateKeySize]byte, writer io.Writer) *SigningWriter {
    32  	s := &SigningWriter{
    33  		hash:    sha512.New(),
    34  		writer:  writer,
    35  		privKey: key,
    36  	}
    37  	return s
    38  }
    39  
    40  // Write implements the Writer interface.
    41  func (w *SigningWriter) Write(data []byte) (int, error) {
    42  	written, err := w.writer.Write(data)
    43  	if err != nil {
    44  		return written, err
    45  	}
    46  	_, err = w.hash.Write(data[:written])
    47  	return written, err
    48  }
    49  
    50  // Finalize writes the signature. No more Write() calls are allowed to
    51  // happen afterwards (not enforced atm).
    52  func (w *SigningWriter) Finalize() error {
    53  	sum := w.hash.Sum(nil)
    54  	sig := ed25519.Sign(&w.privKey, sum)
    55  	if sig == nil {
    56  		return errors.New("signing failed")
    57  	}
    58  	_, err := w.writer.Write(sig[:])
    59  	return err
    60  }
    61  
    62  // VerifyingReader is a Reader which is able to Verify all data read
    63  // against the given public key. .Verify() has to be called, no
    64  // implicit verification is built in!
    65  type VerifyingReader struct {
    66  	hash          hash.Hash
    67  	reader        io.Reader
    68  	limitedReader io.Reader
    69  	pubKey        [PublicKeySize]byte
    70  	sig           [SignatureSize]byte
    71  	dataLength    int64
    72  }
    73  
    74  // NewVerifyingReader returns a new VerifyingReader.
    75  func NewVerifyingReader(pubKey [PublicKeySize]byte, reader io.ReadSeeker) (*VerifyingReader, error) {
    76  	r := &VerifyingReader{
    77  		hash:   sha512.New(),
    78  		reader: reader,
    79  		pubKey: pubKey,
    80  	}
    81  	var err error
    82  	r.dataLength, err = reader.Seek(-SignatureSize, os.SEEK_END)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  	r.limitedReader = &io.LimitedReader{
    87  		R: r.reader,
    88  		N: r.dataLength,
    89  	}
    90  	_, err = r.reader.Read(r.sig[:])
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	_, err = reader.Seek(0, os.SEEK_SET)
    95  	if err != nil {
    96  		return nil, err
    97  	}
    98  	return r, nil
    99  }
   100  
   101  // Read implements the Reader interface.
   102  func (r *VerifyingReader) Read(buf []byte) (int, error) {
   103  	read, err := r.limitedReader.Read(buf)
   104  	_, err2 := r.hash.Write(buf[:read])
   105  	if err2 != nil {
   106  		return read, err2
   107  	}
   108  	if err != nil {
   109  		return read, err
   110  	}
   111  	return read, nil
   112  }
   113  
   114  // VerifyAfterRead returns whether the data read is ok (as in: signature
   115  // matches and verifies with the given public key).
   116  //
   117  // IMPORTANT: This must only be called after *all data has been read*;
   118  // otherwise verification will always fail.
   119  func (r *VerifyingReader) VerifyAfterRead() bool {
   120  	sum := r.hash.Sum(nil)
   121  	return ed25519.Verify(&r.pubKey, sum, &r.sig)
   122  }