/
githubmirror
/
client
Обзор
Документация
Войти
/
githubmirror
/
client
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
go/engine/paperkey_gen.go
371 строка
9 KB
zoom-ua
gofumpt (#28710)
17 дек 2025, 17:16
Не верифицирован
17 дек 2025, 17:16
cda510b
Код
Авторство
О чём код?
// Copyright 2015 Keybase, Inc. All rights reserved. Use of // this source code is governed by the included BSD license. package engine import ( "bytes" "crypto/ed25519" "errors" "fmt" "golang.org/x/crypto/nacl/box" "golang.org/x/crypto/scrypt" "github.com/keybase/client/go/kbcrypto" "github.com/keybase/client/go/libkb" "github.com/keybase/client/go/protocol/keybase1" ) type PaperKeyGenArg struct { Passphrase libkb.PaperKeyPhrase SkipPush bool // One of Me or UID is required // Me is required if not SkipPush Me *libkb.User UID keybase1.UID SigningKey libkb.GenericKey // optional EncryptionKey libkb.NaclDHKeyPair // optional PerUserKeyring *libkb.PerUserKeyring // optional IsEldest bool } // PaperKeyGen is an engine. type PaperKeyGen struct { arg *PaperKeyGenArg // keys of the generated paper key sigKey libkb.GenericKey encKey libkb.NaclDHKeyPair deviceID keybase1.DeviceID libkb.Contextified } // NewPaperKeyGen creates a PaperKeyGen engine. func NewPaperKeyGen(g *libkb.GlobalContext, arg *PaperKeyGenArg) *PaperKeyGen { return &PaperKeyGen{ arg: arg, Contextified: libkb.NewContextified(g), } } // Name is the unique engine name. func (e *PaperKeyGen) Name() string { return "PaperKeyGen" } // GetPrereqs returns the engine prereqs. func (e *PaperKeyGen) Prereqs() Prereqs { // only need a device if pushing keys return Prereqs{ Device: !e.arg.SkipPush && !e.arg.IsEldest, } } // RequiredUIs returns the required UIs. func (e *PaperKeyGen) RequiredUIs() []libkb.UIKind { return []libkb.UIKind{} } // SubConsumers returns the other UI consumers for this engine. func (e *PaperKeyGen) SubConsumers() []libkb.UIConsumer { return nil } func (e *PaperKeyGen) SigKey() libkb.GenericKey { return e.sigKey } func (e *PaperKeyGen) EncKey() libkb.NaclDHKeyPair { return e.encKey } func (e *PaperKeyGen) DeviceID() keybase1.DeviceID { return e.deviceID } func (e *PaperKeyGen) DeviceWithKeys() *libkb.DeviceWithKeys { return libkb.NewDeviceWithKeysOnly(e.sigKey, e.encKey, libkb.KeychainModeNone) } // Run starts the engine. func (e *PaperKeyGen) Run(m libkb.MetaContext) error { if !e.arg.SkipPush { err := e.syncPUK(m) if err != nil { return err } } // make the passphrase stream key, err := scrypt.Key(e.arg.Passphrase.Bytes(), nil, libkb.PaperKeyScryptCost, libkb.PaperKeyScryptR, libkb.PaperKeyScryptP, libkb.PaperKeyScryptKeylen) if err != nil { return err } ppStream := libkb.NewPassphraseStream(key) // make keys for the paper device if err := e.makeSigKey(ppStream.EdDSASeed()); err != nil { return err } if err := e.makeEncKey(ppStream.DHSeed()); err != nil { return err } // push everything to the server if err := e.push(m); err != nil { return err } // no need to notify if key wasn't pushed to server // (e.g. in the case of using this engine to verify a key) if e.arg.SkipPush { return nil } e.G().KeyfamilyChanged(m.Ctx(), e.getUID()) return nil } func (e *PaperKeyGen) getUID() keybase1.UID { if !e.arg.UID.IsNil() { return e.arg.UID } if e.arg.Me != nil { return e.arg.Me.GetUID() } return keybase1.UID("") } func (e *PaperKeyGen) syncPUK(m libkb.MetaContext) error { // Sync the per-user-key keyring before updating other things. pukring, err := e.getPerUserKeyring(m) if err != nil { return err } var upak *keybase1.UserPlusAllKeys if e.arg.Me != nil { tmp := e.arg.Me.ExportToUserPlusAllKeys() upak = &tmp } err = pukring.SyncWithExtras(m, upak) if err != nil { return err } return nil } func (e *PaperKeyGen) makeSigKey(seed []byte) error { pub, priv, err := ed25519.GenerateKey(bytes.NewBuffer(seed)) if err != nil { return err } var key libkb.NaclSigningKeyPair copy(key.Public[:], pub[:]) key.Private = &kbcrypto.NaclSigningKeyPrivate{} copy(key.Private[:], priv[:]) e.sigKey = key return nil } func (e *PaperKeyGen) makeEncKey(seed []byte) error { pub, priv, err := box.GenerateKey(bytes.NewBuffer(seed)) if err != nil { return err } var key libkb.NaclDHKeyPair copy(key.Public[:], (*pub)[:]) key.Private = &libkb.NaclDHKeyPrivate{} copy(key.Private[:], (*priv)[:]) e.encKey = key return nil } func (e *PaperKeyGen) getClientHalfFromSecretStore(m libkb.MetaContext) (clientHalf libkb.LKSecClientHalf, ppgen libkb.PassphraseGeneration, err error) { defer m.Trace("PaperKeyGen#getClientHalfFromSecretStore", &err) secretStore := libkb.NewSecretStore(m, e.arg.Me.GetNormalizedName()) if secretStore == nil { return clientHalf, ppgen, errors.New("No secret store available") } secret, err := secretStore.RetrieveSecret(m) if err != nil { return clientHalf, ppgen, err } devid := e.G().Env.GetDeviceID() if devid.IsNil() { return clientHalf, ppgen, fmt.Errorf("no device id set") } var ss *libkb.SecretSyncer ss, err = m.ActiveDevice().SyncSecrets(m) if err != nil { return clientHalf, ppgen, err } var dev libkb.DeviceKey dev, err = ss.FindDevice(devid) if err != nil { return clientHalf, ppgen, err } serverHalf, err := libkb.NewLKSecServerHalfFromHex(dev.LksServerHalf) if err != nil { return clientHalf, ppgen, err } clientHalf = serverHalf.ComputeClientHalf(secret) return clientHalf, dev.PPGen, nil } func (e *PaperKeyGen) push(m libkb.MetaContext) (err error) { defer m.Trace("PaperKeyGen#push", &err)() if e.arg.SkipPush { return nil } if e.arg.Me == nil { return errors.New("no Me object but we wanted to push public keys") } // Create a new paper key device. Need the passphrase prefix // for the paper device name. This is the first two words in // the passphrase. There is sufficient entropy to cover this... backupDev, err := libkb.NewPaperDevice(e.arg.Passphrase.Prefix()) if err != nil { return err } e.deviceID = backupDev.ID // create lks halves for this device. Note that they aren't used for // local, encrypted storage of the paper keys, but just for recovery // purposes. m.Dump() // Clear the passphrase stream if it's outdated, just in case some // other device changed the passphrase. if err := m.G().ActiveDevice.ClearPassphraseStreamCacheIfOutdated(m); err != nil { return err } var ppgen libkb.PassphraseGeneration var clientHalf libkb.LKSecClientHalf if stream := m.PassphraseStream(); stream != nil { m.Debug("Got cached passphrase stream") clientHalf = stream.LksClientHalf() ppgen = stream.Generation() } else { m.Debug("Got nil passphrase stream; going to secret store") // stream was nil, so we must have loaded lks from the secret // store. clientHalf, ppgen, err = e.getClientHalfFromSecretStore(m) switch err.(type) { case nil: case libkb.SecretStoreError: // as a last resort try to prompt the user for their passphrase if // the SecretUI is present if m.UIs().HasUI(libkb.SecretUIKind) { if pps, _, perr := libkb.GetPassphraseStreamViaPrompt(m); pps != nil { clientHalf = pps.LksClientHalf() ppgen = pps.Generation() } else if perr != nil { return perr } else { return err } } default: return err } } backupLks := libkb.NewLKSecWithClientHalf(clientHalf, ppgen, e.arg.Me.GetUID()) backupLks.SetServerHalf(libkb.NewLKSecServerHalfZeros()) ctext, err := backupLks.EncryptClientHalfRecovery(e.encKey) if err != nil { return err } if err := libkb.PostDeviceLKS(m, backupDev.ID, keybase1.DeviceTypeV2_PAPER, backupLks.GetServerHalf(), backupLks.Generation(), ctext, e.encKey.GetKID()); err != nil { return err } // push the paper signing key sigDel := libkb.Delegator{ NewKey: e.sigKey, Expire: libkb.NaclEdDSAExpireIn, Me: e.arg.Me, Device: backupDev, Contextified: libkb.NewContextified(e.G()), } if e.arg.IsEldest { sigDel.DelegationType = libkb.DelegationTypeEldest } else { sigDel.DelegationType = libkb.DelegationTypeSibkey sigDel.ExistingKey = e.arg.SigningKey } // push the paper encryption key sigEnc := libkb.Delegator{ NewKey: e.encKey, DelegationType: libkb.DelegationTypeSubkey, Expire: libkb.NaclDHExpireIn, ExistingKey: e.sigKey, Me: e.arg.Me, Device: backupDev, Contextified: libkb.NewContextified(e.G()), } pukBoxes, err := e.makePerUserKeyBoxes(m) if err != nil { return err } m.Debug("PaperKeyGen#push running delegators") return libkb.DelegatorAggregator(m, []libkb.Delegator{sigDel, sigEnc}, nil, pukBoxes, nil, nil) } func (e *PaperKeyGen) makePerUserKeyBoxes(m libkb.MetaContext) ([]keybase1.PerUserKeyBox, error) { m.Debug("PaperKeyGen#makePerUserKeyBoxes") var pukBoxes []keybase1.PerUserKeyBox pukring, err := e.getPerUserKeyring(m) if err != nil { return nil, err } if pukring.HasAnyKeys() { if e.arg.EncryptionKey.IsNil() { return nil, errors.New("missing encryption key for creating paper key") } pukBox, err := pukring.PrepareBoxForNewDevice(m, e.encKey, // receiver key: new paper key enc e.arg.EncryptionKey) // sender key: this device enc if err != nil { return nil, err } pukBoxes = append(pukBoxes, pukBox) } m.Debug("PaperKeyGen#makePerUserKeyBoxes -> %v", len(pukBoxes)) return pukBoxes, nil } func (e *PaperKeyGen) getPerUserKeyring(mctx libkb.MetaContext) (ret *libkb.PerUserKeyring, err error) { ret = e.arg.PerUserKeyring if ret != nil { return } ret, err = e.G().GetPerUserKeyring(mctx.Ctx()) return }