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{}