github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/passphrase_stream.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 libkb 5 6 import ( 7 "fmt" 8 "runtime/debug" 9 10 keybase1 "github.com/keybase/client/go/protocol/keybase1" 11 triplesec "github.com/keybase/go-triplesec" 12 ) 13 14 func NewSecureTriplesec(passphrase []byte, salt []byte) (Triplesec, error) { 15 return triplesec.NewCipher(passphrase, salt, ClientTriplesecVersion) 16 } 17 18 func StretchPassphrase(g *GlobalContext, passphrase string, salt []byte) (tsec Triplesec, pps *PassphraseStream, err error) { 19 if salt == nil { 20 err = fmt.Errorf("no salt provided to StretchPassphrase") 21 return nil, nil, err 22 } 23 var tmp []byte 24 var fn func(pw []byte, salt []byte) (Triplesec, error) 25 26 // free memory on mobile before we do this to reduce chance that we get killed because of the 27 // large scrypt allocation coming 28 if g != nil && g.IsMobileAppType() { 29 debug.FreeOSMemory() 30 } 31 if g == nil { 32 fn = NewSecureTriplesec 33 } else { 34 fn = g.NewTriplesec 35 } 36 37 tsec, err = fn([]byte(passphrase), salt) 38 if err != nil { 39 return nil, nil, err 40 } 41 _, tmp, err = tsec.DeriveKey(extraLen) 42 if err != nil { 43 return nil, nil, err 44 } 45 pps = NewPassphraseStream(tmp) 46 return tsec, pps, nil 47 } 48 49 const ( 50 pwhIndex = 0 51 pwhLen = 32 52 eddsaIndex = pwhIndex + pwhLen 53 eddsaLen = 32 54 dhIndex = eddsaIndex + eddsaLen 55 dhLen = 32 56 lksIndex = dhIndex + dhLen 57 lksLen = LKSecLen // == 32 58 extraLen = pwhLen + eddsaLen + dhLen + lksLen 59 ) 60 61 type PassphraseStream struct { 62 stream []byte 63 gen PassphraseGeneration 64 } 65 66 func NewPassphraseStream(s []byte) *PassphraseStream { 67 return &PassphraseStream{ 68 stream: s, 69 gen: PassphraseGeneration(0), 70 } 71 } 72 73 // NewPassphraseStreamLKSecOnly creates a PassphraseStream only with the lks bytes 74 // (stream[lksIndex:]). The rest of the stream is zeros. 75 // This is used to create a passphrase stream from the information in the 76 // secret store, which only contains the lksec portion of the stream. 77 func NewPassphraseStreamLKSecOnly(s *LKSec) (*PassphraseStream, error) { 78 79 clientHalf, err := s.ComputeClientHalf() 80 if err != nil { 81 return nil, err 82 } 83 stream := make([]byte, extraLen) 84 copy(stream[lksIndex:], clientHalf.Bytes()) 85 ps := &PassphraseStream{ 86 stream: stream, 87 gen: s.Generation(), 88 } 89 return ps, nil 90 } 91 92 func (ps *PassphraseStream) SetGeneration(gen PassphraseGeneration) { 93 ps.gen = gen 94 } 95 96 type passphraseStreamPWHash [pwhLen]byte 97 type passphraseSteramEdDSASeed [eddsaLen]byte 98 99 func newPassphraseStreamFromPwhAndEddsa(pwhash passphraseStreamPWHash, eddsa passphraseSteramEdDSASeed) *PassphraseStream { 100 stream := make([]byte, extraLen) 101 copy(stream[pwhIndex:eddsaIndex], pwhash[:]) 102 copy(stream[eddsaIndex:dhIndex], eddsa[:]) 103 ps := &PassphraseStream{ 104 stream: stream, 105 gen: PassphraseGeneration(0), 106 } 107 return ps 108 } 109 110 func (ps PassphraseStream) PWHash() []byte { 111 return ps.stream[pwhIndex:eddsaIndex] 112 } 113 114 func (ps PassphraseStream) EdDSASeed() []byte { 115 return ps.stream[eddsaIndex:dhIndex] 116 } 117 118 func (ps PassphraseStream) DHSeed() []byte { 119 return ps.stream[dhIndex:lksIndex] 120 } 121 122 func (ps PassphraseStream) LksClientHalf() LKSecClientHalf { 123 ret, _ := NewLKSecClientHalfFromBytes(ps.stream[lksIndex:]) 124 return ret 125 } 126 127 func (ps PassphraseStream) ToLKSec(uid keybase1.UID) (*LKSec, error) { 128 ch, err := NewLKSecClientHalfFromBytes(ps.stream[lksIndex:]) 129 if err != nil { 130 return nil, err 131 } 132 return &LKSec{ 133 clientHalf: ch, 134 ppGen: ps.Generation(), 135 uid: uid, 136 }, nil 137 } 138 139 func (ps PassphraseStream) PDPKA5KID() (keybase1.KID, error) { 140 return seedToPDPKAKID(ps.EdDSASeed()) 141 } 142 143 func (ps PassphraseStream) String() string { 144 return fmt.Sprintf("pwh: %x\nEdDSA: %x\nDH: %x\nlks: %x", 145 ps.PWHash(), ps.EdDSASeed(), ps.DHSeed(), ps.LksClientHalf().Bytes()) 146 } 147 148 // Generation returns the generation of this passphrase stream. 149 // It is >=0 for valid generation #. If 0, then we assume the 150 // passphrase has never been reset. 151 func (ps PassphraseStream) Generation() PassphraseGeneration { 152 return ps.gen 153 } 154 155 // Clone a passphrase stream and return a copy. 156 func (ps *PassphraseStream) Clone() *PassphraseStream { 157 if ps == nil { 158 return nil 159 } 160 arr := make([]byte, len(ps.stream)) 161 copy(arr, ps.stream) 162 return &PassphraseStream{ 163 stream: arr, 164 gen: ps.gen, 165 } 166 } 167 168 func (ps PassphraseStream) Export() keybase1.PassphraseStream { 169 return keybase1.PassphraseStream{ 170 PassphraseStream: ps.stream, 171 Generation: int(ps.gen), 172 } 173 } 174 175 func (ps PassphraseStream) SyncAndCheckIfOutdated(mctx MetaContext) (bool, error) { 176 ss, err := mctx.SyncSecrets() 177 if err != nil { 178 return false, err 179 } 180 181 key, err := ss.FindDevice(mctx.G().Env.GetDeviceID()) 182 if err != nil { 183 return false, err 184 } 185 186 return key.PPGen > ps.Generation(), nil 187 }