1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4package libkb 5 6import ( 7 "bytes" 8 "crypto/sha256" 9 "hash" 10 "io" 11 12 keybase1 "github.com/keybase/client/go/protocol/keybase1" 13 "github.com/keybase/go-crypto/openpgp" 14 "github.com/keybase/go-crypto/openpgp/armor" 15 "github.com/keybase/go-crypto/openpgp/packet" 16) 17 18// SimpleSign signs the given data stream, outputs an armored string which is 19// the attached signature of the input data 20func SimpleSign(payload []byte, key PGPKeyBundle) (out string, id keybase1.SigIDBase, err error) { 21 var outb bytes.Buffer 22 var in io.WriteCloser 23 var h HashSummer 24 if !key.HasSecretKey() { 25 err = NoSecretKeyError{} 26 return 27 } 28 if in, h, err = ArmoredAttachedSign(NopWriteCloser{&outb}, *key.Entity, nil, nil); err != nil { 29 return 30 } 31 if _, err = in.Write(payload); err != nil { 32 return 33 } 34 if err = in.Close(); err != nil { 35 return 36 } 37 out = outb.String() 38 if id, err = keybase1.SigIDBaseFromSlice(h()); err != nil { 39 return 40 } 41 return 42} 43 44type HashingWriteCloser struct { 45 targ io.WriteCloser 46 hasher hash.Hash 47} 48 49func (h HashingWriteCloser) Write(buf []byte) (int, error) { 50 n, err := h.targ.Write(buf) 51 if err == nil { 52 _, err = h.hasher.Write(buf) 53 } 54 return n, err 55} 56 57func (h HashingWriteCloser) Close() error { 58 err := h.targ.Close() 59 return err 60} 61 62type HashSummer func() []byte 63 64func ArmoredAttachedSign(out io.WriteCloser, signed openpgp.Entity, hints *openpgp.FileHints, config *packet.Config) (in io.WriteCloser, h HashSummer, err error) { 65 66 var aout io.WriteCloser 67 68 aout, err = armor.Encode(out, "PGP MESSAGE", PGPArmorHeaders) 69 if err != nil { 70 return 71 } 72 73 hwc := HashingWriteCloser{aout, sha256.New()} 74 in, err = openpgp.AttachedSign(hwc, signed, hints, config) 75 h = func() []byte { return hwc.hasher.Sum(nil) } 76 77 return in, h, err 78} 79 80func AttachedSignWrapper(out io.WriteCloser, key PGPKeyBundle, armored bool) ( 81 in io.WriteCloser, err error) { 82 83 if armored { 84 in, _, err = ArmoredAttachedSign(out, *key.Entity, nil, nil) 85 } else { 86 in, err = openpgp.AttachedSign(out, *key.Entity, nil, nil) 87 } 88 return 89} 90 91// NopWriteCloser is like an ioutil.NopCloser, but for an io.Writer. 92// TODO: we have two of these in OpenPGP packages alone. This probably needs 93// to be promoted somewhere more common. 94// 95// From here: 96// https://code.google.com/p/go/source/browse/openpgp/write.go?repo=crypto&r=1e7a3e301825bf9cb32e0535f3761d62d2d369d1#364 97// 98type NopWriteCloser struct { 99 W io.Writer 100} 101 102func (c NopWriteCloser) Write(data []byte) (n int, err error) { 103 return c.W.Write(data) 104} 105 106func (c NopWriteCloser) Close() error { 107 return nil 108} 109