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 5package libkbfs 6 7import ( 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 16type perTeamKeyPair struct { 17 privKey kbfscrypto.TLFPrivateKey 18 pubKey kbfscrypto.TLFPublicKey 19} 20 21type 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. 25type CryptoLocal struct { 26 CryptoCommon 27 kbfscrypto.SigningKeySigner 28 cryptPrivateKey kbfscrypto.CryptPrivateKey 29 teamPrivateKeys map[keybase1.TeamID]perTeamKeyPairs 30} 31 32var _ Crypto = (*CryptoLocal)(nil) 33 34// NewCryptoLocal constructs a new CryptoLocal instance with the given 35// signing key. 36func 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. 50func (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. 60func (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 94func (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. 119func (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. 138func (c *CryptoLocal) Shutdown() {} 139