-
Notifications
You must be signed in to change notification settings - Fork 64
/
packets.go
195 lines (163 loc) · 5.75 KB
/
packets.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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright 2015 Keybase, Inc. All rights reserved. Use of
// this source code is governed by the included BSD license.
package saltpack
import (
"fmt"
"github.com/keybase/go-codec/codec"
)
type receiverKeys struct {
_struct bool `codec:",toarray"` //nolint
ReceiverKID []byte `codec:"receiver_key_id"`
PayloadKeyBox []byte `codec:"payloadkey"`
}
// Version is a major.minor pair that shows the version of the whole file
type Version struct {
_struct bool `codec:",toarray"` //nolint
Major int `codec:"major"`
Minor int `codec:"minor"`
}
func (v Version) String() string {
return fmt.Sprintf("%d.%d", v.Major, v.Minor)
}
// TODO: Check FormatName in the various Header.validate() functions.
// EncryptionHeader is the first packet in an encrypted message. It contains
// the encryptions of the session key, and various message metadata. This same
// struct is used for the signcryption mode as well, though the key types
// represented by the []byte arrays are different. (For example in the
// signcryption mode, the sender secretbox contains a *signing* key instead of
// an encryption key, and the receiver identifier takes a different form.)
type EncryptionHeader struct {
_struct bool `codec:",toarray"` //nolint
FormatName string `codec:"format_name"`
Version Version `codec:"vers"`
Type MessageType `codec:"type"`
Ephemeral []byte `codec:"ephemeral"`
SenderSecretbox []byte `codec:"sendersecretbox"`
Receivers []receiverKeys `codec:"rcvrs"`
}
// encryptionBlockV1 contains a block of encrypted data. It contains
// the ciphertext, and any necessary authentication Tags.
type encryptionBlockV1 struct {
_struct bool `codec:",toarray"` //nolint
HashAuthenticators []payloadAuthenticator `codec:"authenticators"`
PayloadCiphertext []byte `codec:"ctext"`
}
// encryptionBlockV2 is encryptionBlockV1, but with a flag signifying
// whether or not this is the final packet.
type encryptionBlockV2 struct {
encryptionBlockV1
IsFinal bool `codec:"final"`
}
// Make *encryptionBlockV2 implement codec.Selfer to encode IsFinal
// first, to preserve the behavior noticed in this issue:
// https://github.com/keybase/saltpack/pull/43 .
var _ codec.Selfer = (*encryptionBlockV2)(nil)
func (b *encryptionBlockV2) CodecEncodeSelf(e *codec.Encoder) {
e.MustEncode([]interface{}{
b.IsFinal,
b.HashAuthenticators,
b.PayloadCiphertext,
})
}
func (b *encryptionBlockV2) CodecDecodeSelf(d *codec.Decoder) {
d.MustDecode([]interface{}{
&b.IsFinal,
&b.HashAuthenticators,
&b.PayloadCiphertext,
})
}
func (h *EncryptionHeader) validate(versionValidator func(Version) error) error {
if h.Type != MessageTypeEncryption {
return ErrWrongMessageType{MessageTypeEncryption, h.Type}
}
return versionValidator(h.Version)
}
// The SigncryptionHeader has exactly the same structure as the
// EncryptionHeader, though the byte slices represent different types of keys.
type SigncryptionHeader EncryptionHeader
// signcryptionBlock contains a block of signed and encrypted data.
type signcryptionBlock struct {
_struct bool `codec:",toarray"` //nolint
PayloadCiphertext []byte `codec:"ctext"`
IsFinal bool `codec:"final"`
}
func (h *SigncryptionHeader) validate() error {
if h.Type != MessageTypeSigncryption {
return ErrWrongMessageType{MessageTypeSigncryption, h.Type}
}
if h.Version.Major != Version2().Major {
return ErrBadVersion{h.Version}
}
return nil
}
// SignatureHeader is the first packet in a signed message.
type SignatureHeader struct {
_struct bool `codec:",toarray"` //nolint
FormatName string `codec:"format_name"`
Version Version `codec:"vers"`
Type MessageType `codec:"type"`
SenderPublic []byte `codec:"sender_public"`
Nonce []byte `codec:"nonce"`
}
func newSignatureHeader(version Version, sender SigningPublicKey, msgType MessageType) (*SignatureHeader, error) {
if sender == nil {
return nil, ErrInvalidParameter{message: "no public signing key provided"}
}
nonce, err := newSigNonce()
if err != nil {
return nil, err
}
header := &SignatureHeader{
FormatName: FormatName,
Version: version,
Type: msgType,
SenderPublic: sender.ToKID(),
Nonce: nonce[:],
}
return header, nil
}
func (h *SignatureHeader) validate(versionValidator VersionValidator, msgType MessageType) error {
if err := versionValidator(h.Version); err != nil {
return err
}
if h.Type != msgType {
return ErrWrongMessageType{
Wanted: msgType,
Received: h.Type,
}
}
if msgType != MessageTypeAttachedSignature && msgType != MessageTypeDetachedSignature {
return ErrInvalidParameter{message: fmt.Sprintf("signature header must be MessageTypeAttachedSignature or MessageTypeDetachedSignature, not %d", msgType)}
}
return nil
}
// signatureBlockV1 contains a block of signed data.
type signatureBlockV1 struct {
_struct bool `codec:",toarray"` //nolint
Signature []byte `codec:"signature"`
PayloadChunk []byte `codec:"payload_chunk"`
}
// signatureBlockV2 is signatureBlockV1, but with a flag signifying
// whether or not this is the final packet.
type signatureBlockV2 struct {
signatureBlockV1
IsFinal bool `codec:"final"`
}
// Make *signatureBlockV2 implement codec.Selfer to encode IsFinal
// first, to preserve the behavior noticed in this issue:
// https://github.com/keybase/saltpack/pull/43 .
var _ codec.Selfer = (*signatureBlockV2)(nil)
func (b *signatureBlockV2) CodecEncodeSelf(e *codec.Encoder) {
e.MustEncode([]interface{}{
b.IsFinal,
b.Signature,
b.PayloadChunk,
})
}
func (b *signatureBlockV2) CodecDecodeSelf(d *codec.Decoder) {
d.MustDecode([]interface{}{
&b.IsFinal,
&b.Signature,
&b.PayloadChunk,
})
}