github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/kbfs/libkbfs/crypto_client.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 "time" 9 10 "github.com/keybase/client/go/kbcrypto" 11 "github.com/keybase/client/go/kbfs/kbfscrypto" 12 "github.com/keybase/client/go/logger" 13 "github.com/keybase/client/go/protocol/keybase1" 14 "github.com/pkg/errors" 15 "golang.org/x/net/context" 16 ) 17 18 // CryptoClient is a keybase1.CryptoInterface based implementation for Crypto. 19 type CryptoClient struct { 20 CryptoCommon 21 log logger.Logger 22 deferLog logger.Logger 23 client keybase1.CryptoInterface 24 teamsClient keybase1.TeamsInterface 25 shutdownFn func() 26 } 27 28 // cryptoWarningTime says how long we should wait before logging a 29 // message about it taking too long. 30 const cryptoWarningTime = 2 * time.Minute 31 32 var _ Crypto = (*CryptoClient)(nil) 33 34 func (c *CryptoClient) logAboutTooLongUnlessCancelled(ctx context.Context, 35 method string) *time.Timer { 36 return time.AfterFunc(cryptoWarningTime, func() { 37 log := c.log.CloneWithAddedDepth(2) 38 log.CInfof(ctx, "%s call took more than %s", method, 39 cryptoWarningTime) 40 }) 41 } 42 43 // Sign implements the Crypto interface for CryptoClient. 44 func (c *CryptoClient) Sign(ctx context.Context, msg []byte) ( 45 sigInfo kbfscrypto.SignatureInfo, err error) { 46 c.log.CDebugf(ctx, "Signing %d-byte message", len(msg)) 47 defer func() { 48 c.deferLog.CDebugf(ctx, "Signed %d-byte message with %s: err=%+v", len(msg), 49 sigInfo, err) 50 }() 51 52 timer := c.logAboutTooLongUnlessCancelled(ctx, "SignED25519") 53 defer timer.Stop() 54 ed25519SigInfo, err := c.client.SignED25519(ctx, keybase1.SignED25519Arg{ 55 Msg: msg, 56 Reason: "to use kbfs", 57 }) 58 if err != nil { 59 return kbfscrypto.SignatureInfo{}, errors.WithStack(err) 60 } 61 62 return kbfscrypto.SignatureInfo{ 63 Version: kbfscrypto.SigED25519, 64 Signature: ed25519SigInfo.Sig[:], 65 VerifyingKey: kbfscrypto.MakeVerifyingKey(kbcrypto.NaclSigningKeyPublic(ed25519SigInfo.PublicKey).GetKID()), 66 }, nil 67 } 68 69 // SignForKBFS implements the Crypto interface for CryptoClient. 70 func (c *CryptoClient) SignForKBFS(ctx context.Context, msg []byte) ( 71 sigInfo kbfscrypto.SignatureInfo, err error) { 72 c.log.CDebugf(ctx, "Signing %d-byte message", len(msg)) 73 defer func() { 74 c.deferLog.CDebugf(ctx, "Signed %d-byte message with %s: err=%+v", len(msg), 75 sigInfo, err) 76 }() 77 78 timer := c.logAboutTooLongUnlessCancelled(ctx, "SignED25519ForKBFS") 79 defer timer.Stop() 80 ed25519SigInfo, err := c.client.SignED25519ForKBFS(ctx, keybase1.SignED25519ForKBFSArg{ 81 Msg: msg, 82 Reason: "to use kbfs", 83 }) 84 if err != nil { 85 return kbfscrypto.SignatureInfo{}, errors.WithStack(err) 86 } 87 88 return kbfscrypto.SignatureInfo{ 89 Version: kbfscrypto.SigED25519ForKBFS, 90 Signature: ed25519SigInfo.Sig[:], 91 VerifyingKey: kbfscrypto.MakeVerifyingKey(kbcrypto.NaclSigningKeyPublic(ed25519SigInfo.PublicKey).GetKID()), 92 }, nil 93 } 94 95 // SignToString implements the Crypto interface for CryptoClient. 96 func (c *CryptoClient) SignToString(ctx context.Context, msg []byte) ( 97 signature string, err error) { 98 c.log.CDebugf(ctx, "Signing %d-byte message to string", len(msg)) 99 defer func() { 100 c.deferLog.CDebugf(ctx, "Signed %d-byte message: err=%+v", len(msg), err) 101 }() 102 103 timer := c.logAboutTooLongUnlessCancelled(ctx, "SignToString") 104 defer timer.Stop() 105 signature, err = c.client.SignToString(ctx, keybase1.SignToStringArg{ 106 Msg: msg, 107 Reason: "KBFS Authentication", 108 }) 109 if err != nil { 110 return "", errors.WithStack(err) 111 } 112 return signature, nil 113 } 114 115 func (c *CryptoClient) prepareTLFCryptKeyClientHalf( 116 encryptedClientHalf kbfscrypto.EncryptedTLFCryptKeyClientHalf) ( 117 encryptedData keybase1.EncryptedBytes32, nonce keybase1.BoxNonce, 118 err error) { 119 if encryptedClientHalf.Version != kbfscrypto.EncryptionSecretbox { 120 return keybase1.EncryptedBytes32{}, keybase1.BoxNonce{}, 121 errors.WithStack(kbfscrypto.UnknownEncryptionVer{ 122 Ver: encryptedClientHalf.Version}) 123 } 124 125 if len(encryptedClientHalf.EncryptedData) != len(encryptedData) { 126 return keybase1.EncryptedBytes32{}, keybase1.BoxNonce{}, 127 errors.Errorf("Expected %d bytes, got %d", 128 len(encryptedData), 129 len(encryptedClientHalf.EncryptedData)) 130 } 131 copy(encryptedData[:], encryptedClientHalf.EncryptedData) 132 133 if len(encryptedClientHalf.Nonce) != len(nonce) { 134 return keybase1.EncryptedBytes32{}, keybase1.BoxNonce{}, 135 errors.WithStack(kbfscrypto.InvalidNonceError{ 136 Nonce: encryptedClientHalf.Nonce}) 137 } 138 copy(nonce[:], encryptedClientHalf.Nonce) 139 return encryptedData, nonce, nil 140 } 141 142 // DecryptTLFCryptKeyClientHalf implements the Crypto interface for 143 // CryptoClient. 144 func (c *CryptoClient) DecryptTLFCryptKeyClientHalf(ctx context.Context, 145 publicKey kbfscrypto.TLFEphemeralPublicKey, 146 encryptedClientHalf kbfscrypto.EncryptedTLFCryptKeyClientHalf) ( 147 clientHalf kbfscrypto.TLFCryptKeyClientHalf, err error) { 148 c.log.CDebugf(ctx, "Decrypting TLF client key half") 149 defer func() { 150 c.deferLog.CDebugf(ctx, "Decrypted TLF client key half: %+v", 151 err) 152 }() 153 encryptedData, nonce, err := c.prepareTLFCryptKeyClientHalf( 154 encryptedClientHalf) 155 if err != nil { 156 return kbfscrypto.TLFCryptKeyClientHalf{}, err 157 } 158 159 timer := c.logAboutTooLongUnlessCancelled(ctx, "UnboxBytes32") 160 defer timer.Stop() 161 decryptedClientHalf, err := c.client.UnboxBytes32(ctx, keybase1.UnboxBytes32Arg{ 162 EncryptedBytes32: encryptedData, 163 Nonce: nonce, 164 PeersPublicKey: keybase1.BoxPublicKey(publicKey.Data()), 165 Reason: "to use kbfs", 166 }) 167 if err != nil { 168 return kbfscrypto.TLFCryptKeyClientHalf{}, errors.WithStack(err) 169 } 170 171 return kbfscrypto.MakeTLFCryptKeyClientHalf(decryptedClientHalf), nil 172 } 173 174 // DecryptTLFCryptKeyClientHalfAny implements the Crypto interface for 175 // CryptoClient. 176 func (c *CryptoClient) DecryptTLFCryptKeyClientHalfAny(ctx context.Context, 177 keys []EncryptedTLFCryptKeyClientAndEphemeral, promptPaper bool) ( 178 clientHalf kbfscrypto.TLFCryptKeyClientHalf, index int, err error) { 179 c.log.CDebugf(ctx, "Decrypting TLF client key half with any key") 180 defer func() { 181 c.deferLog.CDebugf(ctx, 182 "Decrypted TLF client key half with any key: %+v", 183 err) 184 }() 185 if len(keys) == 0 { 186 return kbfscrypto.TLFCryptKeyClientHalf{}, -1, 187 errors.WithStack(NoKeysError{}) 188 } 189 bundles := make([]keybase1.CiphertextBundle, 0, len(keys)) 190 prepErrs := make([]error, 0, len(keys)) 191 indexLookup := make([]int, 0, len(keys)) 192 for i, k := range keys { 193 encryptedData, nonce, prepErr := 194 c.prepareTLFCryptKeyClientHalf(k.ClientHalf) 195 if err != nil { 196 prepErrs = append(prepErrs, prepErr) 197 } else { 198 bundles = append(bundles, keybase1.CiphertextBundle{ 199 Kid: k.PubKey.KID(), 200 Ciphertext: encryptedData, 201 Nonce: nonce, 202 PublicKey: keybase1.BoxPublicKey(k.EPubKey.Data()), 203 }) 204 indexLookup = append(indexLookup, i) 205 } 206 } 207 if len(bundles) == 0 { 208 return kbfscrypto.TLFCryptKeyClientHalf{}, -1, prepErrs[0] 209 } 210 timer := c.logAboutTooLongUnlessCancelled(ctx, "UnboxBytes32Any") 211 defer timer.Stop() 212 res, err := c.client.UnboxBytes32Any(ctx, keybase1.UnboxBytes32AnyArg{ 213 Bundles: bundles, 214 Reason: "to rekey for kbfs", 215 PromptPaper: promptPaper, 216 }) 217 if err != nil { 218 return kbfscrypto.TLFCryptKeyClientHalf{}, -1, 219 errors.WithStack(err) 220 } 221 return kbfscrypto.MakeTLFCryptKeyClientHalf(res.Plaintext), 222 indexLookup[res.Index], nil 223 } 224 225 // DecryptTeamMerkleLeaf implements the Crypto interface for 226 // CryptoClient. 227 func (c *CryptoClient) DecryptTeamMerkleLeaf( 228 ctx context.Context, teamID keybase1.TeamID, 229 publicKey kbfscrypto.TLFEphemeralPublicKey, 230 encryptedMerkleLeaf kbfscrypto.EncryptedMerkleLeaf, 231 minKeyGen keybase1.PerTeamKeyGeneration) (decryptedData []byte, err error) { 232 c.log.CDebugf(ctx, "Decrypting team Merkle leaf") 233 defer func() { 234 c.deferLog.CDebugf(ctx, "Decrypted team Merkle leaf: %+v", err) 235 }() 236 nonce, err := kbfscrypto.PrepareMerkleLeaf( 237 encryptedMerkleLeaf) 238 if err != nil { 239 return nil, err 240 } 241 242 timer := c.logAboutTooLongUnlessCancelled(ctx, "DecryptTeamMerkleLeaf") 243 defer timer.Stop() 244 decryptedData, err = c.teamsClient.TryDecryptWithTeamKey(ctx, 245 keybase1.TryDecryptWithTeamKeyArg{ 246 TeamID: teamID, 247 EncryptedData: encryptedMerkleLeaf.EncryptedData, 248 Nonce: nonce, 249 PeersPublicKey: keybase1.BoxPublicKey(publicKey.Data()), 250 MinGeneration: minKeyGen, 251 }) 252 if err != nil { 253 return nil, errors.WithStack(err) 254 } 255 return decryptedData, nil 256 } 257 258 // Shutdown implements the Crypto interface for CryptoClient. 259 func (c *CryptoClient) Shutdown() { 260 if c.shutdownFn != nil { 261 c.shutdownFn() 262 } 263 }