forked from cloudflare/circl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
marshal.go
151 lines (136 loc) · 3.82 KB
/
marshal.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
package hpke
import (
"errors"
"golang.org/x/crypto/cryptobyte"
)
// marshal serializes an HPKE context.
func (c *encdecContext) marshal() ([]byte, error) {
var b cryptobyte.Builder
b.AddUint16(uint16(c.suite.kemID))
b.AddUint16(uint16(c.suite.kdfID))
b.AddUint16(uint16(c.suite.aeadID))
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(c.exporterSecret)
})
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(c.key)
})
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(c.baseNonce)
})
b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(c.sequenceNumber)
})
return b.Bytes()
}
// unmarshalContext parses an HPKE context.
func unmarshalContext(raw []byte) (*encdecContext, error) {
var (
err error
t cryptobyte.String
)
c := new(encdecContext)
s := cryptobyte.String(raw)
if !s.ReadUint16((*uint16)(&c.suite.kemID)) ||
!s.ReadUint16((*uint16)(&c.suite.kdfID)) ||
!s.ReadUint16((*uint16)(&c.suite.aeadID)) ||
!s.ReadUint8LengthPrefixed(&t) ||
!t.ReadBytes(&c.exporterSecret, len(t)) ||
!s.ReadUint8LengthPrefixed(&t) ||
!t.ReadBytes(&c.key, len(t)) ||
!s.ReadUint8LengthPrefixed(&t) ||
!t.ReadBytes(&c.baseNonce, len(t)) ||
!s.ReadUint8LengthPrefixed(&t) ||
!t.ReadBytes(&c.sequenceNumber, len(t)) {
return nil, errors.New("failed to parse context")
}
if !c.suite.isValid() {
return nil, ErrInvalidHPKESuite
}
Nh := c.suite.kdfID.ExtractSize()
if len(c.exporterSecret) != Nh {
return nil, errors.New("invalid exporter secret length")
}
Nk := int(c.suite.aeadID.KeySize())
if len(c.key) != Nk {
return nil, errors.New("invalid key length")
}
c.AEAD, err = c.suite.aeadID.New(c.key)
if err != nil {
return nil, err
}
Nn := int(c.suite.aeadID.NonceSize())
if len(c.baseNonce) != Nn {
return nil, errors.New("invalid base nonce length")
}
if len(c.sequenceNumber) != Nn {
return nil, errors.New("invalid sequence number length")
}
c.nonce = make([]byte, Nn)
return c, nil
}
// MarshalBinary serializes an HPKE sealer according to the format specified
// below. (Expressed in TLS syntax.) Note that this format is not defined by
// the HPKE standard.
//
// enum { sealer(0), opener(1) } HpkeRole;
//
// struct {
// HpkeKemId kem_id; // draft-irtf-cfrg-hpke-07
// HpkeKdfId kdf_id; // draft-irtf-cfrg-hpke-07
// HpkeAeadId aead_id; // draft-irtf-cfrg-hpke-07
// opaque exporter_secret<0..255>;
// opaque key<0..255>;
// opaque base_nonce<0..255>;
// opaque seq<0..255>;
// } HpkeContext;
//
// struct {
// HpkeRole role = 0; // sealer
// HpkeContext context;
// } HpkeSealer;
func (c *sealContext) MarshalBinary() ([]byte, error) {
rawContext, err := c.encdecContext.marshal()
if err != nil {
return nil, err
}
return append([]byte{0}, rawContext...), nil
}
// UnmarshalSealer parses an HPKE sealer.
func UnmarshalSealer(raw []byte) (Sealer, error) {
if raw[0] != 0 {
return nil, errors.New("incorrect role")
}
context, err := unmarshalContext(raw[1:])
if err != nil {
return nil, err
}
return &sealContext{context}, nil
}
// MarshalBinary serializes an HPKE opener according to the format specified
// below. (Expressed in TLS syntax.) Note that this format is not defined by the
// HPKE standard.
//
// struct {
// HpkeRole role = 1; // opener
// HpkeContext context;
// } HpkeOpener;
func (c *openContext) MarshalBinary() ([]byte, error) {
rawContext, err := c.encdecContext.marshal()
if err != nil {
return nil, err
}
return append([]byte{1}, rawContext...), nil
}
// UnmarshalOpener parses a serialized HPKE opener and returns the corresponding
// Opener.
func UnmarshalOpener(raw []byte) (Opener, error) {
if raw[0] != 1 {
return nil, errors.New("incorrect role")
}
context, err := unmarshalContext(raw[1:])
if err != nil {
return nil, err
}
return &openContext{context}, nil
}