github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/engine/paperkey_gen.go (about) 1 // Copyright 2015 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package engine 5 6 import ( 7 "bytes" 8 "errors" 9 "fmt" 10 11 "github.com/keybase/go-crypto/ed25519" 12 "golang.org/x/crypto/nacl/box" 13 "golang.org/x/crypto/scrypt" 14 15 "github.com/keybase/client/go/kbcrypto" 16 "github.com/keybase/client/go/libkb" 17 "github.com/keybase/client/go/protocol/keybase1" 18 ) 19 20 type PaperKeyGenArg struct { 21 Passphrase libkb.PaperKeyPhrase 22 SkipPush bool 23 24 // One of Me or UID is required 25 // Me is required if not SkipPush 26 Me *libkb.User 27 UID keybase1.UID 28 29 SigningKey libkb.GenericKey // optional 30 EncryptionKey libkb.NaclDHKeyPair // optional 31 PerUserKeyring *libkb.PerUserKeyring // optional 32 IsEldest bool 33 } 34 35 // PaperKeyGen is an engine. 36 type PaperKeyGen struct { 37 arg *PaperKeyGenArg 38 39 // keys of the generated paper key 40 sigKey libkb.GenericKey 41 encKey libkb.NaclDHKeyPair 42 deviceID keybase1.DeviceID 43 44 libkb.Contextified 45 } 46 47 // NewPaperKeyGen creates a PaperKeyGen engine. 48 func NewPaperKeyGen(g *libkb.GlobalContext, arg *PaperKeyGenArg) *PaperKeyGen { 49 return &PaperKeyGen{ 50 arg: arg, 51 Contextified: libkb.NewContextified(g), 52 } 53 } 54 55 // Name is the unique engine name. 56 func (e *PaperKeyGen) Name() string { 57 return "PaperKeyGen" 58 } 59 60 // GetPrereqs returns the engine prereqs. 61 func (e *PaperKeyGen) Prereqs() Prereqs { 62 // only need a device if pushing keys 63 return Prereqs{ 64 Device: !e.arg.SkipPush && !e.arg.IsEldest, 65 } 66 } 67 68 // RequiredUIs returns the required UIs. 69 func (e *PaperKeyGen) RequiredUIs() []libkb.UIKind { 70 return []libkb.UIKind{} 71 } 72 73 // SubConsumers returns the other UI consumers for this engine. 74 func (e *PaperKeyGen) SubConsumers() []libkb.UIConsumer { 75 return nil 76 } 77 78 func (e *PaperKeyGen) SigKey() libkb.GenericKey { 79 return e.sigKey 80 } 81 82 func (e *PaperKeyGen) EncKey() libkb.NaclDHKeyPair { 83 return e.encKey 84 } 85 86 func (e *PaperKeyGen) DeviceID() keybase1.DeviceID { 87 return e.deviceID 88 } 89 90 func (e *PaperKeyGen) DeviceWithKeys() *libkb.DeviceWithKeys { 91 return libkb.NewDeviceWithKeysOnly(e.sigKey, e.encKey, libkb.KeychainModeNone) 92 } 93 94 // Run starts the engine. 95 func (e *PaperKeyGen) Run(m libkb.MetaContext) error { 96 if !e.arg.SkipPush { 97 err := e.syncPUK(m) 98 if err != nil { 99 return err 100 } 101 } 102 103 // make the passphrase stream 104 key, err := scrypt.Key(e.arg.Passphrase.Bytes(), nil, 105 libkb.PaperKeyScryptCost, libkb.PaperKeyScryptR, libkb.PaperKeyScryptP, libkb.PaperKeyScryptKeylen) 106 if err != nil { 107 return err 108 } 109 110 ppStream := libkb.NewPassphraseStream(key) 111 112 // make keys for the paper device 113 if err := e.makeSigKey(ppStream.EdDSASeed()); err != nil { 114 return err 115 } 116 if err := e.makeEncKey(ppStream.DHSeed()); err != nil { 117 return err 118 } 119 120 // push everything to the server 121 if err := e.push(m); err != nil { 122 return err 123 } 124 125 // no need to notify if key wasn't pushed to server 126 // (e.g. in the case of using this engine to verify a key) 127 if e.arg.SkipPush { 128 return nil 129 } 130 131 e.G().KeyfamilyChanged(m.Ctx(), e.getUID()) 132 133 return nil 134 } 135 136 func (e *PaperKeyGen) getUID() keybase1.UID { 137 if !e.arg.UID.IsNil() { 138 return e.arg.UID 139 } 140 if e.arg.Me != nil { 141 return e.arg.Me.GetUID() 142 } 143 return keybase1.UID("") 144 } 145 146 func (e *PaperKeyGen) syncPUK(m libkb.MetaContext) error { 147 // Sync the per-user-key keyring before updating other things. 148 pukring, err := e.getPerUserKeyring(m) 149 if err != nil { 150 return err 151 } 152 var upak *keybase1.UserPlusAllKeys 153 if e.arg.Me != nil { 154 tmp := e.arg.Me.ExportToUserPlusAllKeys() 155 upak = &tmp 156 } 157 err = pukring.SyncWithExtras(m, upak) 158 if err != nil { 159 return err 160 } 161 return nil 162 } 163 164 func (e *PaperKeyGen) makeSigKey(seed []byte) error { 165 pub, priv, err := ed25519.GenerateKey(bytes.NewBuffer(seed)) 166 if err != nil { 167 return err 168 } 169 170 var key libkb.NaclSigningKeyPair 171 copy(key.Public[:], pub[:]) 172 key.Private = &kbcrypto.NaclSigningKeyPrivate{} 173 copy(key.Private[:], priv[:]) 174 175 e.sigKey = key 176 177 return nil 178 } 179 180 func (e *PaperKeyGen) makeEncKey(seed []byte) error { 181 pub, priv, err := box.GenerateKey(bytes.NewBuffer(seed)) 182 if err != nil { 183 return err 184 } 185 var key libkb.NaclDHKeyPair 186 copy(key.Public[:], (*pub)[:]) 187 key.Private = &libkb.NaclDHKeyPrivate{} 188 copy(key.Private[:], (*priv)[:]) 189 190 e.encKey = key 191 192 return nil 193 } 194 195 func (e *PaperKeyGen) getClientHalfFromSecretStore(m libkb.MetaContext) (clientHalf libkb.LKSecClientHalf, ppgen libkb.PassphraseGeneration, err error) { 196 defer m.Trace("PaperKeyGen#getClientHalfFromSecretStore", &err) 197 198 secretStore := libkb.NewSecretStore(m, e.arg.Me.GetNormalizedName()) 199 if secretStore == nil { 200 return clientHalf, ppgen, errors.New("No secret store available") 201 } 202 203 secret, err := secretStore.RetrieveSecret(m) 204 if err != nil { 205 return clientHalf, ppgen, err 206 } 207 208 devid := e.G().Env.GetDeviceID() 209 if devid.IsNil() { 210 return clientHalf, ppgen, fmt.Errorf("no device id set") 211 } 212 var ss *libkb.SecretSyncer 213 ss, err = m.ActiveDevice().SyncSecrets(m) 214 if err != nil { 215 return clientHalf, ppgen, err 216 } 217 var dev libkb.DeviceKey 218 dev, err = ss.FindDevice(devid) 219 if err != nil { 220 return clientHalf, ppgen, err 221 } 222 serverHalf, err := libkb.NewLKSecServerHalfFromHex(dev.LksServerHalf) 223 if err != nil { 224 return clientHalf, ppgen, err 225 } 226 227 clientHalf = serverHalf.ComputeClientHalf(secret) 228 229 return clientHalf, dev.PPGen, nil 230 } 231 232 func (e *PaperKeyGen) push(m libkb.MetaContext) (err error) { 233 defer m.Trace("PaperKeyGen#push", &err)() 234 if e.arg.SkipPush { 235 return nil 236 } 237 238 if e.arg.Me == nil { 239 return errors.New("no Me object but we wanted to push public keys") 240 } 241 242 // Create a new paper key device. Need the passphrase prefix 243 // for the paper device name. This is the first two words in 244 // the passphrase. There is sufficient entropy to cover this... 245 backupDev, err := libkb.NewPaperDevice(e.arg.Passphrase.Prefix()) 246 if err != nil { 247 return err 248 } 249 e.deviceID = backupDev.ID 250 251 // create lks halves for this device. Note that they aren't used for 252 // local, encrypted storage of the paper keys, but just for recovery 253 // purposes. 254 m.Dump() 255 256 // Clear the passphrase stream if it's outdated, just in case some 257 // other device changed the passphrase. 258 if err := m.G().ActiveDevice.ClearPassphraseStreamCacheIfOutdated(m); err != nil { 259 return err 260 } 261 262 var ppgen libkb.PassphraseGeneration 263 var clientHalf libkb.LKSecClientHalf 264 if stream := m.PassphraseStream(); stream != nil { 265 m.Debug("Got cached passphrase stream") 266 clientHalf = stream.LksClientHalf() 267 ppgen = stream.Generation() 268 } else { 269 m.Debug("Got nil passphrase stream; going to secret store") 270 // stream was nil, so we must have loaded lks from the secret 271 // store. 272 clientHalf, ppgen, err = e.getClientHalfFromSecretStore(m) 273 switch err.(type) { 274 case nil: 275 case libkb.SecretStoreError: 276 // as a last resort try to prompt the user for their passphrase if 277 // the SecretUI is present 278 if m.UIs().HasUI(libkb.SecretUIKind) { 279 if pps, _, perr := libkb.GetPassphraseStreamViaPrompt(m); pps != nil { 280 clientHalf = pps.LksClientHalf() 281 ppgen = pps.Generation() 282 } else if perr != nil { 283 return perr 284 } else { 285 return err 286 } 287 } 288 default: 289 return err 290 } 291 } 292 293 backupLks := libkb.NewLKSecWithClientHalf(clientHalf, ppgen, e.arg.Me.GetUID()) 294 backupLks.SetServerHalf(libkb.NewLKSecServerHalfZeros()) 295 296 ctext, err := backupLks.EncryptClientHalfRecovery(e.encKey) 297 if err != nil { 298 return err 299 } 300 301 if err := libkb.PostDeviceLKS(m, backupDev.ID, keybase1.DeviceTypeV2_PAPER, backupLks.GetServerHalf(), backupLks.Generation(), ctext, e.encKey.GetKID()); err != nil { 302 return err 303 } 304 305 // push the paper signing key 306 sigDel := libkb.Delegator{ 307 NewKey: e.sigKey, 308 Expire: libkb.NaclEdDSAExpireIn, 309 Me: e.arg.Me, 310 Device: backupDev, 311 Contextified: libkb.NewContextified(e.G()), 312 } 313 if e.arg.IsEldest { 314 sigDel.DelegationType = libkb.DelegationTypeEldest 315 } else { 316 sigDel.DelegationType = libkb.DelegationTypeSibkey 317 sigDel.ExistingKey = e.arg.SigningKey 318 } 319 320 // push the paper encryption key 321 sigEnc := libkb.Delegator{ 322 NewKey: e.encKey, 323 DelegationType: libkb.DelegationTypeSubkey, 324 Expire: libkb.NaclDHExpireIn, 325 ExistingKey: e.sigKey, 326 Me: e.arg.Me, 327 Device: backupDev, 328 Contextified: libkb.NewContextified(e.G()), 329 } 330 331 pukBoxes, err := e.makePerUserKeyBoxes(m) 332 if err != nil { 333 return err 334 } 335 336 m.Debug("PaperKeyGen#push running delegators") 337 return libkb.DelegatorAggregator(m, []libkb.Delegator{sigDel, sigEnc}, nil, pukBoxes, nil, nil) 338 } 339 340 func (e *PaperKeyGen) makePerUserKeyBoxes(m libkb.MetaContext) ([]keybase1.PerUserKeyBox, error) { 341 m.Debug("PaperKeyGen#makePerUserKeyBoxes") 342 343 var pukBoxes []keybase1.PerUserKeyBox 344 pukring, err := e.getPerUserKeyring(m) 345 if err != nil { 346 return nil, err 347 } 348 if pukring.HasAnyKeys() { 349 if e.arg.EncryptionKey.IsNil() { 350 return nil, errors.New("missing encryption key for creating paper key") 351 } 352 pukBox, err := pukring.PrepareBoxForNewDevice(m, 353 e.encKey, // receiver key: new paper key enc 354 e.arg.EncryptionKey) // sender key: this device enc 355 if err != nil { 356 return nil, err 357 } 358 pukBoxes = append(pukBoxes, pukBox) 359 } 360 m.Debug("PaperKeyGen#makePerUserKeyBoxes -> %v", len(pukBoxes)) 361 return pukBoxes, nil 362 } 363 364 func (e *PaperKeyGen) getPerUserKeyring(mctx libkb.MetaContext) (ret *libkb.PerUserKeyring, err error) { 365 ret = e.arg.PerUserKeyring 366 if ret != nil { 367 return 368 } 369 ret, err = e.G().GetPerUserKeyring(mctx.Ctx()) 370 return 371 }