-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathapi.go
143 lines (126 loc) · 3.84 KB
/
api.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
package prekeyserver
import (
"crypto/rand"
"encoding/json"
"errors"
"io"
"time"
"github.com/otrv4/gotrx"
)
// Factory is the main entry point for the otrng prekey server functionality.
type Factory interface {
CreateKeypair() Keypair
LoadKeypairFrom(r io.Reader) (Keypair, error)
LoadStorageType(name string) (Storage, error)
StoreKeysInto(Keypair, io.Writer) error
NewServer(identity string, keys Keypair, fragLen int, st Storage, sessionTimeout, fragmentTimeout time.Duration, r Restrictor) Server
}
// Keypair represents the minimum key functionality a server implementation will need
type Keypair interface {
Fingerprint() gotrx.Fingerprint
}
// Storage has the responsibility of creating new storage implementations
type Storage interface {
createStorage() storage
}
// Server is the core handling functionality of a prekey server
type Server interface {
Handle(from, message string) ([]string, error)
}
// CreateFactory will return a new factory that can be used to access
// the basic functionality of the prekey server. The rand argument can
// be a reader to allow for fixed randomness. If nil is given, rand.Reader will
// be used instead.
func CreateFactory(rand io.Reader) Factory {
return &realFactory{rand}
}
type realFactory struct {
r io.Reader
}
func (f *realFactory) RandReader() io.Reader {
if f.r == nil {
return rand.Reader
}
return f.r
}
func (*realFactory) LoadStorageType(name string) (Storage, error) {
if isInMemoryStorageDescriptor(name) {
return &inMemoryStorageFactory{}, nil
} else if isFileStorageDescriptor(name) {
return createFileStorageFactoryFrom(name)
}
return nil, errors.New("unknown storage type")
}
type keypairInStorage struct {
Symmetric string
Private string
Public string
}
func (kis *keypairInStorage) intoKeypair() (*gotrx.Keypair, error) {
sym, ok := decodeMessage(kis.Symmetric)
if !ok {
return nil, errors.New("couldn't decode symmetric key")
}
privb, ok := decodeMessage(kis.Private)
if !ok {
return nil, errors.New("couldn't decode private key")
}
pubb, ok := decodeMessage(kis.Public)
if !ok {
return nil, errors.New("couldn't decode public key")
}
_, priv, ok := gotrx.DeserializeScalar(privb)
if !ok {
return nil, errors.New("couldn't decode scalar for private key")
}
_, pub, ok := gotrx.DeserializePoint(pubb)
if !ok {
return nil, errors.New("couldn't decode point for public key")
}
res := &gotrx.Keypair{}
copy(res.Sym[:], sym)
res.Pub = gotrx.CreatePublicKey(pub, gotrx.Ed448Key)
res.Priv = gotrx.CreatePrivateKey(priv)
return res, nil
}
func (f *realFactory) StoreKeysInto(kpp Keypair, w io.Writer) error {
kp := kpp.(*gotrx.Keypair)
enc := json.NewEncoder(w)
kis := &keypairInStorage{
Symmetric: encodeMessage(kp.Sym[:]),
Private: encodeMessage(gotrx.SerializeScalar(kp.Priv.K())),
Public: encodeMessage(gotrx.SerializePoint(kp.Pub.K())),
}
return enc.Encode(kis)
}
func (*realFactory) LoadKeypairFrom(r io.Reader) (Keypair, error) {
dec := json.NewDecoder(r)
res := &keypairInStorage{}
if e := dec.Decode(res); e != nil {
return nil, e
}
return res.intoKeypair()
}
func (f *realFactory) CreateKeypair() Keypair {
return gotrx.GenerateKeypair(f)
}
func (*realFactory) NewServer(identity string, keys Keypair, fragLen int, st Storage, sessionTimeout, fragmentTimeout time.Duration, r Restrictor) Server {
kp := keys.(*gotrx.Keypair)
if r == nil {
r = nullRestrictor
}
gs := &GenericServer{
identity: identity,
fingerprint: kp.Fingerprint(),
key: kp,
fragLen: fragLen,
fragmentations: gotrx.NewFragmentor(fragmentationPrefix),
sessions: newSessionManager(),
storageImpl: st.createStorage(),
sessionTimeout: sessionTimeout,
fragmentationTimeout: fragmentTimeout,
rest: r,
}
gs.messageHandler = &otrngMessageHandler{s: gs}
return gs
}