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  }