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 }