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 "fmt" 8 "io" 9 10 "github.com/keybase/go-crypto/ed25519" 11 12 "github.com/keybase/client/go/kbcrypto" 13 keybase1 "github.com/keybase/client/go/protocol/keybase1" 14 "github.com/keybase/saltpack" 15) 16 17type streamfn func(io.Writer, saltpack.SigningSecretKey, string) (io.WriteCloser, error) 18 19func SaltpackSign(g *GlobalContext, source io.ReadCloser, sink io.WriteCloser, key NaclSigningKeyPair, binary bool, saltpackVersion saltpack.Version) error { 20 var s streamfn 21 if binary { 22 s = func(w io.Writer, k saltpack.SigningSecretKey, _ string) (io.WriteCloser, error) { 23 return saltpack.NewSignStream(saltpackVersion, w, k) 24 } 25 } else { 26 s = func(w io.Writer, k saltpack.SigningSecretKey, brand string) (io.WriteCloser, error) { 27 return saltpack.NewSignArmor62Stream(saltpackVersion, w, k, brand) 28 } 29 } 30 return saltpackSign(g, source, sink, key, s) 31} 32 33func SaltpackSignDetached(g *GlobalContext, source io.ReadCloser, sink io.WriteCloser, key NaclSigningKeyPair, binary bool, saltpackVersion saltpack.Version) error { 34 var s streamfn 35 if binary { 36 s = func(w io.Writer, k saltpack.SigningSecretKey, _ string) (io.WriteCloser, error) { 37 return saltpack.NewSignDetachedStream(saltpackVersion, w, k) 38 } 39 } else { 40 s = func(w io.Writer, k saltpack.SigningSecretKey, brand string) (io.WriteCloser, error) { 41 return saltpack.NewSignDetachedArmor62Stream(saltpackVersion, w, k, brand) 42 } 43 } 44 return saltpackSign(g, source, sink, key, s) 45} 46 47func saltpackSign(g *GlobalContext, source io.ReadCloser, sink io.WriteCloser, key NaclSigningKeyPair, streamer streamfn) error { 48 defer func() { 49 if err := source.Close(); err != nil { 50 g.Log.Warning("error closing source: %s", err) 51 } 52 if err := sink.Close(); err != nil { 53 g.Log.Warning("error closing sink: %s", err) 54 } 55 }() 56 57 stream, err := streamer(sink, saltSigner{key}, KeybaseSaltpackBrand) 58 if err != nil { 59 return err 60 } 61 62 if _, err := io.Copy(stream, source); err != nil { 63 return err 64 } 65 66 return stream.Close() 67} 68 69type saltSigner struct { 70 NaclSigningKeyPair 71} 72 73func (s saltSigner) GetPublicKey() saltpack.SigningPublicKey { 74 return saltSignerPublic{key: s.Public} 75} 76 77func (s saltSigner) Sign(msg []byte) ([]byte, error) { 78 sig := s.Private.Sign(msg) 79 return sig[:], nil 80} 81 82type saltSignerPublic struct { 83 key kbcrypto.NaclSigningKeyPublic 84} 85 86func (s saltSignerPublic) ToKID() []byte { 87 return s.key[:] 88} 89 90func (s saltSignerPublic) Verify(msg, sig []byte) error { 91 if len(sig) != ed25519.SignatureSize { 92 return fmt.Errorf("signature size: %d, expected %d", len(sig), ed25519.SignatureSize) 93 } 94 95 var fixed kbcrypto.NaclSignature 96 copy(fixed[:], sig) 97 if !s.key.Verify(msg, fixed) { 98 return BadSigError{E: "bad signature"} 99 } 100 101 return nil 102} 103 104func SigningPublicKeyToKeybaseKID(k saltpack.SigningPublicKey) (ret keybase1.KID) { 105 if k == nil { 106 return ret 107 } 108 p := k.ToKID() 109 return keybase1.KIDFromRawKey(p, byte(kbcrypto.KIDNaclEddsa)) 110} 111