github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/libkbfs/crypto_local.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 libkbfs
     6  
     7  import (
     8  	"github.com/keybase/client/go/kbfs/kbfscodec"
     9  	"github.com/keybase/client/go/kbfs/kbfscrypto"
    10  	"github.com/keybase/client/go/libkb"
    11  	"github.com/keybase/client/go/protocol/keybase1"
    12  	"github.com/pkg/errors"
    13  	"golang.org/x/net/context"
    14  )
    15  
    16  type perTeamKeyPair struct {
    17  	privKey kbfscrypto.TLFPrivateKey
    18  	pubKey  kbfscrypto.TLFPublicKey
    19  }
    20  
    21  type perTeamKeyPairs map[keybase1.PerTeamKeyGeneration]perTeamKeyPair
    22  
    23  // CryptoLocal implements the Crypto interface by using a local
    24  // signing key and a local crypt private key.
    25  type CryptoLocal struct {
    26  	CryptoCommon
    27  	kbfscrypto.SigningKeySigner
    28  	cryptPrivateKey kbfscrypto.CryptPrivateKey
    29  	teamPrivateKeys map[keybase1.TeamID]perTeamKeyPairs
    30  }
    31  
    32  var _ Crypto = (*CryptoLocal)(nil)
    33  
    34  // NewCryptoLocal constructs a new CryptoLocal instance with the given
    35  // signing key.
    36  func NewCryptoLocal(codec kbfscodec.Codec,
    37  	signingKey kbfscrypto.SigningKey,
    38  	cryptPrivateKey kbfscrypto.CryptPrivateKey,
    39  	blockCryptVersioner blockCryptVersioner) *CryptoLocal {
    40  	return &CryptoLocal{
    41  		MakeCryptoCommon(codec, blockCryptVersioner),
    42  		kbfscrypto.SigningKeySigner{Key: signingKey},
    43  		cryptPrivateKey,
    44  		make(map[keybase1.TeamID]perTeamKeyPairs),
    45  	}
    46  }
    47  
    48  // DecryptTLFCryptKeyClientHalf implements the Crypto interface for
    49  // CryptoLocal.
    50  func (c *CryptoLocal) DecryptTLFCryptKeyClientHalf(ctx context.Context,
    51  	publicKey kbfscrypto.TLFEphemeralPublicKey,
    52  	encryptedClientHalf kbfscrypto.EncryptedTLFCryptKeyClientHalf) (
    53  	kbfscrypto.TLFCryptKeyClientHalf, error) {
    54  	return kbfscrypto.DecryptTLFCryptKeyClientHalf(
    55  		c.cryptPrivateKey, publicKey, encryptedClientHalf)
    56  }
    57  
    58  // DecryptTLFCryptKeyClientHalfAny implements the Crypto interface for
    59  // CryptoLocal.
    60  func (c *CryptoLocal) DecryptTLFCryptKeyClientHalfAny(ctx context.Context,
    61  	keys []EncryptedTLFCryptKeyClientAndEphemeral, _ bool) (
    62  	clientHalf kbfscrypto.TLFCryptKeyClientHalf, index int, err error) {
    63  	if len(keys) == 0 {
    64  		return kbfscrypto.TLFCryptKeyClientHalf{}, -1,
    65  			errors.WithStack(NoKeysError{})
    66  	}
    67  	var firstNonDecryptionErr error
    68  	for i, k := range keys {
    69  		clientHalf, err := c.DecryptTLFCryptKeyClientHalf(
    70  			ctx, k.EPubKey, k.ClientHalf)
    71  		if err != nil {
    72  			_, isDecryptionError :=
    73  				errors.Cause(err).(libkb.DecryptionError)
    74  			if firstNonDecryptionErr == nil && !isDecryptionError {
    75  				firstNonDecryptionErr = err
    76  			}
    77  			continue
    78  		}
    79  		return clientHalf, i, nil
    80  	}
    81  	// This is to mimic the behavior in
    82  	// CryptoClient.DecryptTLFCryptKeyClientHalfAny, which is to,
    83  	// if all calls to prepareTLFCryptKeyClientHalf failed, return
    84  	// the first prep error, and otherwise to return the error
    85  	// from the service, which is usually libkb.DecryptionError.
    86  	if firstNonDecryptionErr != nil {
    87  		return kbfscrypto.TLFCryptKeyClientHalf{}, -1,
    88  			firstNonDecryptionErr
    89  	}
    90  	return kbfscrypto.TLFCryptKeyClientHalf{}, -1,
    91  		errors.WithStack(libkb.DecryptionError{})
    92  }
    93  
    94  func (c *CryptoLocal) pubKeyForTeamKeyGeneration(
    95  	teamID keybase1.TeamID, keyGen keybase1.PerTeamKeyGeneration) (
    96  	pubKey kbfscrypto.TLFPublicKey, err error) {
    97  	if c.teamPrivateKeys[teamID] == nil {
    98  		c.teamPrivateKeys[teamID] = make(perTeamKeyPairs)
    99  	}
   100  
   101  	teamKeys := c.teamPrivateKeys[teamID]
   102  	kp, ok := teamKeys[keyGen]
   103  	// If a key pair doesn't exist yet for this keygen, generate a
   104  	// random one.
   105  	if !ok {
   106  		pubKey, privKey, _, err := c.MakeRandomTLFKeys()
   107  		if err != nil {
   108  			return kbfscrypto.TLFPublicKey{}, err
   109  		}
   110  		kp = perTeamKeyPair{privKey, pubKey}
   111  		c.teamPrivateKeys[teamID][keyGen] = kp
   112  	}
   113  
   114  	return kp.pubKey, nil
   115  }
   116  
   117  // DecryptTeamMerkleLeaf implements the Crypto interface for
   118  // CryptoLocal.
   119  func (c *CryptoLocal) DecryptTeamMerkleLeaf(
   120  	ctx context.Context, teamID keybase1.TeamID,
   121  	publicKey kbfscrypto.TLFEphemeralPublicKey,
   122  	encryptedMerkleLeaf kbfscrypto.EncryptedMerkleLeaf,
   123  	minKeyGen keybase1.PerTeamKeyGeneration) (decryptedData []byte, err error) {
   124  	perTeamKeys := c.teamPrivateKeys[teamID]
   125  	maxKeyGen := keybase1.PerTeamKeyGeneration(len(perTeamKeys))
   126  	for i := minKeyGen; i <= maxKeyGen; i++ {
   127  		decryptedData, err := kbfscrypto.DecryptMerkleLeaf(
   128  			perTeamKeys[i].privKey, publicKey, encryptedMerkleLeaf)
   129  		if err == nil {
   130  			return decryptedData, nil
   131  		}
   132  	}
   133  
   134  	return nil, errors.WithStack(libkb.DecryptionError{})
   135  }
   136  
   137  // Shutdown implements the Crypto interface for CryptoLocal.
   138  func (c *CryptoLocal) Shutdown() {}