github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/libkb/lksec.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 "crypto/hmac" 8 "crypto/rand" 9 "crypto/sha256" 10 "encoding/hex" 11 "errors" 12 "fmt" 13 "strings" 14 15 keybase1 "github.com/keybase/client/go/protocol/keybase1" 16 "golang.org/x/crypto/nacl/secretbox" 17 ) 18 19 const LKSecVersion = 100 20 const LKSecLen = 32 21 22 type LKSecClientHalf struct { 23 c *[LKSecLen]byte 24 } 25 26 func (c LKSecClientHalf) IsNil() bool { 27 return c.c == nil 28 } 29 30 func (c LKSecClientHalf) Bytes() []byte { 31 if c.c == nil { 32 return nil 33 } 34 return c.c[:] 35 } 36 37 type LKSecServerHalf struct { 38 s *[LKSecLen]byte 39 } 40 41 func (s LKSecServerHalf) IsNil() bool { 42 return s.s == nil 43 } 44 45 func (s LKSecServerHalf) Bytes() []byte { 46 if s.s == nil { 47 return nil 48 } 49 return s.s[:] 50 } 51 52 type LKSecFullSecret struct { 53 f *[LKSecLen]byte 54 } 55 56 type LKSecMask struct { 57 m *[LKSecLen]byte 58 } 59 60 func (f LKSecFullSecret) IsNil() bool { 61 return f.f == nil 62 } 63 64 func (f LKSecFullSecret) Bytes() []byte { 65 if f.f == nil { 66 return nil 67 } 68 return f.f[:] 69 } 70 71 func NewLKSecServerHalfFromHex(s string) (ret LKSecServerHalf, err error) { 72 var b []byte 73 b, err = hex.DecodeString(s) 74 if err != nil { 75 return ret, err 76 } 77 if len(b) != LKSecLen { 78 err = fmt.Errorf("Wrong LKSec server length: %d != %d", len(b), LKSecLen) 79 return ret, err 80 } 81 var v [LKSecLen]byte 82 copy(v[:], b) 83 ret = LKSecServerHalf{s: &v} 84 return ret, nil 85 } 86 87 func newLKSecFullSecretFromBytes(b []byte) (ret LKSecFullSecret, err error) { 88 if len(b) != LKSecLen { 89 err = fmt.Errorf("Wrong LKSecFullSecret len: %d != %d", len(b), LKSecLen) 90 return ret, err 91 } 92 var v [LKSecLen]byte 93 copy(v[:], b) 94 ret = LKSecFullSecret{f: &v} 95 return ret, nil 96 } 97 98 func NewLKSecClientHalfFromBytes(b []byte) (ret LKSecClientHalf, err error) { 99 if len(b) != LKSecLen { 100 err = fmt.Errorf("Wrong LKSecClientHalf len: %d != %d", len(b), LKSecLen) 101 return ret, err 102 } 103 var v [LKSecLen]byte 104 copy(v[:], b) 105 ret = LKSecClientHalf{c: &v} 106 return ret, nil 107 } 108 109 func (f LKSecFullSecret) Equal(f2 LKSecFullSecret) bool { 110 if f.IsNil() { 111 return false 112 } 113 if f2.IsNil() { 114 return false 115 } 116 return hmac.Equal(f.f[:], f2.f[:]) 117 } 118 119 func (c LKSecClientHalf) Equal(c2 LKSecClientHalf) bool { 120 if c.IsNil() { 121 return false 122 } 123 if c2.IsNil() { 124 return false 125 } 126 return hmac.Equal(c.c[:], c2.c[:]) 127 } 128 129 func (s LKSecServerHalf) EncodeToHex() string { 130 if s.IsNil() { 131 return "" 132 } 133 return hex.EncodeToString(s.s[:]) 134 } 135 136 func (m LKSecMask) IsNil() bool { 137 return m.m == nil 138 } 139 140 func (m LKSecMask) EncodeToHex() string { 141 if m.IsNil() { 142 return "" 143 } 144 return hex.EncodeToString(m.m[:]) 145 } 146 147 func NewLKSecServerHalfZeros() LKSecServerHalf { 148 var z [LKSecLen]byte 149 return LKSecServerHalf{s: &z} 150 } 151 152 type LKSec struct { 153 serverHalf LKSecServerHalf 154 clientHalf LKSecClientHalf 155 secret LKSecFullSecret 156 ppGen PassphraseGeneration 157 uid keybase1.UID 158 deviceID keybase1.DeviceID 159 } 160 161 func xorBytes(x *[LKSecLen]byte, y *[LKSecLen]byte) *[LKSecLen]byte { 162 var ret [LKSecLen]byte 163 for i := 0; i < LKSecLen; i++ { 164 ret[i] = x[i] ^ y[i] 165 } 166 return &ret 167 } 168 169 func (s LKSecServerHalf) ComputeFullSecret(c LKSecClientHalf) LKSecFullSecret { 170 return LKSecFullSecret{f: xorBytes(s.s, c.c)} 171 } 172 173 func (s LKSecServerHalf) ComputeClientHalf(f LKSecFullSecret) LKSecClientHalf { 174 return LKSecClientHalf{c: xorBytes(s.s, f.f)} 175 } 176 177 func (f LKSecFullSecret) bug3964Remask(s LKSecServerHalf) LKSecFullSecret { 178 return LKSecFullSecret{f: xorBytes(s.s, f.f)} 179 } 180 181 func (c LKSecClientHalf) ComputeMask(c2 LKSecClientHalf) LKSecMask { 182 if c.IsNil() || c2.IsNil() { 183 return LKSecMask{} 184 } 185 return LKSecMask{m: xorBytes(c.c, c2.c)} 186 } 187 188 func NewLKSec(pps *PassphraseStream, uid keybase1.UID) *LKSec { 189 return NewLKSecWithDeviceID(pps, uid, keybase1.DeviceID("")) 190 } 191 192 func NewLKSecWithDeviceID(pps *PassphraseStream, uid keybase1.UID, deviceID keybase1.DeviceID) *LKSec { 193 res := &LKSec{ 194 uid: uid, 195 deviceID: deviceID, 196 } 197 198 if pps != nil { 199 res.clientHalf = pps.LksClientHalf() 200 res.ppGen = pps.Generation() 201 } 202 return res 203 } 204 205 func NewLKSecWithClientHalf(clientHalf LKSecClientHalf, ppgen PassphraseGeneration, uid keybase1.UID) *LKSec { 206 return &LKSec{ 207 clientHalf: clientHalf, 208 ppGen: ppgen, 209 uid: uid, 210 } 211 } 212 213 func NewLKSecWithFullSecret(secret LKSecFullSecret, uid keybase1.UID) *LKSec { 214 return &LKSec{ 215 secret: secret, 216 ppGen: PassphraseGeneration(-1), 217 uid: uid, 218 } 219 } 220 221 func (s *LKSec) CorruptedFullSecretForBug3964Testing(srv LKSecServerHalf) LKSecFullSecret { 222 return s.FullSecret().bug3964Remask(srv) 223 } 224 225 func (s *LKSec) SetUID(u keybase1.UID) { 226 s.uid = u 227 } 228 229 func (s *LKSec) SetClientHalf(b LKSecClientHalf) { 230 s.clientHalf = b 231 } 232 233 func (s *LKSec) SetServerHalf(b LKSecServerHalf) { 234 s.serverHalf = b 235 } 236 237 // Generation returns the passphrase generation that this local key security 238 // object is derived from. 239 func (s LKSec) Generation() PassphraseGeneration { 240 return s.ppGen 241 } 242 243 func (s *LKSec) GenerateServerHalf() error { 244 if s.clientHalf.IsNil() { 245 return errors.New("Can't generate server half without a client half") 246 } 247 if !s.serverHalf.IsNil() { 248 return nil 249 } 250 var v [LKSecLen]byte 251 var n int 252 var err error 253 if n, err = rand.Read(v[:]); err != nil { 254 return err 255 } 256 if n != LKSecLen { 257 return fmt.Errorf("short random read; wanted %d bytes but only got %d", LKSecLen, n) 258 } 259 s.serverHalf = LKSecServerHalf{s: &v} 260 return nil 261 } 262 263 func (s *LKSec) GetServerHalf() LKSecServerHalf { 264 return s.serverHalf 265 } 266 267 func (s *LKSec) Load(m MetaContext) (err error) { 268 defer m.Trace("LKSec::Load()", &err)() 269 270 if !s.secret.IsNil() { 271 m.Debug("| Short-circuit; we already know the full secret") 272 return nil 273 } 274 275 if s.clientHalf.IsNil() { 276 err = fmt.Errorf("client half not set") 277 return err 278 } 279 280 if err = s.LoadServerHalf(m); err != nil { 281 return err 282 } 283 284 s.SetFullSecret(m) 285 return nil 286 } 287 288 func (s *LKSec) SetFullSecret(m MetaContext) { 289 m.Debug("| Making XOR'ed secret key for Local Key Security (LKS)") 290 s.secret = s.serverHalf.ComputeFullSecret(s.clientHalf) 291 } 292 293 func (s *LKSec) LoadServerHalf(m MetaContext) (err error) { 294 defer m.Trace("LKSec::LoadServerHalf()", &err)() 295 296 if !s.serverHalf.IsNil() { 297 m.Debug("| short-circuit: already have serverHalf") 298 return nil 299 } 300 _, err = s.LoadServerDetails(m) 301 return err 302 } 303 304 func (s *LKSec) LoadServerDetails(m MetaContext) (ret DeviceKeyMap, err error) { 305 defer m.Trace("LKSec#LoadServerDetails", &err)() 306 307 devid := s.deviceID 308 if devid.IsNil() { 309 devid = m.G().Env.GetDeviceIDForUID(s.uid) 310 } 311 if devid.IsNil() { 312 return ret, fmt.Errorf("lksec load: no device id set, thus can't fetch server half") 313 } 314 315 if ret, err = s.apiServerHalf(m, devid); err != nil { 316 m.Debug("apiServerHalf(%s) error: %s", devid, err) 317 return ret, err 318 } 319 if s.serverHalf.IsNil() { 320 return ret, fmt.Errorf("after apiServerHalf(%s), serverHalf still empty", devid) 321 } 322 323 return ret, nil 324 } 325 326 func (s *LKSec) GetSecret(m MetaContext) (secret LKSecFullSecret, err error) { 327 defer m.Trace("LKsec:GetSecret()", &err)() 328 if err = s.Load(m); err != nil { 329 return secret, err 330 } 331 secret = s.secret 332 return secret, nil 333 } 334 335 func (s *LKSec) Encrypt(m MetaContext, src []byte) (res []byte, err error) { 336 defer m.Trace("LKsec:Encrypt()", &err)() 337 if err = s.Load(m); err != nil { 338 return nil, err 339 } 340 var nonce []byte 341 nonce, err = RandBytes(24) 342 if err != nil { 343 return nil, err 344 } 345 var fnonce [24]byte 346 copy(fnonce[:], nonce) 347 box := secretbox.Seal(nil, src, &fnonce, s.secret.f) 348 349 ret := nonce 350 ret = append(ret, box...) 351 return ret, nil 352 } 353 354 func (s *LKSec) attemptBug3964Recovery(m MetaContext, data []byte, nonce *[24]byte) (res []byte, gen PassphraseGeneration, erroneousMask LKSecServerHalf, err error) { 355 ss, err := s.loadSecretSyncer(m) 356 if err != nil { 357 return nil, 0, LKSecServerHalf{}, err 358 } 359 devices := ss.AllDevices() 360 res, serverHalf, err := s.tryAllDevicesForBug3964Recovery(m, devices, data, nonce) 361 return res, s.ppGen, serverHalf, err 362 } 363 364 func (s *LKSec) tryAllDevicesForBug3964Recovery(m MetaContext, devices DeviceKeyMap, data []byte, nonce *[24]byte) (res []byte, erroneousMask LKSecServerHalf, err error) { 365 366 // This logline is asserted in testing in bug_3964_repairman_test 367 defer m.Trace("LKSec#tryAllDevicesForBug3964Recovery()", &err)() 368 369 for devid, dev := range devices { 370 371 // This logline is asserted in testing in bug_3964_repairman_test 372 m.Debug("| Trying Bug 3964 Recovery w/ device %q {id: %s, lks: %s...}", dev.Description, devid, dev.LksServerHalf[0:8]) 373 374 serverHalf, err := dev.ToLKSec() 375 if err != nil { 376 m.Debug("| Failed with error: %s\n", err) 377 continue 378 } 379 fs := s.secret.bug3964Remask(serverHalf) 380 res, ok := secretbox.Open(nil, data, nonce, fs.f) 381 382 if ok { 383 // This logline is asserted in testing in bug_3964_repairman_test 384 m.Debug("| Success") 385 return res, serverHalf, nil 386 } 387 } 388 389 err = PassphraseError{"failed to open secretbox"} 390 return nil, LKSecServerHalf{}, err 391 } 392 393 func splitCiphertext(src []byte) ([]byte, *[24]byte) { 394 var nonce [24]byte 395 copy(nonce[:], src[0:24]) 396 data := src[24:] 397 return data, &nonce 398 } 399 400 func (s *LKSec) Decrypt(m MetaContext, src []byte) (res []byte, gen PassphraseGeneration, erroneousMask LKSecServerHalf, err error) { 401 // This logline is asserted in testing in bug_3964_repairman_test 402 defer m.Trace("LKSec#Decrypt()", &err)() 403 404 if err = s.Load(m); err != nil { 405 return nil, 0, LKSecServerHalf{}, err 406 } 407 var ok bool 408 data, nonce := splitCiphertext(src) 409 res, ok = secretbox.Open(nil, data, nonce, s.secret.f) 410 if !ok { 411 secretHash := sha256.New() 412 _, _ = secretHash.Write((*s.secret.f)[:]) 413 m.Debug("secretbox.Open failed: used a secret of length %d", len(s.secret.f)) 414 m.Debug("secretbox.Open failed: used secret of hash prefix %x and nonce prefix %x", 415 secretHash.Sum(nil)[:4], nonce[:4]) 416 m.Debug("secretbox.Open failed: attempting recovery") 417 return s.attemptBug3964Recovery(m, data, nonce) 418 } 419 420 return res, s.ppGen, LKSecServerHalf{}, nil 421 } 422 423 func (s *LKSec) decryptForBug3964Repair(m MetaContext, src []byte, dkm DeviceKeyMap) (res []byte, erroneousMask LKSecServerHalf, err error) { 424 defer m.Trace("LKSec#decryptForBug3964Repair()", &err)() 425 data, nonce := splitCiphertext(src) 426 res, ok := secretbox.Open(nil, data, nonce, s.secret.f) 427 if ok { 428 m.Debug("| Succeeded with intended mask") 429 return res, LKSecServerHalf{}, nil 430 } 431 return s.tryAllDevicesForBug3964Recovery(m, dkm, data, nonce) 432 } 433 434 func (s *LKSec) ComputeClientHalf() (ret LKSecClientHalf, err error) { 435 if !s.clientHalf.IsNil() { 436 return s.clientHalf, nil 437 } 438 if s.serverHalf.IsNil() { 439 return ret, errors.New("LKSec: tried to compute client half, but no server half loaded") 440 } 441 if s.secret.IsNil() { 442 return ret, errors.New("LKSec: tried to compute client half, but no full secret loaded") 443 } 444 return s.serverHalf.ComputeClientHalf(s.secret), nil 445 } 446 447 func (s *LKSec) loadSecretSyncer(m MetaContext) (ss *SecretSyncer, err error) { 448 return m.SyncSecrets() 449 } 450 451 func (s *LKSec) apiServerHalf(m MetaContext, devid keybase1.DeviceID) (dkm DeviceKeyMap, err error) { 452 var dev DeviceKey 453 ss, err := s.loadSecretSyncer(m) 454 if err != nil { 455 return dkm, err 456 } 457 dev, err = ss.FindDevice(devid) 458 if err != nil { 459 return dkm, err 460 } 461 462 s.serverHalf, err = dev.ToLKSec() 463 if err != nil { 464 return dkm, err 465 } 466 s.ppGen = dev.PPGen 467 return ss.AllDevices(), nil 468 } 469 470 // NewLKSForEncrypt gets a verified passphrase stream, and returns 471 // an LKS that works for encryption. 472 func NewLKSecForEncrypt(m MetaContext, ui SecretUI, uid keybase1.UID) (ret *LKSec, err error) { 473 m = m.WithUIs(UIs{SecretUI: ui}) 474 pps, err := GetPassphraseStreamStored(m) 475 if err != nil { 476 return nil, err 477 } 478 ret = NewLKSec(pps, uid) 479 return ret, nil 480 } 481 482 // EncryptClientHalfRecovery takes the client half of the LKS secret 483 // and encrypts it for the given key. This is for recovery of passphrases 484 // on device recovery operations. 485 func (s *LKSec) EncryptClientHalfRecovery(key GenericKey) (string, error) { 486 if s.clientHalf.IsNil() { 487 return "", errors.New("Nil LKS Client Half") 488 } 489 return key.EncryptToString(s.clientHalf.Bytes(), nil) 490 } 491 492 // ToSKB exports a generic key with the given LKSec to a SecretKeyBundle, 493 // performing all necessary encryption. 494 func (s *LKSec) ToSKB(m MetaContext, key GenericKey) (ret *SKB, err error) { 495 defer m.Trace("LKSec#ToSKB", &err)() 496 if s == nil { 497 return nil, errors.New("nil lks") 498 } 499 ret = NewSKBWithGlobalContext(m.G()) 500 501 var publicKey RawPublicKey 502 var privateKey RawPrivateKey 503 504 publicKey, privateKey, err = key.ExportPublicAndPrivate() 505 if err != nil { 506 return nil, err 507 } 508 509 ret.Priv.Data, err = s.Encrypt(m, []byte(privateKey)) 510 if err != nil { 511 return nil, err 512 } 513 ret.Priv.Encryption = LKSecVersion 514 ret.Priv.PassphraseGeneration = int(s.Generation()) 515 ret.Pub = []byte(publicKey) 516 ret.Type = key.GetAlgoType() 517 ret.uid = s.uid 518 return ret, nil 519 } 520 521 func WriteLksSKBToKeyring(m MetaContext, k GenericKey, lks *LKSec) (skb *SKB, err error) { 522 defer m.Trace("WriteLksSKBToKeyring", &err)() 523 skb, err = lks.ToSKB(m, k) 524 if err != nil { 525 return nil, fmt.Errorf("k.ToLksSKB() error: %s", err) 526 } 527 if err = skbPushAndSave(m, skb); err != nil { 528 return nil, err 529 } 530 return skb, nil 531 } 532 533 func (s *LKSec) FullSecret() LKSecFullSecret { 534 if !s.secret.IsNil() { 535 return s.secret 536 } 537 if s.serverHalf.IsNil() || s.clientHalf.IsNil() { 538 return LKSecFullSecret{} 539 } 540 return s.serverHalf.ComputeFullSecret(s.clientHalf) 541 } 542 543 func (s LKSec) ServerHalf() LKSecServerHalf { 544 return s.serverHalf 545 } 546 547 func (s LKSec) ClientHalf() LKSecClientHalf { 548 return s.clientHalf 549 } 550 551 type LKSecServerHalfSet struct { 552 index map[[LKSecLen]byte]bool 553 } 554 555 func NewLKSecServerHalfSet() *LKSecServerHalfSet { 556 return &LKSecServerHalfSet{ 557 index: make(map[[LKSecLen]byte]bool), 558 } 559 } 560 561 func (l *LKSecServerHalfSet) Add(s LKSecServerHalf) { 562 if !s.IsNil() { 563 l.index[*s.s] = true 564 } 565 } 566 567 func (l *LKSecServerHalfSet) EncodeToHexList() string { 568 var s []string 569 for k := range l.index { 570 s = append(s, hex.EncodeToString(k[:])) 571 } 572 return strings.Join(s, ",") 573 }