-
Notifications
You must be signed in to change notification settings - Fork 7
/
forwardsecure.go
106 lines (83 loc) · 2.38 KB
/
forwardsecure.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
package ed25519
import "encoding/binary"
const (
ForwardSecureSignatureSize = SignatureSize + PublicKeySize + SignatureSize
)
type ForwardSecurePublicKey PublicKey
type signedSubKey struct {
Sk PrivateKey
PkSig Signature
}
type ForwardSecurePrivateKey struct {
PublicKey ForwardSecurePublicKey
Start uint64
SubKeys []signedSubKey
}
func (key ForwardSecurePrivateKey) ValidOffset(offset uint64) bool {
limit := key.Start + uint64(len(key.SubKeys))
return offset >= key.Start && offset < limit
}
type ForwardSecureSignature struct {
Sig Signature
Pk PublicKey
PkSig Signature
}
func GenerateForwardSecureKey(offset, count uint64) (pk ForwardSecurePublicKey, sk ForwardSecurePrivateKey) {
rawPk, skToBeDestroyed := GenerateKey()
subs := make([]signedSubKey, count)
for i := uint64(0); i < count; i++ {
subPk, subSk := GenerateKey()
data := toBytes(offset+i, subPk)
subPkSig := Sign(&skToBeDestroyed, data)
subs[i] = signedSubKey{
Sk: subSk,
PkSig: subPkSig,
}
}
pk = ForwardSecurePublicKey(rawPk)
sk = ForwardSecurePrivateKey{
PublicKey: pk,
Start: offset,
SubKeys: subs,
}
return
}
func toBytes(offset uint64, subPk PublicKey) []byte {
var buffer [8 + PublicKeySize]byte
binary.BigEndian.PutUint64(buffer[0:8], offset)
copy(buffer[8:PublicKeySize], subPk[:])
return buffer[:]
}
func ForwardSecurePrivateKeyToPublicKey(sk *ForwardSecurePrivateKey) ForwardSecurePublicKey {
return sk.PublicKey
}
func ForwardSecureSign(sk *ForwardSecurePrivateKey, offset uint64, data []byte) ForwardSecureSignature {
if !sk.ValidOffset(offset) {
return ForwardSecureSignature{}
}
idx := offset - sk.Start
subSk := &sk.SubKeys[idx].Sk
subPk, _ := PrivateKeyToPublicKey(subSk)
sig := Sign(subSk, data)
return ForwardSecureSignature{
Sig: sig,
Pk: subPk,
PkSig: sk.SubKeys[idx].PkSig,
}
}
func ForwardSecureVerify(pk *ForwardSecurePublicKey, offset uint64, data []byte, sig ForwardSecureSignature) bool {
verifyData := toBytes(offset, sig.Pk)
masterPk := (*PublicKey)(pk)
return Verify(masterPk, verifyData, &sig.PkSig) && Verify(&sig.Pk, data, &sig.Sig)
}
func ForwardSecureUpdate(sk *ForwardSecurePrivateKey, offset uint64) (deleted uint64) {
if offset > sk.Start {
deleted = offset - sk.Start
if max := uint64(len(sk.SubKeys)); deleted > max {
deleted = max
}
sk.Start += deleted
sk.SubKeys = sk.SubKeys[deleted:]
}
return
}