github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/kbfs/kbfsmd/key_bundle_v3.go (about) 1 // Copyright 2016 Keybase Inc. All rights reserved. 2 // Use of this source code is governed by a BSD 3 // license that can be found in the LICENSE file. 4 5 package kbfsmd 6 7 import ( 8 "encoding" 9 "fmt" 10 "reflect" 11 12 "github.com/keybase/client/go/kbfs/cache" 13 "github.com/keybase/client/go/kbfs/kbfscodec" 14 "github.com/keybase/client/go/kbfs/kbfscrypto" 15 "github.com/keybase/client/go/kbfs/kbfshash" 16 "github.com/keybase/client/go/protocol/keybase1" 17 "github.com/keybase/go-codec/codec" 18 "github.com/pkg/errors" 19 ) 20 21 // A lot of this code is duplicated from key_bundle_v3.go, except with 22 // DeviceKeyInfoMapV2 (keyed by keybase1.KID) replaced with 23 // DeviceKeyInfoMapV3 (keyed by kbfscrypto.CryptPublicKey). 24 25 // DeviceKeyInfoMapV3 is a map from a user devices (identified by the 26 // corresponding device CryptPublicKey) to the TLF's symmetric secret 27 // key information. 28 type DeviceKeyInfoMapV3 map[kbfscrypto.CryptPublicKey]TLFCryptKeyInfo 29 30 // static sizes in DeviceKeyInfoMapV3 31 var ( 32 ssCryptPublicKey = int(reflect.TypeOf(kbfscrypto.CryptPublicKey{}).Size()) 33 ssTLFCryptKeyInfo = int(reflect.TypeOf(TLFCryptKeyInfo{}).Size()) 34 ) 35 36 // Size implements the cache.Measurable interface. 37 func (dkimV3 DeviceKeyInfoMapV3) Size() int { 38 // statically-sized part 39 mapSize := cache.StaticSizeOfMapWithSize( 40 ssCryptPublicKey, ssTLFCryptKeyInfo, len(dkimV3)) 41 42 // go through pointer type content 43 var contentSize int 44 for k, v := range dkimV3 { 45 contentSize += len(k.KID()) 46 contentSize += len(v.ServerHalfID.ID.String()) 47 48 // We are not using v.ClientHalf.encryptedData here since that would 49 // include the size of struct itself which is already counted in 50 // cache.StaticSizeOfMapWithSize. 51 contentSize += len(v.ClientHalf.EncryptedData) + 52 len(v.ClientHalf.Nonce) 53 } 54 55 return mapSize + contentSize 56 } 57 58 var _ cache.Measurable = DeviceKeyInfoMapV3{} 59 60 func (dkimV3 DeviceKeyInfoMapV3) fillInDeviceInfos( 61 uid keybase1.UID, tlfCryptKey kbfscrypto.TLFCryptKey, 62 ePrivKey kbfscrypto.TLFEphemeralPrivateKey, ePubIndex int, 63 updatedDeviceKeys DevicePublicKeys) ( 64 serverHalves DeviceKeyServerHalves, err error) { 65 serverHalves = make(DeviceKeyServerHalves, len(updatedDeviceKeys)) 66 // TODO: parallelize 67 for k := range updatedDeviceKeys { 68 // Skip existing entries, and only fill in new ones 69 if _, ok := dkimV3[k]; ok { 70 continue 71 } 72 73 clientInfo, serverHalf, err := splitTLFCryptKey( 74 uid, tlfCryptKey, ePrivKey, ePubIndex, k) 75 if err != nil { 76 return nil, err 77 } 78 79 dkimV3[k] = clientInfo 80 serverHalves[k] = serverHalf 81 } 82 83 return serverHalves, nil 84 } 85 86 func (dkimV3 DeviceKeyInfoMapV3) toPublicKeys() DevicePublicKeys { 87 publicKeys := make(DevicePublicKeys, len(dkimV3)) 88 for key := range dkimV3 { 89 publicKeys[key] = true 90 } 91 return publicKeys 92 } 93 94 // UserDeviceKeyInfoMapV3 maps a user's keybase UID to their 95 // DeviceKeyInfoMapV3. 96 type UserDeviceKeyInfoMapV3 map[keybase1.UID]DeviceKeyInfoMapV3 97 98 // Size implements the cache.Measurable interface. 99 func (udkimV3 UserDeviceKeyInfoMapV3) Size() int { 100 // statically-sized part 101 mapSize := cache.StaticSizeOfMapWithSize( 102 cache.PtrSize, cache.PtrSize, len(udkimV3)) 103 104 // go through pointer type content 105 var contentSize int 106 for k, v := range udkimV3 { 107 contentSize += len(k) + v.Size() 108 } 109 110 return mapSize + contentSize 111 } 112 113 var _ cache.Measurable = UserDeviceKeyInfoMapV3{} 114 115 // ToPublicKeys converts this object to a UserDevicePublicKeys object. 116 func (udkimV3 UserDeviceKeyInfoMapV3) ToPublicKeys() UserDevicePublicKeys { 117 publicKeys := make(UserDevicePublicKeys, len(udkimV3)) 118 for u, dkimV3 := range udkimV3 { 119 publicKeys[u] = dkimV3.toPublicKeys() 120 } 121 return publicKeys 122 } 123 124 func writerUDKIMV2ToV3(codec kbfscodec.Codec, udkimV2 UserDeviceKeyInfoMapV2, 125 ePubKeyCount int) ( 126 UserDeviceKeyInfoMapV3, error) { 127 udkimV3 := make(UserDeviceKeyInfoMapV3, len(udkimV2)) 128 for uid, dkimV2 := range udkimV2 { 129 dkimV3 := make(DeviceKeyInfoMapV3, len(dkimV2)) 130 for kid, info := range dkimV2 { 131 index := info.EPubKeyIndex 132 if index < 0 { 133 // TODO: Fix this; see KBFS-1719. 134 return nil, fmt.Errorf( 135 "Writer key with index %d for user=%s, kid=%s not handled yet", 136 index, uid, kid) 137 } 138 if index >= ePubKeyCount { 139 return nil, fmt.Errorf( 140 "Invalid writer key index %d for user=%s, kid=%s", 141 index, uid, kid) 142 } 143 144 var infoCopy TLFCryptKeyInfo 145 err := kbfscodec.Update(codec, &infoCopy, info) 146 if err != nil { 147 return nil, err 148 } 149 dkimV3[kbfscrypto.MakeCryptPublicKey(kid)] = infoCopy 150 } 151 udkimV3[uid] = dkimV3 152 } 153 return udkimV3, nil 154 } 155 156 // RemoveDevicesNotIn removes any info for any device that is not 157 // contained in the given map of users and devices. 158 func (udkimV3 UserDeviceKeyInfoMapV3) RemoveDevicesNotIn( 159 updatedUserKeys UserDevicePublicKeys) ServerHalfRemovalInfo { 160 removalInfo := make(ServerHalfRemovalInfo) 161 for uid, dkim := range udkimV3 { 162 userRemoved := false 163 deviceServerHalfIDs := make(DeviceServerHalfRemovalInfo) 164 if deviceKeys, ok := updatedUserKeys[uid]; ok { 165 for key, info := range dkim { 166 if !deviceKeys[key] { 167 delete(dkim, key) 168 deviceServerHalfIDs[key] = append( 169 deviceServerHalfIDs[key], 170 info.ServerHalfID) 171 } 172 } 173 174 if len(deviceServerHalfIDs) == 0 { 175 continue 176 } 177 } else { 178 // The user was completely removed, which 179 // shouldn't happen but might as well make it 180 // work just in case. 181 userRemoved = true 182 for key, info := range dkim { 183 deviceServerHalfIDs[key] = append( 184 deviceServerHalfIDs[key], 185 info.ServerHalfID) 186 } 187 188 delete(udkimV3, uid) 189 } 190 191 removalInfo[uid] = UserServerHalfRemovalInfo{ 192 UserRemoved: userRemoved, 193 DeviceServerHalfIDs: deviceServerHalfIDs, 194 } 195 } 196 197 return removalInfo 198 } 199 200 // FillInUserInfos fills in this map from the given info. 201 func (udkimV3 UserDeviceKeyInfoMapV3) FillInUserInfos( 202 newIndex int, updatedUserKeys UserDevicePublicKeys, 203 ePrivKey kbfscrypto.TLFEphemeralPrivateKey, 204 tlfCryptKey kbfscrypto.TLFCryptKey) ( 205 serverHalves UserDeviceKeyServerHalves, err error) { 206 serverHalves = make(UserDeviceKeyServerHalves, len(updatedUserKeys)) 207 for u, updatedDeviceKeys := range updatedUserKeys { 208 if _, ok := udkimV3[u]; !ok { 209 udkimV3[u] = DeviceKeyInfoMapV3{} 210 } 211 212 deviceServerHalves, err := udkimV3[u].fillInDeviceInfos( 213 u, tlfCryptKey, ePrivKey, newIndex, 214 updatedDeviceKeys) 215 if err != nil { 216 return nil, err 217 } 218 if len(deviceServerHalves) > 0 { 219 serverHalves[u] = deviceServerHalves 220 } 221 } 222 return serverHalves, nil 223 } 224 225 // All section references below are to https://keybase.io/docs/crypto/kbfs 226 // (version 1.8). 227 228 // TLFWriterKeyBundleV3 is a bundle of writer keys and historic 229 // symmetric encryption keys for a top-level folder. 230 type TLFWriterKeyBundleV3 struct { 231 // Maps from each user to their crypt key bundle for the current generation. 232 Keys UserDeviceKeyInfoMapV3 `codec:"wKeys"` 233 234 // M_f as described in § 4.1.1. 235 TLFPublicKey kbfscrypto.TLFPublicKey `codec:"pubKey"` 236 237 // M_e as described in § 4.1.1. Because devices can be added 238 // into the key generation after it is initially created (so 239 // those devices can get access to existing data), we track 240 // multiple ephemeral public keys; the one used by a 241 // particular device is specified by EPubKeyIndex in its 242 // TLFCryptoKeyInfo struct. 243 TLFEphemeralPublicKeys kbfscrypto.TLFEphemeralPublicKeys `codec:"ePubKey"` 244 245 // This is a time-ordered encrypted list of historic key generations. 246 // It is encrypted with the latest generation of the TLF crypt key. 247 EncryptedHistoricTLFCryptKeys kbfscrypto.EncryptedTLFCryptKeys `codec:"oldKeys"` 248 249 codec.UnknownFieldSetHandler 250 } 251 252 // DeserializeTLFWriterKeyBundleV3 deserializes a TLFWriterKeyBundleV3 253 // from the given path and returns it. 254 func DeserializeTLFWriterKeyBundleV3(codec kbfscodec.Codec, path string) ( 255 TLFWriterKeyBundleV3, error) { 256 var wkb TLFWriterKeyBundleV3 257 err := kbfscodec.DeserializeFromFile(codec, path, &wkb) 258 if err != nil { 259 return TLFWriterKeyBundleV3{}, err 260 } 261 if len(wkb.Keys) == 0 { 262 return TLFWriterKeyBundleV3{}, errors.New( 263 "Writer key bundle with no keys (DeserializeTLFWriterKeyBundleV3)") 264 } 265 return wkb, nil 266 } 267 268 // Size implements the cache.Measurable interface. 269 func (wkb TLFWriterKeyBundleV3) Size() (bytes int) { 270 bytes += cache.PtrSize + wkb.Keys.Size() // Keys 271 272 // TLFPublicKey is essentially a 32-byte array. 273 bytes += kbfscrypto.TLFPublicKey{}.Size() 274 275 // TLFEphemeralPublicKeys 276 bytes += wkb.TLFEphemeralPublicKeys.Size() 277 278 // EncryptedHistoricTLFCryptKeys 279 bytes += wkb.EncryptedHistoricTLFCryptKeys.Size() 280 281 // For codec.UnknownFieldSetHandler. It has a private map field which we 282 // can't inspect unless extending the codec package. Just assume it's empty 283 // for now. 284 bytes += cache.PtrSize 285 286 return bytes 287 } 288 289 var _ cache.Measurable = TLFWriterKeyBundleV3{} 290 291 // IsWriter returns true if the given user device is in the device set. 292 func (wkb TLFWriterKeyBundleV3) IsWriter(user keybase1.UID, deviceKey kbfscrypto.CryptPublicKey) bool { 293 _, ok := wkb.Keys[user][deviceKey] 294 return ok 295 } 296 297 // DeepCopy creates a deep copy of this key bundle. 298 func (wkb TLFWriterKeyBundleV3) DeepCopy(codec kbfscodec.Codec) ( 299 TLFWriterKeyBundleV3, error) { 300 if len(wkb.Keys) == 0 { 301 return TLFWriterKeyBundleV3{}, errors.New( 302 "Writer key bundle with no keys (DeepCopy)") 303 } 304 var wkbCopy TLFWriterKeyBundleV3 305 if err := kbfscodec.Update(codec, &wkbCopy, wkb); err != nil { 306 return TLFWriterKeyBundleV3{}, err 307 } 308 return wkbCopy, nil 309 } 310 311 // TLFWriterKeyBundleID is the hash of a serialized TLFWriterKeyBundle. 312 type TLFWriterKeyBundleID struct { 313 h kbfshash.Hash 314 } 315 316 var _ encoding.BinaryMarshaler = TLFWriterKeyBundleID{} 317 var _ encoding.BinaryUnmarshaler = (*TLFWriterKeyBundleID)(nil) 318 319 // TLFWriterKeyBundleIDFromBytes creates a new TLFWriterKeyBundleID from the given bytes. 320 // If the returned error is nil, the returned TLFWriterKeyBundleID is valid. 321 func TLFWriterKeyBundleIDFromBytes(data []byte) (TLFWriterKeyBundleID, error) { 322 h, err := kbfshash.HashFromBytes(data) 323 if err != nil { 324 return TLFWriterKeyBundleID{}, err 325 } 326 return TLFWriterKeyBundleID{h}, nil 327 } 328 329 // TLFWriterKeyBundleIDFromString creates a new TLFWriterKeyBundleID from the given string. 330 // If the returned error is nil, the returned TLFWriterKeyBundleID is valid. 331 func TLFWriterKeyBundleIDFromString(id string) (TLFWriterKeyBundleID, error) { 332 if len(id) == 0 { 333 return TLFWriterKeyBundleID{}, nil 334 } 335 h, err := kbfshash.HashFromString(id) 336 if err != nil { 337 return TLFWriterKeyBundleID{}, err 338 } 339 return TLFWriterKeyBundleID{h}, nil 340 } 341 342 // Bytes returns the bytes of the TLFWriterKeyBundleID. 343 func (h TLFWriterKeyBundleID) Bytes() []byte { 344 return h.h.Bytes() 345 } 346 347 // String returns the string form of the TLFWriterKeyBundleID. 348 func (h TLFWriterKeyBundleID) String() string { 349 return h.h.String() 350 } 351 352 // Size implements the cache.Measurable interface. 353 func (h TLFWriterKeyBundleID) Size() int { 354 return h.h.Size() 355 } 356 357 var _ cache.Measurable = TLFWriterKeyBundleID{} 358 359 // MarshalBinary implements the encoding.BinaryMarshaler interface for 360 // TLFWriterKeyBundleID. Returns an error if the TLFWriterKeyBundleID is invalid and not the 361 // zero TLFWriterKeyBundleID. 362 func (h TLFWriterKeyBundleID) MarshalBinary() (data []byte, err error) { 363 return h.h.MarshalBinary() 364 } 365 366 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 367 // for TLFWriterKeyBundleID. Returns an error if the given byte array is non-empty and 368 // the TLFWriterKeyBundleID is invalid. 369 func (h *TLFWriterKeyBundleID) UnmarshalBinary(data []byte) error { 370 return h.h.UnmarshalBinary(data) 371 } 372 373 // IsNil returns true if the ID is unset. 374 func (h TLFWriterKeyBundleID) IsNil() bool { 375 return h == TLFWriterKeyBundleID{} 376 } 377 378 // MakeTLFWriterKeyBundleID hashes a TLFWriterKeyBundleV3 to create an ID. 379 func MakeTLFWriterKeyBundleID(codec kbfscodec.Codec, wkb TLFWriterKeyBundleV3) ( 380 TLFWriterKeyBundleID, error) { 381 if len(wkb.Keys) == 0 { 382 return TLFWriterKeyBundleID{}, errors.New( 383 "Writer key bundle with no keys (MakeTLFWriterKeyBundleID)") 384 } 385 buf, err := codec.Encode(wkb) 386 if err != nil { 387 return TLFWriterKeyBundleID{}, err 388 } 389 h, err := kbfshash.DefaultHash(buf) 390 if err != nil { 391 return TLFWriterKeyBundleID{}, err 392 } 393 return TLFWriterKeyBundleID{h}, nil 394 } 395 396 // TLFReaderKeyBundleV3 stores all the reader keys with reader 397 // permissions on a TLF. 398 type TLFReaderKeyBundleV3 struct { 399 Keys UserDeviceKeyInfoMapV3 `codec:"rKeys,omitempty"` 400 401 // M_e as described in § 4.1.1. Because devices can be added 402 // into the key generation after it is initially created (so 403 // those devices can get access to existing data), we track 404 // multiple ephemeral public keys; the one used by a 405 // particular device is specified by EPubKeyIndex in its 406 // TLFCryptoKeyInfo struct. This list is needed so a reader 407 // rekey doesn't modify the writer metadata. 408 TLFEphemeralPublicKeys kbfscrypto.TLFEphemeralPublicKeys `codec:"rEPubKey,omitempty"` 409 410 codec.UnknownFieldSetHandler 411 } 412 413 // DeserializeTLFReaderKeyBundleV3 deserializes a TLFReaderKeyBundleV3 414 // from the given path and returns it. 415 func DeserializeTLFReaderKeyBundleV3(codec kbfscodec.Codec, path string) ( 416 TLFReaderKeyBundleV3, error) { 417 var rkb TLFReaderKeyBundleV3 418 err := kbfscodec.DeserializeFromFile(codec, path, &rkb) 419 if err != nil { 420 return TLFReaderKeyBundleV3{}, err 421 } 422 if len(rkb.Keys) == 0 { 423 rkb.Keys = make(UserDeviceKeyInfoMapV3) 424 } 425 return rkb, nil 426 } 427 428 // Size implements the cache.Measurable interface. 429 func (rkb TLFReaderKeyBundleV3) Size() (bytes int) { 430 bytes += cache.PtrSize + rkb.Keys.Size() // Keys 431 432 // TLFEphemeralPublicKeys 433 bytes += rkb.TLFEphemeralPublicKeys.Size() 434 435 // For codec.UnknownFieldSetHandler. It has a private map field which we 436 // can't inspect unless extending the codec package. Just assume it's empty 437 // for now. 438 bytes += cache.PtrSize 439 440 return bytes 441 } 442 443 var _ cache.Measurable = TLFReaderKeyBundleV3{} 444 445 // IsReader returns true if the given user device is in the reader set. 446 func (rkb TLFReaderKeyBundleV3) IsReader(user keybase1.UID, deviceKey kbfscrypto.CryptPublicKey) bool { 447 _, ok := rkb.Keys[user][deviceKey] 448 return ok 449 } 450 451 // DeepCopy creates a deep copy of this key bundle. 452 func (rkb TLFReaderKeyBundleV3) DeepCopy(codec kbfscodec.Codec) ( 453 TLFReaderKeyBundleV3, error) { 454 var rkbCopy TLFReaderKeyBundleV3 455 if err := kbfscodec.Update(codec, &rkbCopy, rkb); err != nil { 456 return TLFReaderKeyBundleV3{}, err 457 } 458 if len(rkbCopy.Keys) == 0 { 459 rkbCopy.Keys = make(UserDeviceKeyInfoMapV3) 460 } 461 return rkbCopy, nil 462 } 463 464 // TLFReaderKeyBundleID is the hash of a serialized TLFReaderKeyBundle. 465 type TLFReaderKeyBundleID struct { 466 h kbfshash.Hash 467 } 468 469 var _ encoding.BinaryMarshaler = TLFReaderKeyBundleID{} 470 var _ encoding.BinaryUnmarshaler = (*TLFReaderKeyBundleID)(nil) 471 472 // TLFReaderKeyBundleIDFromBytes creates a new TLFReaderKeyBundleID from the given bytes. 473 // If the returned error is nil, the returned TLFReaderKeyBundleID is valid. 474 func TLFReaderKeyBundleIDFromBytes(data []byte) (TLFReaderKeyBundleID, error) { 475 h, err := kbfshash.HashFromBytes(data) 476 if err != nil { 477 return TLFReaderKeyBundleID{}, err 478 } 479 return TLFReaderKeyBundleID{h}, nil 480 } 481 482 // TLFReaderKeyBundleIDFromString creates a new TLFReaderKeyBundleID from the given string. 483 // If the returned error is nil, the returned TLFReaderKeyBundleID is valid. 484 func TLFReaderKeyBundleIDFromString(id string) (TLFReaderKeyBundleID, error) { 485 if len(id) == 0 { 486 return TLFReaderKeyBundleID{}, nil 487 } 488 h, err := kbfshash.HashFromString(id) 489 if err != nil { 490 return TLFReaderKeyBundleID{}, err 491 } 492 return TLFReaderKeyBundleID{h}, nil 493 } 494 495 // Bytes returns the bytes of the TLFReaderKeyBundleID. 496 func (h TLFReaderKeyBundleID) Bytes() []byte { 497 return h.h.Bytes() 498 } 499 500 // String returns the string form of the TLFReaderKeyBundleID. 501 func (h TLFReaderKeyBundleID) String() string { 502 return h.h.String() 503 } 504 505 // MarshalBinary implements the encoding.BinaryMarshaler interface for 506 // TLFReaderKeyBundleID. Returns an error if the TLFReaderKeyBundleID is invalid and not the 507 // zero TLFReaderKeyBundleID. 508 func (h TLFReaderKeyBundleID) MarshalBinary() (data []byte, err error) { 509 return h.h.MarshalBinary() 510 } 511 512 // UnmarshalBinary implements the encoding.BinaryUnmarshaler interface 513 // for TLFReaderKeyBundleID. Returns an error if the given byte array is non-empty and 514 // the TLFReaderKeyBundleID is invalid. 515 func (h *TLFReaderKeyBundleID) UnmarshalBinary(data []byte) error { 516 return h.h.UnmarshalBinary(data) 517 } 518 519 // IsNil returns true if the ID is unset. 520 func (h TLFReaderKeyBundleID) IsNil() bool { 521 return h == TLFReaderKeyBundleID{} 522 } 523 524 // MakeTLFReaderKeyBundleID hashes a TLFReaderKeyBundleV3 to create an ID. 525 func MakeTLFReaderKeyBundleID(codec kbfscodec.Codec, rkb TLFReaderKeyBundleV3) ( 526 TLFReaderKeyBundleID, error) { 527 buf, err := codec.Encode(rkb) 528 if err != nil { 529 return TLFReaderKeyBundleID{}, err 530 } 531 h, err := kbfshash.DefaultHash(buf) 532 if err != nil { 533 return TLFReaderKeyBundleID{}, err 534 } 535 return TLFReaderKeyBundleID{h}, nil 536 } 537 538 // Size implements the cache.Measurable interface. 539 func (h TLFReaderKeyBundleID) Size() int { 540 return h.h.Size() 541 } 542 543 var _ cache.Measurable = TLFReaderKeyBundleID{}