github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/saltpack.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  	"bytes"
     8  	"fmt"
     9  
    10  	"github.com/keybase/client/go/kbcrypto"
    11  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    12  	"github.com/keybase/saltpack"
    13  	"golang.org/x/crypto/ed25519"
    14  	"golang.org/x/crypto/nacl/box"
    15  )
    16  
    17  // Wrap types from naclwrap.go in saltpack interfaces.
    18  
    19  type naclBoxPublicKey NaclDHKeyPublic
    20  
    21  var _ saltpack.BoxPublicKey = naclBoxPublicKey{}
    22  
    23  func (b naclBoxPublicKey) ToKID() []byte {
    24  	return b[:]
    25  }
    26  
    27  func (b naclBoxPublicKey) ToRawBoxKeyPointer() *saltpack.RawBoxKey {
    28  	return (*saltpack.RawBoxKey)(&b)
    29  }
    30  
    31  func (b naclBoxPublicKey) CreateEphemeralKey() (saltpack.BoxSecretKey, error) {
    32  	kp, err := GenerateNaclDHKeyPair()
    33  	if err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	return naclBoxSecretKey(kp), nil
    38  }
    39  
    40  func (b naclBoxPublicKey) HideIdentity() bool {
    41  	return false
    42  }
    43  
    44  type hiddenNaclBoxPublicKey NaclDHKeyPublic
    45  
    46  func (b hiddenNaclBoxPublicKey) ToKID() []byte {
    47  	return b[:]
    48  }
    49  
    50  func (b hiddenNaclBoxPublicKey) ToRawBoxKeyPointer() *saltpack.RawBoxKey {
    51  	return (*saltpack.RawBoxKey)(&b)
    52  }
    53  
    54  func (b hiddenNaclBoxPublicKey) CreateEphemeralKey() (saltpack.BoxSecretKey, error) {
    55  	kp, err := GenerateNaclDHKeyPair()
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  
    60  	return naclBoxSecretKey(kp), nil
    61  }
    62  
    63  func (b hiddenNaclBoxPublicKey) HideIdentity() bool {
    64  	return true
    65  }
    66  
    67  type naclBoxPrecomputedSharedKey [32]byte
    68  
    69  var _ saltpack.BoxPrecomputedSharedKey = naclBoxPrecomputedSharedKey{}
    70  
    71  func (k naclBoxPrecomputedSharedKey) Unbox(nonce saltpack.Nonce, msg []byte) (
    72  	[]byte, error) {
    73  	ret, ok := box.OpenAfterPrecomputation(
    74  		[]byte{}, msg, (*[24]byte)(&nonce), (*[32]byte)(&k))
    75  	if !ok {
    76  		return nil, DecryptionError{}
    77  	}
    78  	return ret, nil
    79  }
    80  
    81  func (k naclBoxPrecomputedSharedKey) Box(nonce saltpack.Nonce, msg []byte) []byte {
    82  	ret := box.SealAfterPrecomputation([]byte{}, msg, (*[24]byte)(&nonce), (*[32]byte)(&k))
    83  	return ret
    84  }
    85  
    86  type naclBoxSecretKey NaclDHKeyPair
    87  
    88  var _ saltpack.BoxSecretKey = naclBoxSecretKey{}
    89  
    90  func (n naclBoxSecretKey) Box(
    91  	receiver saltpack.BoxPublicKey, nonce saltpack.Nonce, msg []byte) []byte {
    92  	ret := box.Seal([]byte{}, msg, (*[24]byte)(&nonce),
    93  		(*[32]byte)(receiver.ToRawBoxKeyPointer()),
    94  		(*[32]byte)(n.Private))
    95  	return ret
    96  }
    97  
    98  func (n naclBoxSecretKey) Unbox(
    99  	sender saltpack.BoxPublicKey, nonce saltpack.Nonce, msg []byte) (
   100  	[]byte, error) {
   101  	ret, ok := box.Open([]byte{}, msg, (*[24]byte)(&nonce),
   102  		(*[32]byte)(sender.ToRawBoxKeyPointer()),
   103  		(*[32]byte)(n.Private))
   104  	if !ok {
   105  		return nil, DecryptionError{}
   106  	}
   107  	return ret, nil
   108  }
   109  
   110  func (n naclBoxSecretKey) GetPublicKey() saltpack.BoxPublicKey {
   111  	return naclBoxPublicKey(n.Public)
   112  }
   113  
   114  func (n naclBoxSecretKey) Precompute(
   115  	sender saltpack.BoxPublicKey) saltpack.BoxPrecomputedSharedKey {
   116  	var res naclBoxPrecomputedSharedKey
   117  	box.Precompute((*[32]byte)(&res),
   118  		(*[32]byte)(sender.ToRawBoxKeyPointer()),
   119  		(*[32]byte)(n.Private))
   120  	return res
   121  }
   122  
   123  // A secret key also functions as a keyring with a single key.
   124  type naclKeyring naclBoxSecretKey
   125  
   126  var _ saltpack.Keyring = naclKeyring{}
   127  
   128  func (n naclKeyring) LookupBoxSecretKey(
   129  	kids [][]byte) (int, saltpack.BoxSecretKey) {
   130  	sk := (naclBoxSecretKey)(n)
   131  	pkKid := sk.GetPublicKey().ToKID()
   132  	for i, kid := range kids {
   133  		if bytes.Equal(pkKid, kid) {
   134  			return i, sk
   135  		}
   136  	}
   137  
   138  	return -1, nil
   139  }
   140  
   141  func (n naclKeyring) LookupBoxPublicKey(kid []byte) saltpack.BoxPublicKey {
   142  	var pk naclBoxPublicKey
   143  	if len(kid) != len(pk) {
   144  		return nil
   145  	}
   146  	copy(pk[:], kid)
   147  	return pk
   148  }
   149  
   150  func (n naclKeyring) GetAllBoxSecretKeys() []saltpack.BoxSecretKey {
   151  	return []saltpack.BoxSecretKey{naclBoxSecretKey(n)}
   152  }
   153  
   154  func (n naclKeyring) ImportBoxEphemeralKey(kid []byte) saltpack.BoxPublicKey {
   155  	return n.LookupBoxPublicKey(kid)
   156  }
   157  
   158  func (n naclKeyring) CreateEphemeralKey() (saltpack.BoxSecretKey, error) {
   159  	kp, err := GenerateNaclDHKeyPair()
   160  	if err != nil {
   161  		return nil, err
   162  	}
   163  
   164  	return naclBoxSecretKey(kp), nil
   165  }
   166  
   167  func (n naclKeyring) LookupSigningPublicKey(kid []byte) saltpack.SigningPublicKey {
   168  	if len(kid) != ed25519.PublicKeySize {
   169  		return nil
   170  	}
   171  	keyBytes := [ed25519.PublicKeySize]byte{}
   172  	copy(keyBytes[:], kid)
   173  	return saltSignerPublic{kbcrypto.NaclSigningKeyPublic(keyBytes)}
   174  }
   175  
   176  // An empty keyring just for generating ephemeral keys.
   177  type emptyKeyring struct{}
   178  
   179  var _ saltpack.Keyring = emptyKeyring{}
   180  
   181  func (e emptyKeyring) LookupBoxSecretKey(kids [][]byte) (int, saltpack.BoxSecretKey) {
   182  	panic("unimplemented")
   183  }
   184  
   185  func (e emptyKeyring) LookupBoxPublicKey(kid []byte) saltpack.BoxPublicKey {
   186  	panic("unimplemented")
   187  }
   188  
   189  func (e emptyKeyring) GetAllBoxSecretKeys() []saltpack.BoxSecretKey {
   190  	panic("unimplemented")
   191  }
   192  
   193  func (e emptyKeyring) ImportBoxEphemeralKey(kid []byte) saltpack.BoxPublicKey {
   194  	panic("unimplemented")
   195  }
   196  
   197  func (e emptyKeyring) CreateEphemeralKey() (saltpack.BoxSecretKey, error) {
   198  	kp, err := GenerateNaclDHKeyPair()
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	return naclBoxSecretKey(kp), nil
   204  }
   205  
   206  func BoxPublicKeyToKeybaseKID(k saltpack.BoxPublicKey) (ret keybase1.KID) {
   207  	if k == nil {
   208  		return ret
   209  	}
   210  	p := k.ToKID()
   211  	return keybase1.KIDFromRawKey(p, byte(kbcrypto.KIDNaclDH))
   212  }
   213  
   214  func checkSaltpackBrand(b string) error {
   215  	// Everything is awesome!
   216  	return nil
   217  }
   218  
   219  func SaltpackVersionFromArg(saltpackVersionArg int) (saltpack.Version, error) {
   220  	if saltpackVersionArg == 0 {
   221  		return CurrentSaltpackVersion(), nil
   222  	}
   223  
   224  	// The arg specifies the major version we want, and the minor version is
   225  	// assumed to be the latest available. Make a map to accomplish that.
   226  	majorVersionMap := map[int]saltpack.Version{}
   227  	for _, v := range saltpack.KnownVersions() {
   228  		latestPair, found := majorVersionMap[v.Major]
   229  		if !found || (v.Minor > latestPair.Minor) {
   230  			majorVersionMap[v.Major] = v
   231  		}
   232  	}
   233  
   234  	ret, found := majorVersionMap[saltpackVersionArg]
   235  	if !found {
   236  		return saltpack.Version{}, fmt.Errorf("failed to find saltpack major version %d", saltpackVersionArg)
   237  	}
   238  	return ret, nil
   239  }