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
/
common.go
158 lines (134 loc) · 5.01 KB
/
common.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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package ephemeral
import (
"context"
"fmt"
"sort"
"time"
"github.com/keybase/client/go/libkb"
"github.com/keybase/client/go/protocol/keybase1"
)
// NOTE: If you change this value you should change it in web/ephemeral.iced
// and go/ekreaperd/reaper.go as well.
// Keys last at most one week
const KeyLifetimeSecs = 60 * 60 * 24 * 7 // one week
// Everyday we want to generate a new key if possible
const KeyGenLifetimeSecs = 60 * 60 * 24 // one day
type EKType string
const (
DeviceEKStr EKType = "deviceEK"
UserEKStr EKType = "userEK"
TeamEKStr EKType = "teamEK"
)
type EKUnboxErr struct {
boxType EKType
boxGeneration keybase1.EkGeneration
missingType EKType
missingGeneration keybase1.EkGeneration
}
func newEKUnboxErr(boxType EKType, boxGeneration keybase1.EkGeneration, missingType EKType, missingGeneration keybase1.EkGeneration) *EKUnboxErr {
return &EKUnboxErr{
missingType: missingType,
boxType: boxType,
missingGeneration: missingGeneration,
boxGeneration: boxGeneration,
}
}
func (e *EKUnboxErr) Error() string {
return fmt.Sprintf("Error unboxing %s@generation:%v missing %s@generation:%v", e.boxType, e.boxGeneration, e.missingType, e.missingGeneration)
}
type EKMissingBoxErr struct {
boxType EKType
boxGeneration keybase1.EkGeneration
}
func newEKMissingBoxErr(boxType EKType, boxGeneration keybase1.EkGeneration) *EKMissingBoxErr {
return &EKMissingBoxErr{
boxType: boxType,
boxGeneration: boxGeneration,
}
}
func (e *EKMissingBoxErr) Error() string {
return fmt.Sprintf("Missing box for %s@generation:%v", e.boxType, e.boxGeneration)
}
func ctimeIsStale(ctime keybase1.Time, currentMerkleRoot libkb.MerkleRoot) bool {
return currentMerkleRoot.Ctime()-ctime.UnixSeconds() >= KeyLifetimeSecs
}
func keygenNeeded(ctime keybase1.Time, currentMerkleRoot libkb.MerkleRoot) bool {
return currentMerkleRoot.Ctime()-ctime.UnixSeconds() >= KeyGenLifetimeSecs
}
func nextKeygenTime(ctime keybase1.Time) time.Time {
return keybase1.TimeFromSeconds(ctime.UnixSeconds() + KeyGenLifetimeSecs).Time()
}
func makeNewRandomSeed() (seed keybase1.Bytes32, err error) {
bs, err := libkb.RandBytes(libkb.NaclDHKeysize)
if err != nil {
return seed, err
}
return libkb.MakeByte32(bs), nil
}
func deriveDHKey(k keybase1.Bytes32, reason libkb.DeriveReason) *libkb.NaclDHKeyPair {
derived, err := libkb.DeriveFromSecret(k, reason)
if err != nil {
panic("This should never fail: " + err.Error())
}
keypair, err := libkb.MakeNaclDHKeyPairFromSecret(derived)
if err != nil {
panic("This should never fail: " + err.Error())
}
return &keypair
}
func newEKSeedFromBytes(b []byte) (seed keybase1.Bytes32, err error) {
if len(b) != libkb.NaclDHKeysize {
err = fmt.Errorf("Wrong EkSeed len: %d != %d", len(b), libkb.NaclDHKeysize)
return seed, err
}
copy(seed[:], b)
return seed, nil
}
func getCurrentUserUV(ctx context.Context, g *libkb.GlobalContext) (ret keybase1.UserVersion, err error) {
err = g.GetFullSelfer().WithSelf(ctx, func(u *libkb.User) error {
ret = u.ToUserVersion()
return nil
})
return ret, err
}
// Map generations to their creation time
type keyExpiryMap map[keybase1.EkGeneration]keybase1.Time
// Keys expire after `KeyLifetimeSecs` unless there has been a gap in their
// generation. If there has been a gap of more than a day (the normal
// generation time), a key can be re-used for up to `KeyLifetimeSecs` until it
// is considered expired. to determine expiration, we look at all of the
// current keys and account for any gaps since we don't want to expire a key if
// it is still used to encrypt a different key. This only applies to deviceEKs
// or userEKs since they can have a dependency above them. A teamEK expires
// after `KeyLifetimeSecs` without exception, so it doesn't call this.
func getExpiredGenerations(ctx context.Context, g *libkb.GlobalContext,
keyMap keyExpiryMap, nowCtime keybase1.Time) (expired []keybase1.EkGeneration) {
// Sort the generations we have so we can walk through them in order.
maxLifetime := keybase1.TimeFromSeconds(KeyLifetimeSecs)
var keys []keybase1.EkGeneration
for k := range keyMap {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool { return keys[i] < keys[j] })
var nextKeyCtime keybase1.Time
var expiryOffset keybase1.Time
for i, generation := range keys {
keyCtime := keyMap[generation]
if i < len(keys)-1 {
nextKeyCtime = keyMap[keys[i+1]]
} else {
nextKeyCtime = nowCtime
}
expiryOffset = nextKeyCtime - keyCtime
if expiryOffset > maxLifetime { // Offset can be max KeyLifetimeSecs
expiryOffset = maxLifetime
}
// Keys can live for as long as KeyLifetimeSecs + expiryOffset
if (nowCtime - keyCtime) >= (maxLifetime + expiryOffset) {
g.Log.CDebugf(ctx, "getExpiredGenerations: expired generation:%v, nowCtime: %v, keyCtime:%v, nextKeyCtime:%v, expiryOffset:%v, keyMap: %v, i:%v",
generation, nowCtime.Time(), keyCtime.Time(), nextKeyCtime.Time(), time.Duration(expiryOffset)*time.Second, keyMap, i)
expired = append(expired, generation)
}
}
return expired
}