This repository has been archived by the owner on Jul 7, 2020. It is now read-only.
forked from keybase/client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
encrypteddb.go
119 lines (102 loc) · 2.47 KB
/
encrypteddb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
package encrypteddb
import (
"fmt"
"github.com/keybase/client/go/libkb"
"golang.org/x/crypto/nacl/secretbox"
"golang.org/x/net/context"
)
type DbFn func(g *libkb.GlobalContext) *libkb.JSONLocalDb
type KeyFn func(context.Context) ([32]byte, error)
type boxedData struct {
V int
N [24]byte
E []byte
}
// ***
// If we change this, make sure to update the key derivation reason for all callers of EncryptedDB!
// ***
const cryptoVersion = 1
// Handle to a db that encrypts values using nacl secretbox.
// Does not encrypt keys.
// Not threadsafe.
type EncryptedDB struct {
libkb.Contextified
getSecretBoxKey KeyFn
getDB DbFn
}
func New(g *libkb.GlobalContext, getDB DbFn, getSecretBoxKey KeyFn) *EncryptedDB {
return &EncryptedDB{
Contextified: libkb.NewContextified(g),
getDB: getDB,
getSecretBoxKey: getSecretBoxKey,
}
}
// Get a value
// Decodes into res
// Returns (found, err). Res is valid only if (found && err == nil)
func (i *EncryptedDB) Get(ctx context.Context, key libkb.DbKey, res interface{}) (bool, error) {
var err error
db := i.getDB(i.G())
b, found, err := db.GetRaw(key)
if err != nil {
return false, err
}
if !found {
return false, nil
}
// Decode encrypted box
var boxed boxedData
if err := libkb.MPackDecode(b, &boxed); err != nil {
return true, err
}
if boxed.V > cryptoVersion {
return true, fmt.Errorf("bad crypto version: %d current: %d", boxed.V,
cryptoVersion)
}
enckey, err := i.getSecretBoxKey(ctx)
if err != nil {
return true, err
}
pt, ok := secretbox.Open(nil, boxed.E, &boxed.N, &enckey)
if !ok {
return true, fmt.Errorf("failed to decrypt item")
}
if err = libkb.MPackDecode(pt, res); err != nil {
return true, err
}
return true, nil
}
func (i *EncryptedDB) Put(ctx context.Context, key libkb.DbKey, data interface{}) error {
db := i.getDB(i.G())
dat, err := libkb.MPackEncode(data)
if err != nil {
return err
}
enckey, err := i.getSecretBoxKey(ctx)
if err != nil {
return err
}
var nonce []byte
nonce, err = libkb.RandBytes(24)
if err != nil {
return err
}
var fnonce [24]byte
copy(fnonce[:], nonce)
sealed := secretbox.Seal(nil, dat, &fnonce, &enckey)
boxed := boxedData{
V: cryptoVersion,
E: sealed,
N: fnonce,
}
// Encode encrypted box
if dat, err = libkb.MPackEncode(boxed); err != nil {
return err
}
// Write out
return db.PutRaw(key, dat)
}
func (i *EncryptedDB) Delete(ctx context.Context, key libkb.DbKey) error {
db := i.getDB(i.G())
return db.Delete(key)
}