@@ -28,6 +28,8 @@ import (
2828 "sync"
2929 "time"
3030
31+ "github.com/pkg/errors"
32+
3133 "github.com/dgraph-io/badger/v4/pb"
3234 "github.com/dgraph-io/badger/v4/y"
3335 "google.golang.org/protobuf/proto"
@@ -265,7 +267,7 @@ func WriteKeyRegistry(reg *KeyRegistry, opt KeyRegistryOptions) error {
265267 // Write all the datakeys to the buf.
266268 for _ , k := range reg .dataKeys {
267269 // Writing the datakey to the given buffer.
268- if err := storeDataKey (buf , opt .EncryptionKey , k ); err != nil {
270+ if err := storeDataKey (buf , opt .EncryptionKey , * k ); err != nil {
269271 return y .Wrapf (err , "Error while storing datakey in WriteKeyRegistry" )
270272 }
271273 }
@@ -339,44 +341,58 @@ func (kr *KeyRegistry) LatestDataKey() (*pb.DataKey, error) {
339341 defer kr .Unlock ()
340342 // Key might have generated by another go routine. So,
341343 // checking once again.
342- key , valid = validKey ()
343- if valid {
344+ if key , valid := validKey (); valid {
344345 return key , nil
345346 }
346347 k := make ([]byte , len (kr .opt .EncryptionKey ))
347348 iv , err := y .GenerateIV ()
348349 if err != nil {
349350 return nil , err
350351 }
351- _ , err = rand . Read ( k )
352- if err != nil {
352+
353+ if _ , err := rand . Read ( k ); err != nil {
353354 return nil , err
354355 }
355356 // Otherwise Increment the KeyID and generate new datakey.
356357 kr .nextKeyID ++
357- dk := & pb.DataKey {
358+ dk := pb.DataKey {
358359 KeyId : kr .nextKeyID ,
359360 Data : k ,
360361 CreatedAt : time .Now ().Unix (),
361362 Iv : iv ,
362363 }
364+ kr .lastCreated = dk .CreatedAt
365+ kr .dataKeys [kr .nextKeyID ] = & dk
363366 // Don't store the datakey on file if badger is running in InMemory mode.
364- if ! kr .opt .InMemory {
365- // Store the datekey.
366- buf := & bytes.Buffer {}
367- if err = storeDataKey (buf , kr .opt .EncryptionKey , dk ); err != nil {
368- return nil , err
369- }
370- // Persist the datakey to the disk
371- if _ , err = kr .fp .Write (buf .Bytes ()); err != nil {
372- return nil , err
373- }
367+ if kr .opt .InMemory {
368+ return & dk , nil
369+
374370 }
375- // storeDatakey encrypts the datakey So, placing un-encrypted key in the memory.
376- dk .Data = k
377- kr .lastCreated = dk .CreatedAt
378- kr .dataKeys [kr .nextKeyID ] = dk
379- return dk , nil
371+ // Store the datekey.
372+ if err = storeDataKey (kr .fp , kr .opt .EncryptionKey , dk ); err != nil {
373+ return nil , err
374+ }
375+ return & dk , nil
376+ }
377+
378+ func (kr * KeyRegistry ) AddKey (dk pb.DataKey ) (uint64 , error ) {
379+ // If we don't have a encryption key, we cannot store the datakey.
380+ if len (kr .opt .EncryptionKey ) == 0 {
381+ return 0 , errors .New ("No encryption key found. Cannot add data key" )
382+ }
383+
384+ if _ , ok := kr .dataKeys [dk .KeyId ]; ! ok {
385+ // If KeyId does not exists already, then use the next available KeyId to store data key.
386+ kr .nextKeyID ++
387+ dk .KeyId = kr .nextKeyID
388+ }
389+ kr .dataKeys [dk .KeyId ] = & dk
390+
391+ if kr .opt .InMemory {
392+ return dk .KeyId , nil
393+ }
394+ // Store the datakey.
395+ return dk .KeyId , storeDataKey (kr .fp , kr .opt .EncryptionKey , dk )
380396}
381397
382398// Close closes the key registry.
@@ -388,38 +404,36 @@ func (kr *KeyRegistry) Close() error {
388404}
389405
390406// storeDataKey stores datakey in an encrypted format in the given buffer. If storage key preset.
391- func storeDataKey (buf * bytes.Buffer , storageKey []byte , k * pb.DataKey ) error {
407+ // DO NOT use a pointer for key. storeDataKey modifies the kv.Data field.
408+ func storeDataKey (w io.Writer , storageKey []byte , key pb.DataKey ) error {
392409 // xor will encrypt the IV and xor with the given data.
393410 // It'll used for both encryption and decryption.
394411 xor := func () error {
395412 if len (storageKey ) == 0 {
396413 return nil
397414 }
398415 var err error
399- k .Data , err = y .XORBlockAllocate (k .Data , storageKey , k .Iv )
416+ key .Data , err = y .XORBlockAllocate (key .Data , storageKey , key .Iv )
400417 return err
401418 }
402419 // In memory datakey will be plain text so encrypting before storing to the disk.
403- var err error
404- if err = xor (); err != nil {
420+ if err := xor (); err != nil {
405421 return y .Wrapf (err , "Error while encrypting datakey in storeDataKey" )
406422 }
407- var data []byte
408- if data , err = proto .Marshal (k ); err != nil {
423+
424+ data , err := key .Marshal ()
425+ if err != nil {
409426 err = y .Wrapf (err , "Error while marshaling datakey in storeDataKey" )
410- var err2 error
411- // decrypting the datakey back.
412- if err2 = xor (); err2 != nil {
413- return y .Wrapf (err ,
414- y .Wrapf (err2 , "Error while decrypting datakey in storeDataKey" ).Error ())
427+ if err2 := xor (); err2 != nil {
428+ return y .Wrapf (err , y .Wrapf (err2 , "Error while decrypting datakey in storeDataKey" ).Error ())
415429 }
416430 return err
417431 }
432+
418433 var lenCrcBuf [8 ]byte
419434 binary .BigEndian .PutUint32 (lenCrcBuf [0 :4 ], uint32 (len (data )))
420435 binary .BigEndian .PutUint32 (lenCrcBuf [4 :8 ], crc32 .Checksum (data , y .CastagnoliCrcTable ))
421- y .Check2 (buf .Write (lenCrcBuf [:]))
422- y .Check2 (buf .Write (data ))
423- // Decrypting the datakey back since we're using the pointer.
424- return xor ()
436+ y .Check2 (w .Write (lenCrcBuf [:]))
437+ y .Check2 (w .Write (data ))
438+ return nil
425439}
0 commit comments