github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/lksec.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  	"crypto/hmac"
     8  	"crypto/rand"
     9  	"crypto/sha256"
    10  	"encoding/hex"
    11  	"errors"
    12  	"fmt"
    13  	"strings"
    14  
    15  	keybase1 "github.com/keybase/client/go/protocol/keybase1"
    16  	"golang.org/x/crypto/nacl/secretbox"
    17  )
    18  
    19  const LKSecVersion = 100
    20  const LKSecLen = 32
    21  
    22  type LKSecClientHalf struct {
    23  	c *[LKSecLen]byte
    24  }
    25  
    26  func (c LKSecClientHalf) IsNil() bool {
    27  	return c.c == nil
    28  }
    29  
    30  func (c LKSecClientHalf) Bytes() []byte {
    31  	if c.c == nil {
    32  		return nil
    33  	}
    34  	return c.c[:]
    35  }
    36  
    37  type LKSecServerHalf struct {
    38  	s *[LKSecLen]byte
    39  }
    40  
    41  func (s LKSecServerHalf) IsNil() bool {
    42  	return s.s == nil
    43  }
    44  
    45  func (s LKSecServerHalf) Bytes() []byte {
    46  	if s.s == nil {
    47  		return nil
    48  	}
    49  	return s.s[:]
    50  }
    51  
    52  type LKSecFullSecret struct {
    53  	f *[LKSecLen]byte
    54  }
    55  
    56  type LKSecMask struct {
    57  	m *[LKSecLen]byte
    58  }
    59  
    60  func (f LKSecFullSecret) IsNil() bool {
    61  	return f.f == nil
    62  }
    63  
    64  func (f LKSecFullSecret) Bytes() []byte {
    65  	if f.f == nil {
    66  		return nil
    67  	}
    68  	return f.f[:]
    69  }
    70  
    71  func NewLKSecServerHalfFromHex(s string) (ret LKSecServerHalf, err error) {
    72  	var b []byte
    73  	b, err = hex.DecodeString(s)
    74  	if err != nil {
    75  		return ret, err
    76  	}
    77  	if len(b) != LKSecLen {
    78  		err = fmt.Errorf("Wrong LKSec server length: %d != %d", len(b), LKSecLen)
    79  		return ret, err
    80  	}
    81  	var v [LKSecLen]byte
    82  	copy(v[:], b)
    83  	ret = LKSecServerHalf{s: &v}
    84  	return ret, nil
    85  }
    86  
    87  func newLKSecFullSecretFromBytes(b []byte) (ret LKSecFullSecret, err error) {
    88  	if len(b) != LKSecLen {
    89  		err = fmt.Errorf("Wrong LKSecFullSecret len: %d != %d", len(b), LKSecLen)
    90  		return ret, err
    91  	}
    92  	var v [LKSecLen]byte
    93  	copy(v[:], b)
    94  	ret = LKSecFullSecret{f: &v}
    95  	return ret, nil
    96  }
    97  
    98  func NewLKSecClientHalfFromBytes(b []byte) (ret LKSecClientHalf, err error) {
    99  	if len(b) != LKSecLen {
   100  		err = fmt.Errorf("Wrong LKSecClientHalf len: %d != %d", len(b), LKSecLen)
   101  		return ret, err
   102  	}
   103  	var v [LKSecLen]byte
   104  	copy(v[:], b)
   105  	ret = LKSecClientHalf{c: &v}
   106  	return ret, nil
   107  }
   108  
   109  func (f LKSecFullSecret) Equal(f2 LKSecFullSecret) bool {
   110  	if f.IsNil() {
   111  		return false
   112  	}
   113  	if f2.IsNil() {
   114  		return false
   115  	}
   116  	return hmac.Equal(f.f[:], f2.f[:])
   117  }
   118  
   119  func (c LKSecClientHalf) Equal(c2 LKSecClientHalf) bool {
   120  	if c.IsNil() {
   121  		return false
   122  	}
   123  	if c2.IsNil() {
   124  		return false
   125  	}
   126  	return hmac.Equal(c.c[:], c2.c[:])
   127  }
   128  
   129  func (s LKSecServerHalf) EncodeToHex() string {
   130  	if s.IsNil() {
   131  		return ""
   132  	}
   133  	return hex.EncodeToString(s.s[:])
   134  }
   135  
   136  func (m LKSecMask) IsNil() bool {
   137  	return m.m == nil
   138  }
   139  
   140  func (m LKSecMask) EncodeToHex() string {
   141  	if m.IsNil() {
   142  		return ""
   143  	}
   144  	return hex.EncodeToString(m.m[:])
   145  }
   146  
   147  func NewLKSecServerHalfZeros() LKSecServerHalf {
   148  	var z [LKSecLen]byte
   149  	return LKSecServerHalf{s: &z}
   150  }
   151  
   152  type LKSec struct {
   153  	serverHalf LKSecServerHalf
   154  	clientHalf LKSecClientHalf
   155  	secret     LKSecFullSecret
   156  	ppGen      PassphraseGeneration
   157  	uid        keybase1.UID
   158  	deviceID   keybase1.DeviceID
   159  }
   160  
   161  func xorBytes(x *[LKSecLen]byte, y *[LKSecLen]byte) *[LKSecLen]byte {
   162  	var ret [LKSecLen]byte
   163  	for i := 0; i < LKSecLen; i++ {
   164  		ret[i] = x[i] ^ y[i]
   165  	}
   166  	return &ret
   167  }
   168  
   169  func (s LKSecServerHalf) ComputeFullSecret(c LKSecClientHalf) LKSecFullSecret {
   170  	return LKSecFullSecret{f: xorBytes(s.s, c.c)}
   171  }
   172  
   173  func (s LKSecServerHalf) ComputeClientHalf(f LKSecFullSecret) LKSecClientHalf {
   174  	return LKSecClientHalf{c: xorBytes(s.s, f.f)}
   175  }
   176  
   177  func (f LKSecFullSecret) bug3964Remask(s LKSecServerHalf) LKSecFullSecret {
   178  	return LKSecFullSecret{f: xorBytes(s.s, f.f)}
   179  }
   180  
   181  func (c LKSecClientHalf) ComputeMask(c2 LKSecClientHalf) LKSecMask {
   182  	if c.IsNil() || c2.IsNil() {
   183  		return LKSecMask{}
   184  	}
   185  	return LKSecMask{m: xorBytes(c.c, c2.c)}
   186  }
   187  
   188  func NewLKSec(pps *PassphraseStream, uid keybase1.UID) *LKSec {
   189  	return NewLKSecWithDeviceID(pps, uid, keybase1.DeviceID(""))
   190  }
   191  
   192  func NewLKSecWithDeviceID(pps *PassphraseStream, uid keybase1.UID, deviceID keybase1.DeviceID) *LKSec {
   193  	res := &LKSec{
   194  		uid:      uid,
   195  		deviceID: deviceID,
   196  	}
   197  
   198  	if pps != nil {
   199  		res.clientHalf = pps.LksClientHalf()
   200  		res.ppGen = pps.Generation()
   201  	}
   202  	return res
   203  }
   204  
   205  func NewLKSecWithClientHalf(clientHalf LKSecClientHalf, ppgen PassphraseGeneration, uid keybase1.UID) *LKSec {
   206  	return &LKSec{
   207  		clientHalf: clientHalf,
   208  		ppGen:      ppgen,
   209  		uid:        uid,
   210  	}
   211  }
   212  
   213  func NewLKSecWithFullSecret(secret LKSecFullSecret, uid keybase1.UID) *LKSec {
   214  	return &LKSec{
   215  		secret: secret,
   216  		ppGen:  PassphraseGeneration(-1),
   217  		uid:    uid,
   218  	}
   219  }
   220  
   221  func (s *LKSec) CorruptedFullSecretForBug3964Testing(srv LKSecServerHalf) LKSecFullSecret {
   222  	return s.FullSecret().bug3964Remask(srv)
   223  }
   224  
   225  func (s *LKSec) SetUID(u keybase1.UID) {
   226  	s.uid = u
   227  }
   228  
   229  func (s *LKSec) SetClientHalf(b LKSecClientHalf) {
   230  	s.clientHalf = b
   231  }
   232  
   233  func (s *LKSec) SetServerHalf(b LKSecServerHalf) {
   234  	s.serverHalf = b
   235  }
   236  
   237  // Generation returns the passphrase generation that this local key security
   238  // object is derived from.
   239  func (s LKSec) Generation() PassphraseGeneration {
   240  	return s.ppGen
   241  }
   242  
   243  func (s *LKSec) GenerateServerHalf() error {
   244  	if s.clientHalf.IsNil() {
   245  		return errors.New("Can't generate server half without a client half")
   246  	}
   247  	if !s.serverHalf.IsNil() {
   248  		return nil
   249  	}
   250  	var v [LKSecLen]byte
   251  	var n int
   252  	var err error
   253  	if n, err = rand.Read(v[:]); err != nil {
   254  		return err
   255  	}
   256  	if n != LKSecLen {
   257  		return fmt.Errorf("short random read; wanted %d bytes but only got %d", LKSecLen, n)
   258  	}
   259  	s.serverHalf = LKSecServerHalf{s: &v}
   260  	return nil
   261  }
   262  
   263  func (s *LKSec) GetServerHalf() LKSecServerHalf {
   264  	return s.serverHalf
   265  }
   266  
   267  func (s *LKSec) Load(m MetaContext) (err error) {
   268  	defer m.Trace("LKSec::Load()", &err)()
   269  
   270  	if !s.secret.IsNil() {
   271  		m.Debug("| Short-circuit; we already know the full secret")
   272  		return nil
   273  	}
   274  
   275  	if s.clientHalf.IsNil() {
   276  		err = fmt.Errorf("client half not set")
   277  		return err
   278  	}
   279  
   280  	if err = s.LoadServerHalf(m); err != nil {
   281  		return err
   282  	}
   283  
   284  	s.SetFullSecret(m)
   285  	return nil
   286  }
   287  
   288  func (s *LKSec) SetFullSecret(m MetaContext) {
   289  	m.Debug("| Making XOR'ed secret key for Local Key Security (LKS)")
   290  	s.secret = s.serverHalf.ComputeFullSecret(s.clientHalf)
   291  }
   292  
   293  func (s *LKSec) LoadServerHalf(m MetaContext) (err error) {
   294  	defer m.Trace("LKSec::LoadServerHalf()", &err)()
   295  
   296  	if !s.serverHalf.IsNil() {
   297  		m.Debug("| short-circuit: already have serverHalf")
   298  		return nil
   299  	}
   300  	_, err = s.LoadServerDetails(m)
   301  	return err
   302  }
   303  
   304  func (s *LKSec) LoadServerDetails(m MetaContext) (ret DeviceKeyMap, err error) {
   305  	defer m.Trace("LKSec#LoadServerDetails", &err)()
   306  
   307  	devid := s.deviceID
   308  	if devid.IsNil() {
   309  		devid = m.G().Env.GetDeviceIDForUID(s.uid)
   310  	}
   311  	if devid.IsNil() {
   312  		return ret, fmt.Errorf("lksec load: no device id set, thus can't fetch server half")
   313  	}
   314  
   315  	if ret, err = s.apiServerHalf(m, devid); err != nil {
   316  		m.Debug("apiServerHalf(%s) error: %s", devid, err)
   317  		return ret, err
   318  	}
   319  	if s.serverHalf.IsNil() {
   320  		return ret, fmt.Errorf("after apiServerHalf(%s), serverHalf still empty", devid)
   321  	}
   322  
   323  	return ret, nil
   324  }
   325  
   326  func (s *LKSec) GetSecret(m MetaContext) (secret LKSecFullSecret, err error) {
   327  	defer m.Trace("LKsec:GetSecret()", &err)()
   328  	if err = s.Load(m); err != nil {
   329  		return secret, err
   330  	}
   331  	secret = s.secret
   332  	return secret, nil
   333  }
   334  
   335  func (s *LKSec) Encrypt(m MetaContext, src []byte) (res []byte, err error) {
   336  	defer m.Trace("LKsec:Encrypt()", &err)()
   337  	if err = s.Load(m); err != nil {
   338  		return nil, err
   339  	}
   340  	var nonce []byte
   341  	nonce, err = RandBytes(24)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  	var fnonce [24]byte
   346  	copy(fnonce[:], nonce)
   347  	box := secretbox.Seal(nil, src, &fnonce, s.secret.f)
   348  
   349  	ret := nonce
   350  	ret = append(ret, box...)
   351  	return ret, nil
   352  }
   353  
   354  func (s *LKSec) attemptBug3964Recovery(m MetaContext, data []byte, nonce *[24]byte) (res []byte, gen PassphraseGeneration, erroneousMask LKSecServerHalf, err error) {
   355  	ss, err := s.loadSecretSyncer(m)
   356  	if err != nil {
   357  		return nil, 0, LKSecServerHalf{}, err
   358  	}
   359  	devices := ss.AllDevices()
   360  	res, serverHalf, err := s.tryAllDevicesForBug3964Recovery(m, devices, data, nonce)
   361  	return res, s.ppGen, serverHalf, err
   362  }
   363  
   364  func (s *LKSec) tryAllDevicesForBug3964Recovery(m MetaContext, devices DeviceKeyMap, data []byte, nonce *[24]byte) (res []byte, erroneousMask LKSecServerHalf, err error) {
   365  
   366  	// This logline is asserted in testing in bug_3964_repairman_test
   367  	defer m.Trace("LKSec#tryAllDevicesForBug3964Recovery()", &err)()
   368  
   369  	for devid, dev := range devices {
   370  
   371  		// This logline is asserted in testing in bug_3964_repairman_test
   372  		m.Debug("| Trying Bug 3964 Recovery w/ device %q {id: %s, lks: %s...}", dev.Description, devid, dev.LksServerHalf[0:8])
   373  
   374  		serverHalf, err := dev.ToLKSec()
   375  		if err != nil {
   376  			m.Debug("| Failed with error: %s\n", err)
   377  			continue
   378  		}
   379  		fs := s.secret.bug3964Remask(serverHalf)
   380  		res, ok := secretbox.Open(nil, data, nonce, fs.f)
   381  
   382  		if ok {
   383  			// This logline is asserted in testing in bug_3964_repairman_test
   384  			m.Debug("| Success")
   385  			return res, serverHalf, nil
   386  		}
   387  	}
   388  
   389  	err = PassphraseError{"failed to open secretbox"}
   390  	return nil, LKSecServerHalf{}, err
   391  }
   392  
   393  func splitCiphertext(src []byte) ([]byte, *[24]byte) {
   394  	var nonce [24]byte
   395  	copy(nonce[:], src[0:24])
   396  	data := src[24:]
   397  	return data, &nonce
   398  }
   399  
   400  func (s *LKSec) Decrypt(m MetaContext, src []byte) (res []byte, gen PassphraseGeneration, erroneousMask LKSecServerHalf, err error) {
   401  	// This logline is asserted in testing in bug_3964_repairman_test
   402  	defer m.Trace("LKSec#Decrypt()", &err)()
   403  
   404  	if err = s.Load(m); err != nil {
   405  		return nil, 0, LKSecServerHalf{}, err
   406  	}
   407  	var ok bool
   408  	data, nonce := splitCiphertext(src)
   409  	res, ok = secretbox.Open(nil, data, nonce, s.secret.f)
   410  	if !ok {
   411  		secretHash := sha256.New()
   412  		_, _ = secretHash.Write((*s.secret.f)[:])
   413  		m.Debug("secretbox.Open failed: used a secret of length %d", len(s.secret.f))
   414  		m.Debug("secretbox.Open failed: used secret of hash prefix %x and nonce prefix %x",
   415  			secretHash.Sum(nil)[:4], nonce[:4])
   416  		m.Debug("secretbox.Open failed: attempting recovery")
   417  		return s.attemptBug3964Recovery(m, data, nonce)
   418  	}
   419  
   420  	return res, s.ppGen, LKSecServerHalf{}, nil
   421  }
   422  
   423  func (s *LKSec) decryptForBug3964Repair(m MetaContext, src []byte, dkm DeviceKeyMap) (res []byte, erroneousMask LKSecServerHalf, err error) {
   424  	defer m.Trace("LKSec#decryptForBug3964Repair()", &err)()
   425  	data, nonce := splitCiphertext(src)
   426  	res, ok := secretbox.Open(nil, data, nonce, s.secret.f)
   427  	if ok {
   428  		m.Debug("| Succeeded with intended mask")
   429  		return res, LKSecServerHalf{}, nil
   430  	}
   431  	return s.tryAllDevicesForBug3964Recovery(m, dkm, data, nonce)
   432  }
   433  
   434  func (s *LKSec) ComputeClientHalf() (ret LKSecClientHalf, err error) {
   435  	if !s.clientHalf.IsNil() {
   436  		return s.clientHalf, nil
   437  	}
   438  	if s.serverHalf.IsNil() {
   439  		return ret, errors.New("LKSec: tried to compute client half, but no server half loaded")
   440  	}
   441  	if s.secret.IsNil() {
   442  		return ret, errors.New("LKSec: tried to compute client half, but no full secret loaded")
   443  	}
   444  	return s.serverHalf.ComputeClientHalf(s.secret), nil
   445  }
   446  
   447  func (s *LKSec) loadSecretSyncer(m MetaContext) (ss *SecretSyncer, err error) {
   448  	return m.SyncSecrets()
   449  }
   450  
   451  func (s *LKSec) apiServerHalf(m MetaContext, devid keybase1.DeviceID) (dkm DeviceKeyMap, err error) {
   452  	var dev DeviceKey
   453  	ss, err := s.loadSecretSyncer(m)
   454  	if err != nil {
   455  		return dkm, err
   456  	}
   457  	dev, err = ss.FindDevice(devid)
   458  	if err != nil {
   459  		return dkm, err
   460  	}
   461  
   462  	s.serverHalf, err = dev.ToLKSec()
   463  	if err != nil {
   464  		return dkm, err
   465  	}
   466  	s.ppGen = dev.PPGen
   467  	return ss.AllDevices(), nil
   468  }
   469  
   470  // NewLKSForEncrypt gets a verified passphrase stream, and returns
   471  // an LKS that works for encryption.
   472  func NewLKSecForEncrypt(m MetaContext, ui SecretUI, uid keybase1.UID) (ret *LKSec, err error) {
   473  	m = m.WithUIs(UIs{SecretUI: ui})
   474  	pps, err := GetPassphraseStreamStored(m)
   475  	if err != nil {
   476  		return nil, err
   477  	}
   478  	ret = NewLKSec(pps, uid)
   479  	return ret, nil
   480  }
   481  
   482  // EncryptClientHalfRecovery takes the client half of the LKS secret
   483  // and encrypts it for the given key.  This is for recovery of passphrases
   484  // on device recovery operations.
   485  func (s *LKSec) EncryptClientHalfRecovery(key GenericKey) (string, error) {
   486  	if s.clientHalf.IsNil() {
   487  		return "", errors.New("Nil LKS Client Half")
   488  	}
   489  	return key.EncryptToString(s.clientHalf.Bytes(), nil)
   490  }
   491  
   492  // ToSKB exports a generic key with the given LKSec to a SecretKeyBundle,
   493  // performing all necessary encryption.
   494  func (s *LKSec) ToSKB(m MetaContext, key GenericKey) (ret *SKB, err error) {
   495  	defer m.Trace("LKSec#ToSKB", &err)()
   496  	if s == nil {
   497  		return nil, errors.New("nil lks")
   498  	}
   499  	ret = NewSKBWithGlobalContext(m.G())
   500  
   501  	var publicKey RawPublicKey
   502  	var privateKey RawPrivateKey
   503  
   504  	publicKey, privateKey, err = key.ExportPublicAndPrivate()
   505  	if err != nil {
   506  		return nil, err
   507  	}
   508  
   509  	ret.Priv.Data, err = s.Encrypt(m, []byte(privateKey))
   510  	if err != nil {
   511  		return nil, err
   512  	}
   513  	ret.Priv.Encryption = LKSecVersion
   514  	ret.Priv.PassphraseGeneration = int(s.Generation())
   515  	ret.Pub = []byte(publicKey)
   516  	ret.Type = key.GetAlgoType()
   517  	ret.uid = s.uid
   518  	return ret, nil
   519  }
   520  
   521  func WriteLksSKBToKeyring(m MetaContext, k GenericKey, lks *LKSec) (skb *SKB, err error) {
   522  	defer m.Trace("WriteLksSKBToKeyring", &err)()
   523  	skb, err = lks.ToSKB(m, k)
   524  	if err != nil {
   525  		return nil, fmt.Errorf("k.ToLksSKB() error: %s", err)
   526  	}
   527  	if err = skbPushAndSave(m, skb); err != nil {
   528  		return nil, err
   529  	}
   530  	return skb, nil
   531  }
   532  
   533  func (s *LKSec) FullSecret() LKSecFullSecret {
   534  	if !s.secret.IsNil() {
   535  		return s.secret
   536  	}
   537  	if s.serverHalf.IsNil() || s.clientHalf.IsNil() {
   538  		return LKSecFullSecret{}
   539  	}
   540  	return s.serverHalf.ComputeFullSecret(s.clientHalf)
   541  }
   542  
   543  func (s LKSec) ServerHalf() LKSecServerHalf {
   544  	return s.serverHalf
   545  }
   546  
   547  func (s LKSec) ClientHalf() LKSecClientHalf {
   548  	return s.clientHalf
   549  }
   550  
   551  type LKSecServerHalfSet struct {
   552  	index map[[LKSecLen]byte]bool
   553  }
   554  
   555  func NewLKSecServerHalfSet() *LKSecServerHalfSet {
   556  	return &LKSecServerHalfSet{
   557  		index: make(map[[LKSecLen]byte]bool),
   558  	}
   559  }
   560  
   561  func (l *LKSecServerHalfSet) Add(s LKSecServerHalf) {
   562  	if !s.IsNil() {
   563  		l.index[*s.s] = true
   564  	}
   565  }
   566  
   567  func (l *LKSecServerHalfSet) EncodeToHexList() string {
   568  	var s []string
   569  	for k := range l.index {
   570  		s = append(s, hex.EncodeToString(k[:]))
   571  	}
   572  	return strings.Join(s, ",")
   573  }