github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/saltpack_sign.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 import ( 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 17 type streamfn func(io.Writer, saltpack.SigningSecretKey, string) (io.WriteCloser, error) 18 19 func 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 33 func 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 47 func 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 69 type saltSigner struct { 70 NaclSigningKeyPair 71 } 72 73 func (s saltSigner) GetPublicKey() saltpack.SigningPublicKey { 74 return saltSignerPublic{key: s.Public} 75 } 76 77 func (s saltSigner) Sign(msg []byte) ([]byte, error) { 78 sig := s.Private.Sign(msg) 79 return sig[:], nil 80 } 81 82 type saltSignerPublic struct { 83 key kbcrypto.NaclSigningKeyPublic 84 } 85 86 func (s saltSignerPublic) ToKID() []byte { 87 return s.key[:] 88 } 89 90 func (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 104 func 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 }