/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/engine/crypto.go
375 строк
11 KB
zoom-ua
remove golang.org/x/net/context in favor of context (#28708)
17 дек 2025, 18:24
Не верифицирован
17 дек 2025, 18:24
67b0ffe
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package engine import ( "context" "sync" "github.com/keybase/client/go/kbcrypto" "github.com/keybase/client/go/libkb" keybase1 "github.com/keybase/client/go/protocol/keybase1" "golang.org/x/crypto/nacl/box" ) // getKeyMu synchronizes all accesses to the need to pull in pinentries/secret keys // for this user. var getKeyMu sync.Mutex // GetMySecretKey uses ActiveDevice to get a secret key for the current user. // // It used to have functionality to load the user and prompt for a passphrase to // unlock the keys, but that is outdated now. Either you are logged in and // have your device keys cached, or you aren't. // // If the key isn't found in the ActiveDevice cache, this will return LoginRequiredError. func GetMySecretKey(ctx context.Context, g *libkb.GlobalContext, secretKeyType libkb.SecretKeyType, _ string) (libkb.GenericKey, error) { key, err := g.ActiveDevice.KeyByType(secretKeyType) if err != nil { if _, ok := err.(libkb.NotFoundError); ok { g.Log.CDebugf(ctx, "GetMySecretKey: no device key of type %s in ActiveDevice, returning LoginRequiredError", secretKeyType) return nil, libkb.LoginRequiredError{Context: "GetMySecretKey"} } g.Log.CDebugf(ctx, "GetMySecretKey(%s), unexpected error: %s", secretKeyType, err) return nil, err } return key, nil } // GetMySecretKeyWithUID is like GetMySecretKey but returns an error if uid is not active. func GetMySecretKeyWithUID(ctx context.Context, g *libkb.GlobalContext, uid keybase1.UID, secretKeyType libkb.SecretKeyType, reason string) (libkb.GenericKey, error) { key, err := g.ActiveDevice.KeyByTypeWithUID(uid, secretKeyType) if err != nil { if _, ok := err.(libkb.NotFoundError); ok { g.Log.CDebugf(ctx, "GetMySecretKeyWithUID: no device key of type %s in ActiveDevice, returning LoginRequiredError", secretKeyType) return nil, libkb.LoginRequiredError{Context: "GetMySecretKey"} } g.Log.CDebugf(ctx, "GetMySecretKeyWithUID(%s), unexpected error: %s", secretKeyType, err) return nil, err } return key, nil } // SignED25519 signs the given message with the current user's private // signing key. func SignED25519(ctx context.Context, g *libkb.GlobalContext, arg keybase1.SignED25519Arg) (ret keybase1.ED25519SignatureInfo, err error) { signingKey, err := GetMySecretKey(ctx, g, libkb.DeviceSigningKeyType, arg.Reason) if err != nil { return } kp, ok := signingKey.(libkb.NaclSigningKeyPair) if !ok || kp.Private == nil { err = libkb.KeyCannotSignError{} return } sig := kp.Private.Sign(arg.Msg) publicKey := kp.Public ret = keybase1.ED25519SignatureInfo{ Sig: keybase1.ED25519Signature(sig), PublicKey: keybase1.ED25519PublicKey(publicKey), } return } // SignED25519ForKBFS signs the given message with the current user's private // signing key on behalf of KBFS. func SignED25519ForKBFS(ctx context.Context, g *libkb.GlobalContext, arg keybase1.SignED25519ForKBFSArg) ( ret keybase1.ED25519SignatureInfo, err error, ) { signingKey, err := GetMySecretKey(ctx, g, libkb.DeviceSigningKeyType, arg.Reason) if err != nil { return } kp, ok := signingKey.(libkb.NaclSigningKeyPair) if !ok || kp.Private == nil { err = libkb.KeyCannotSignError{} return } var sigInfo kbcrypto.NaclSigInfo sigInfo, err = kp.SignV2(arg.Msg, kbcrypto.SignaturePrefixKBFS) if err != nil { return } publicKey := kp.Public ret = keybase1.ED25519SignatureInfo{ Sig: keybase1.ED25519Signature(sigInfo.Sig), PublicKey: keybase1.ED25519PublicKey(publicKey), } return } // SignToString signs the given message with the current user's private // signing key and outputs the serialized NaclSigInfo string. func SignToString(ctx context.Context, g *libkb.GlobalContext, arg keybase1.SignToStringArg) (sig string, err error) { signingKey, err := GetMySecretKey(ctx, g, libkb.DeviceSigningKeyType, arg.Reason) if err != nil { return } kp, ok := signingKey.(libkb.NaclSigningKeyPair) if !ok || kp.Private == nil { err = libkb.KeyCannotSignError{} return } sig, _, err = kp.SignToString(arg.Msg) return } // UnboxBytes32 decrypts the given message with the current user's // private encryption key and the given nonce and peer public key. func UnboxBytes32(ctx context.Context, g *libkb.GlobalContext, arg keybase1.UnboxBytes32Arg) (bytes32 keybase1.Bytes32, err error) { encryptionKey, err := GetMySecretKey(ctx, g, libkb.DeviceEncryptionKeyType, arg.Reason) if err != nil { return } return unboxBytes32(encryptionKey, arg.EncryptedBytes32, arg.Nonce, arg.PeersPublicKey) } // UnboxBytes32Any will decrypt any of the KID, ciphertext, nonce // bundles in arg.Bundles. Key preference order: cached device keys, // cached paper keys, local device key, user-entered paper key. // It returns the KID and bundle index along with the plaintext. func UnboxBytes32Any(m libkb.MetaContext, getSecretUI func() libkb.SecretUI, arg keybase1.UnboxBytes32AnyArg) (res keybase1.UnboxAnyRes, err error) { defer m.Trace("UnboxBytes32Any", &err)() // find a matching secret key for a bundle in arg.Bundles key, index, err := getMatchingSecretKey(m, getSecretUI, arg) if err != nil { return res, err } // decrypt the bundle's ciphertext plaintext, err := unboxBytes32(key, arg.Bundles[index].Ciphertext, arg.Bundles[index].Nonce, arg.Bundles[index].PublicKey) if err != nil { return res, err } // return plaintext, kid, and index res.Plaintext = plaintext res.Kid = key.GetKID() res.Index = index return res, nil } func unboxBytes32(encryptionKey libkb.GenericKey, ciphertext keybase1.EncryptedBytes32, nonce keybase1.BoxNonce, peerPubKey keybase1.BoxPublicKey) (bytes32 keybase1.Bytes32, err error) { kp, ok := encryptionKey.(libkb.NaclDHKeyPair) if !ok { err = libkb.KeyCannotDecryptError{} return } if kp.Private == nil { err = libkb.NoSecretKeyError{} return } decryptedData, ok := box.Open(nil, ciphertext[:], (*[24]byte)(&nonce), (*[32]byte)(&peerPubKey), (*[32]byte)(kp.Private)) if !ok { err = libkb.DecryptionError{} return } if len(decryptedData) != len(bytes32) { err = libkb.DecryptionError{} return } copy(bytes32[:], decryptedData) return } func getMatchingSecretKey(m libkb.MetaContext, getSecretUI func() libkb.SecretUI, arg keybase1.UnboxBytes32AnyArg) (key libkb.GenericKey, index int, err error) { // first check cached keys key, index, err = matchingCachedKey(m, arg) if err != nil { return nil, 0, err } if key != nil { return key, index, nil } m.Debug("getMatchingSecretKey: acquiring lock") getKeyMu.Lock() defer func() { getKeyMu.Unlock() m.Debug("getMatchingSecretKey: lock released") }() m.Debug("getMatchingSecretKey: lock acquired") // check cache after acquiring lock key, index, err = matchingCachedKey(m, arg) if err != nil { return nil, 0, err } if key != nil { return key, index, nil } m.Debug("getMatchingSecretKey: no matching cached device key found") // load the user me, err := libkb.LoadMe(libkb.NewLoadUserArgWithMetaContext(m)) if err != nil { return nil, 0, err } // need secretUI now: secretUI := getSecretUI() // check the device key for this user key, index, err = matchingDeviceKey(m, secretUI, arg, me) if err != nil { return nil, 0, err } if key != nil { return key, index, nil } m.Debug("getMatchingSecretKey: no matching device key found") if !arg.PromptPaper { m.Debug("UnboxBytes32Any/getMatchingSecretKey: not checking paper keys (promptPaper == false)") return nil, 0, libkb.NoSecretKeyError{} } // check the paper keys for this user key, index, err = matchingPaperKey(m, secretUI, arg, me) if err != nil { return nil, 0, err } if key != nil { return key, index, nil } return nil, 0, libkb.NoSecretKeyError{} } // check cached keys for arg.Bundles match. func matchingCachedKey(m libkb.MetaContext, arg keybase1.UnboxBytes32AnyArg) (key libkb.GenericKey, index int, err error) { // check device key first dkey, err := m.ActiveDevice().EncryptionKey() if err == nil && dkey != nil { if n, ok := kidMatch(dkey, arg.Bundles); ok { return dkey, n, nil } } device := m.ActiveDevice().ProvisioningKey(m) if device != nil { pkey := device.EncryptionKey() if n, ok := kidMatch(pkey, arg.Bundles); ok { return pkey, n, nil } } return nil, 0, nil } // check device key for arg.Bundles match. func matchingDeviceKey(m libkb.MetaContext, secretUI libkb.SecretUI, arg keybase1.UnboxBytes32AnyArg, me *libkb.User) (key libkb.GenericKey, index int, err error) { ekey, err := me.GetDeviceSubkey() if err == nil { if n, ok := kidMatch(ekey, arg.Bundles); ok { // unlock this key parg := libkb.SecretKeyPromptArg{ Ska: libkb.SecretKeyArg{ Me: me, KeyType: libkb.DeviceEncryptionKeyType, }, SecretUI: secretUI, Reason: arg.Reason, UseCancelCache: true, } key, err := m.G().Keyrings.GetSecretKeyWithPrompt(m, parg) if err != nil { return nil, 0, err } return key, n, nil } m.Debug("matchingDeviceKey: no match found for ekey in arg.Bundles") logNoMatch(m, ekey, arg.Bundles) } else { m.Debug("matchingDeviceKey: ignoring error getting device subkey: %s", err) } return nil, 0, nil } // check all the user's paper keys for arg.Bundles match func matchingPaperKey(m libkb.MetaContext, secretUI libkb.SecretUI, arg keybase1.UnboxBytes32AnyArg, me *libkb.User) (key libkb.GenericKey, index int, err error) { cki := me.GetComputedKeyInfos() if cki == nil { return nil, 0, nil } var matchingPaper []*libkb.Device for _, pdev := range cki.PaperDevices() { enckey, err := me.GetComputedKeyFamily().GetEncryptionSubkeyForDevice(pdev.ID) if err != nil { return nil, 0, err } if _, ok := kidMatch(enckey, arg.Bundles); ok { m.Debug("matching paper key: %s", *pdev.Description) matchingPaper = append(matchingPaper, pdev) } } if len(matchingPaper) == 0 { m.Debug("no matching paper keys found") return nil, 0, nil } phrase, err := libkb.GetPaperKeyForCryptoPassphrase(m, secretUI, arg.Reason, matchingPaper) if err != nil { return nil, 0, err } paperPhrase, err := libkb.NewPaperKeyPhraseCheckVersion(m, phrase) if err != nil { return nil, 0, err } bkarg := &PaperKeyGenArg{ Passphrase: paperPhrase, SkipPush: true, } bkeng := NewPaperKeyGen(m.G(), bkarg) if err := RunEngine2(m, bkeng); err != nil { return nil, 0, err } // find the index for the key they entered (and make sure the key they entered matches) if n, ok := kidMatch(bkeng.EncKey(), arg.Bundles); ok { m.ActiveDevice().CacheProvisioningKey(m, bkeng.DeviceWithKeys()) return bkeng.EncKey(), n, nil } return nil, 0, nil } func kidMatch(key libkb.GenericKey, bundles []keybase1.CiphertextBundle) (int, bool) { if key == nil { return -1, false } kid := key.GetKID() for i, bundle := range bundles { if kid.Equal(bundle.Kid) { return i, true } } return -1, false } func logNoMatch(m libkb.MetaContext, key libkb.GenericKey, bundles []keybase1.CiphertextBundle) { if key == nil { m.Debug("logNoMatch: key is nil") return } kid := key.GetKID() m.Debug("logNoMatch: desired kid: %s", kid) for i, bundle := range bundles { m.Debug("logNoMatch: kid %d: %s (%v)", i, bundle.Kid, kid.Equal(bundle.Kid)) } }