github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/passphrase_stream_store.go (about) 1 // Copyright 2019 Keybase, Inc. All rights reserved. Use of 2 // this source code is governed by the included BSD license. 3 4 package libkb 5 6 // Code in this file drives a temporary storage for PWHash and EdDSA parts of 7 // passphrase stream. If signup is done with GenerateRandomPassphrase=true and 8 // it fails, but after SignupJoin has already succeeded (so account has been 9 // created, but it has no sigchain or devices), we store PWHash and EdDSA parts 10 // of passphrase stream using additional two secret store entries. Each part is 11 // 32-bytes so they fit using existing secret store code: we pretend these are 12 // LKSecFullSecret. 13 14 // This partial passphrase stream is then used during login to let the user in 15 // and continue signup process and provision their first device. Normally they 16 // would be able to do that by entering their password, but since it was a 17 // GenerateRandomPassphrase (or NOPW) signup, they don't know it. Both EdDSA 18 // and PWHash entries are then cleared after provisioning succeeds. 19 20 import ( 21 "fmt" 22 "strings" 23 24 "github.com/keybase/client/go/protocol/keybase1" 25 ) 26 27 // pwhStoreIdentifier is the suffix used for secret store identifier. 28 type pwhStoreIdentifier string 29 30 const ( 31 ssEddsaSuffix pwhStoreIdentifier = "tmp_eddsa" 32 ssPwhashSuffix pwhStoreIdentifier = "tmp_pwhash" 33 ) 34 35 func formatPPSSecretStoreIdentifier(username NormalizedUsername, typ pwhStoreIdentifier) NormalizedUsername { 36 return NormalizedUsername(fmt.Sprintf("%s.%s", username, typ)) 37 } 38 39 func isPPSSecretStore(identifier string) bool { 40 return strings.HasSuffix(identifier, string(ssEddsaSuffix)) || 41 strings.HasSuffix(identifier, string(ssPwhashSuffix)) 42 } 43 44 func RetrievePwhashEddsaPassphraseStream(mctx MetaContext, username NormalizedUsername, uid keybase1.UID) (ret *PassphraseStream, err error) { 45 defer mctx.Trace(fmt.Sprintf("RetrievePwhashEddsaPassphraseStream(%q,%q)", username, uid), 46 &err)() 47 48 ss := mctx.G().SecretStore() 49 50 var pwHash passphraseStreamPWHash 51 pwHashSecret, err := ss.RetrieveSecret(mctx, formatPPSSecretStoreIdentifier(username, ssPwhashSuffix)) 52 if err != nil { 53 return nil, err 54 } 55 copy(pwHash[:], pwHashSecret.Bytes()) 56 57 var eddsaSeed passphraseSteramEdDSASeed 58 edDSASecret, err := ss.RetrieveSecret(mctx, formatPPSSecretStoreIdentifier(username, ssEddsaSuffix)) 59 if err != nil { 60 return nil, err 61 } 62 copy(eddsaSeed[:], edDSASecret.Bytes()) 63 64 pps := newPassphraseStreamFromPwhAndEddsa(pwHash, eddsaSeed) 65 return pps, nil 66 } 67 68 func StorePwhashEddsaPassphraseStream(mctx MetaContext, username NormalizedUsername, pps *PassphraseStream) (err error) { 69 defer mctx.Trace(fmt.Sprintf("StorePwhashEddsaPassphraseStream(%q)", username), 70 &err)() 71 72 ss := mctx.G().SecretStore() 73 74 var secret LKSecFullSecret 75 var id NormalizedUsername 76 77 prevOptions := ss.GetOptions(mctx) 78 ss.SetOptions(mctx, &SecretStoreOptions{RandomPw: true}) 79 // Restore secret store options after we are done here. 80 defer ss.SetOptions(mctx, prevOptions) 81 82 defer func() { 83 if err != nil { 84 // Never store partial secret. 85 mctx.Debug("Clearing partial secret after unsuccessful store, error was: %s", err) 86 clrErr := ClearPwhashEddsaPassphraseStream(mctx, username) 87 if clrErr != nil { 88 mctx.Debug("Failed to clear: %v", clrErr) 89 } 90 } 91 }() 92 93 secret, err = newLKSecFullSecretFromBytes(pps.EdDSASeed()) 94 if err != nil { 95 return err 96 } 97 id = formatPPSSecretStoreIdentifier(username, ssEddsaSuffix) 98 if err := ss.StoreSecret(mctx, id, secret); err != nil { 99 return err 100 } 101 102 secret, err = newLKSecFullSecretFromBytes(pps.PWHash()) 103 if err != nil { 104 return err 105 } 106 id = formatPPSSecretStoreIdentifier(username, ssPwhashSuffix) 107 if err := ss.StoreSecret(mctx, id, secret); err != nil { 108 return err 109 } 110 111 return nil 112 } 113 114 func ClearPwhashEddsaPassphraseStream(mctx MetaContext, username NormalizedUsername) error { 115 ss := mctx.G().SecretStore() 116 117 prevOptions := ss.GetOptions(mctx) 118 ss.SetOptions(mctx, &SecretStoreOptions{RandomPw: true}) 119 // Restore secret store options after we are done here. 120 defer ss.SetOptions(mctx, prevOptions) 121 122 err1 := ss.ClearSecret(mctx, formatPPSSecretStoreIdentifier(username, ssEddsaSuffix)) 123 err2 := ss.ClearSecret(mctx, formatPPSSecretStoreIdentifier(username, ssPwhashSuffix)) 124 return CombineErrors(err1, err2) 125 }