github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/kbfscrypto/signature.go (about)

     1  // Copyright 2016 Keybase Inc. All rights reserved.
     2  // Use of this source code is governed by a BSD
     3  // license that can be found in the LICENSE file.
     4  
     5  package kbfscrypto
     6  
     7  import (
     8  	"bytes"
     9  	"encoding"
    10  	"encoding/hex"
    11  	"encoding/json"
    12  	"fmt"
    13  
    14  	"github.com/keybase/client/go/kbcrypto"
    15  	"github.com/keybase/client/go/libkb"
    16  	"github.com/keybase/client/go/protocol/keybase1"
    17  	"github.com/pkg/errors"
    18  
    19  	"golang.org/x/net/context"
    20  )
    21  
    22  // SigVer denotes a signature version.
    23  type SigVer int
    24  
    25  const (
    26  	// SigED25519 is the signature type for ED25519
    27  	SigED25519 = SigVer(iota + 1)
    28  	// SigED25519ForKBFS is the signature type for ED25519 with a KBFS prefix.
    29  	SigED25519ForKBFS
    30  )
    31  
    32  // IsNil returns true if this SigVer is nil.
    33  func (v SigVer) IsNil() bool {
    34  	return int(v) == 0
    35  }
    36  
    37  // SignatureInfo contains all the info needed to verify a signature
    38  // for a message.
    39  type SignatureInfo struct {
    40  	// Exported only for serialization purposes.
    41  	Version      SigVer       `codec:"v"`
    42  	Signature    []byte       `codec:"s"`
    43  	VerifyingKey VerifyingKey `codec:"k"`
    44  }
    45  
    46  // IsNil returns true if this SignatureInfo is nil.
    47  func (s SignatureInfo) IsNil() bool {
    48  	return s.Version.IsNil() && len(s.Signature) == 0 && s.VerifyingKey.IsNil()
    49  }
    50  
    51  // Equals returns true if this SignatureInfo matches the given one.
    52  func (s SignatureInfo) Equals(other SignatureInfo) bool {
    53  	if s.Version != other.Version {
    54  		return false
    55  	}
    56  	if !bytes.Equal(s.Signature, other.Signature) {
    57  		return false
    58  	}
    59  	if s.VerifyingKey != other.VerifyingKey {
    60  		return false
    61  	}
    62  
    63  	return true
    64  }
    65  
    66  // DeepCopy makes a complete copy of this SignatureInfo.
    67  func (s SignatureInfo) DeepCopy() SignatureInfo {
    68  	signature := make([]byte, len(s.Signature))
    69  	copy(signature, s.Signature)
    70  	return SignatureInfo{s.Version, signature, s.VerifyingKey}
    71  }
    72  
    73  // String implements the fmt.Stringer interface for SignatureInfo.
    74  func (s SignatureInfo) String() string {
    75  	return fmt.Sprintf("SignatureInfo{Version: %d, Signature: %s, "+
    76  		"VerifyingKey: %s}", s.Version, hex.EncodeToString(s.Signature),
    77  		&s.VerifyingKey)
    78  }
    79  
    80  // SigningKey is a key pair for signing.
    81  type SigningKey struct {
    82  	kp libkb.NaclSigningKeyPair
    83  }
    84  
    85  // NewSigningKey returns a SigningKey using the given key pair.
    86  func NewSigningKey(kp libkb.NaclSigningKeyPair) SigningKey {
    87  	return SigningKey{kp}
    88  }
    89  
    90  // Sign signs the given data and returns a SignatureInfo.
    91  func (k SigningKey) Sign(data []byte) SignatureInfo {
    92  	sig := k.kp.Private.Sign(data)
    93  	return SignatureInfo{
    94  		Version:      SigED25519,
    95  		Signature:    sig[:],
    96  		VerifyingKey: k.GetVerifyingKey(),
    97  	}
    98  }
    99  
   100  // SignForKBFS signs the given data with the KBFS prefix and returns a SignatureInfo.
   101  func (k SigningKey) SignForKBFS(data []byte) (SignatureInfo, error) {
   102  	sigInfo, err := k.kp.SignV2(data, kbcrypto.SignaturePrefixKBFS)
   103  	if err != nil {
   104  		return SignatureInfo{}, errors.WithStack(err)
   105  	}
   106  	return SignatureInfo{
   107  		Version:      SigVer(sigInfo.Version),
   108  		Signature:    sigInfo.Sig[:],
   109  		VerifyingKey: k.GetVerifyingKey(),
   110  	}, nil
   111  }
   112  
   113  // SignToString signs the given data and returns a string.
   114  func (k SigningKey) SignToString(data []byte) (sig string, err error) {
   115  	sig, _, err = k.kp.SignToString(data)
   116  	if err != nil {
   117  		return "", errors.WithStack(err)
   118  	}
   119  	return sig, nil
   120  }
   121  
   122  // GetVerifyingKey returns the public key half of this signing key.
   123  func (k SigningKey) GetVerifyingKey() VerifyingKey {
   124  	return MakeVerifyingKey(k.kp.Public.GetKID())
   125  }
   126  
   127  // A VerifyingKey is a public key that can be used to verify a
   128  // signature created by the corresponding private signing key. In
   129  // particular, VerifyingKeys are used to authenticate home and public
   130  // TLFs. (See 4.2, 4.3.)
   131  //
   132  // These are also sometimes known as sibkeys.
   133  //
   134  // Copies of VerifyingKey objects are deep copies.
   135  type VerifyingKey struct {
   136  	// Even though we currently use NaclSignatures, we use a KID
   137  	// here (which encodes the key type) as we may end up storing
   138  	// other kinds of signatures.
   139  	kidContainer
   140  }
   141  
   142  var _ encoding.BinaryMarshaler = VerifyingKey{}
   143  var _ encoding.BinaryUnmarshaler = (*VerifyingKey)(nil)
   144  
   145  var _ json.Marshaler = VerifyingKey{}
   146  var _ json.Unmarshaler = (*VerifyingKey)(nil)
   147  
   148  // MakeVerifyingKey returns a VerifyingKey containing the given KID.
   149  func MakeVerifyingKey(kid keybase1.KID) VerifyingKey {
   150  	return VerifyingKey{kidContainer{kid}}
   151  }
   152  
   153  // IsNil returns true if the VerifyingKey is nil.
   154  func (k VerifyingKey) IsNil() bool {
   155  	return k.kid.IsNil()
   156  }
   157  
   158  // Verify verifies the given message against the given SignatureInfo,
   159  // and returns nil if it verifies successfully, or an error otherwise.
   160  func Verify(msg []byte, sigInfo SignatureInfo) error {
   161  	if sigInfo.Version < SigED25519 || sigInfo.Version > SigED25519ForKBFS {
   162  		return errors.WithStack(UnknownSigVer{sigInfo.Version})
   163  	}
   164  
   165  	publicKey := kbcrypto.KIDToNaclSigningKeyPublic(
   166  		sigInfo.VerifyingKey.KID().ToBytes())
   167  	if publicKey == nil {
   168  		return errors.WithStack(libkb.KeyCannotVerifyError{})
   169  	}
   170  
   171  	var naclSignature kbcrypto.NaclSignature
   172  	if len(sigInfo.Signature) != len(naclSignature) {
   173  		return errors.WithStack(kbcrypto.VerificationError{})
   174  	}
   175  	copy(naclSignature[:], sigInfo.Signature)
   176  
   177  	if sigInfo.Version == SigED25519ForKBFS {
   178  		msg = kbcrypto.SignaturePrefixKBFS.Prefix(msg)
   179  	}
   180  
   181  	if !publicKey.Verify(msg, naclSignature) {
   182  		return errors.WithStack(kbcrypto.VerificationError{})
   183  	}
   184  
   185  	return nil
   186  }
   187  
   188  // A Signer is something that can sign using an internal private key.
   189  type Signer interface {
   190  	// Sign signs msg with some internal private key.
   191  	Sign(ctx context.Context, msg []byte) (sigInfo SignatureInfo, err error)
   192  	// SignForKBFS signs msg with some internal private key on behalf of KBFS.
   193  	SignForKBFS(ctx context.Context, msg []byte) (sigInfo SignatureInfo, err error)
   194  	// SignToString signs msg with some internal private key and
   195  	// outputs the full serialized NaclSigInfo.
   196  	SignToString(ctx context.Context, msg []byte) (signature string, err error)
   197  }
   198  
   199  // SigningKeySigner is a Signer wrapper around a SigningKey.
   200  type SigningKeySigner struct {
   201  	Key SigningKey
   202  }
   203  
   204  // Sign implements Signer for SigningKeySigner.
   205  func (s SigningKeySigner) Sign(
   206  	ctx context.Context, data []byte) (SignatureInfo, error) {
   207  	return s.Key.Sign(data), nil
   208  }
   209  
   210  // SignForKBFS implements Signer for SigningKeySigner.
   211  func (s SigningKeySigner) SignForKBFS(
   212  	ctx context.Context, data []byte) (SignatureInfo, error) {
   213  	return s.Key.SignForKBFS(data)
   214  }
   215  
   216  // SignToString implements Signer for SigningKeySigner.
   217  func (s SigningKeySigner) SignToString(
   218  	ctx context.Context, data []byte) (sig string, err error) {
   219  	return s.Key.SignToString(data)
   220  }