forked from cloudflare/circl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
algs.go
278 lines (251 loc) · 7.73 KB
/
algs.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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
package hpke
import (
"crypto"
"crypto/aes"
"crypto/cipher"
"crypto/elliptic"
_ "crypto/sha256" // Linking sha256.
_ "crypto/sha512" // Linking sha512.
"fmt"
"hash"
"io"
"github.com/cloudflare/circl/dh/x25519"
"github.com/cloudflare/circl/dh/x448"
"github.com/cloudflare/circl/ecc/p384"
"github.com/cloudflare/circl/kem"
"github.com/cloudflare/circl/kem/kyber/kyber768"
"golang.org/x/crypto/chacha20poly1305"
"golang.org/x/crypto/hkdf"
)
type KEM uint16
//nolint:golint,stylecheck
const (
// KEM_P256_HKDF_SHA256 is a KEM using P256 curve and HKDF with SHA-256.
KEM_P256_HKDF_SHA256 KEM = 0x10
// KEM_P384_HKDF_SHA384 is a KEM using P384 curve and HKDF with SHA-384.
KEM_P384_HKDF_SHA384 KEM = 0x11
// KEM_P521_HKDF_SHA512 is a KEM using P521 curve and HKDF with SHA-512.
KEM_P521_HKDF_SHA512 KEM = 0x12
// KEM_X25519_HKDF_SHA256 is a KEM using X25519 Diffie-Hellman function
// and HKDF with SHA-256.
KEM_X25519_HKDF_SHA256 KEM = 0x20
// KEM_X448_HKDF_SHA512 is a KEM using X448 Diffie-Hellman function and
// HKDF with SHA-512.
KEM_X448_HKDF_SHA512 KEM = 0x21
// KEM_X25519_KYBER768_DRAFT00 is a hybrid KEM built on DHKEM(X25519, HKDF-SHA256)
// and Kyber768Draft00
KEM_X25519_KYBER768_DRAFT00 KEM = 0x30
)
// IsValid returns true if the KEM identifier is supported by the HPKE package.
func (k KEM) IsValid() bool {
switch k {
case KEM_P256_HKDF_SHA256,
KEM_P384_HKDF_SHA384,
KEM_P521_HKDF_SHA512,
KEM_X25519_HKDF_SHA256,
KEM_X448_HKDF_SHA512,
KEM_X25519_KYBER768_DRAFT00:
return true
default:
return false
}
}
// Scheme returns an instance of a KEM that supports authentication. Panics if
// the KEM identifier is invalid.
func (k KEM) Scheme() kem.AuthScheme {
switch k {
case KEM_P256_HKDF_SHA256:
return dhkemp256hkdfsha256
case KEM_P384_HKDF_SHA384:
return dhkemp384hkdfsha384
case KEM_P521_HKDF_SHA512:
return dhkemp521hkdfsha512
case KEM_X25519_HKDF_SHA256:
return dhkemx25519hkdfsha256
case KEM_X448_HKDF_SHA512:
return dhkemx448hkdfsha512
case KEM_X25519_KYBER768_DRAFT00:
return hybridkemX25519Kyber768
default:
panic(ErrInvalidKEM)
}
}
type KDF uint16
//nolint:golint,stylecheck
const (
// KDF_HKDF_SHA256 is a KDF using HKDF with SHA-256.
KDF_HKDF_SHA256 KDF = 0x01
// KDF_HKDF_SHA384 is a KDF using HKDF with SHA-384.
KDF_HKDF_SHA384 KDF = 0x02
// KDF_HKDF_SHA512 is a KDF using HKDF with SHA-512.
KDF_HKDF_SHA512 KDF = 0x03
)
func (k KDF) IsValid() bool {
switch k {
case KDF_HKDF_SHA256,
KDF_HKDF_SHA384,
KDF_HKDF_SHA512:
return true
default:
return false
}
}
// ExtractSize returns the size (in bytes) of the pseudorandom key produced
// by KDF.Extract.
func (k KDF) ExtractSize() int {
switch k {
case KDF_HKDF_SHA256:
return crypto.SHA256.Size()
case KDF_HKDF_SHA384:
return crypto.SHA384.Size()
case KDF_HKDF_SHA512:
return crypto.SHA512.Size()
default:
panic(ErrInvalidKDF)
}
}
// Extract derives a pseudorandom key from a high-entropy, secret input and a
// salt. The size of the output is determined by KDF.ExtractSize.
func (k KDF) Extract(secret, salt []byte) (pseudorandomKey []byte) {
return hkdf.Extract(k.hash(), secret, salt)
}
// Expand derives a variable length pseudorandom string from a pseudorandom key
// and an information string. Panics if the pseudorandom key is less
// than N bytes, or if the output length is greater than 255*N bytes,
// where N is the size returned by KDF.Extract function.
func (k KDF) Expand(pseudorandomKey, info []byte, outputLen uint) []byte {
extractSize := k.ExtractSize()
if len(pseudorandomKey) < extractSize {
panic(fmt.Errorf("pseudorandom key must be %v bytes", extractSize))
}
maxLength := uint(255 * extractSize)
if outputLen > maxLength {
panic(fmt.Errorf("output length must be less than %v bytes", maxLength))
}
output := make([]byte, outputLen)
rd := hkdf.Expand(k.hash(), pseudorandomKey[:extractSize], info)
_, err := io.ReadFull(rd, output)
if err != nil {
panic(err)
}
return output
}
func (k KDF) hash() func() hash.Hash {
switch k {
case KDF_HKDF_SHA256:
return crypto.SHA256.New
case KDF_HKDF_SHA384:
return crypto.SHA384.New
case KDF_HKDF_SHA512:
return crypto.SHA512.New
default:
panic(ErrInvalidKDF)
}
}
type AEAD uint16
//nolint:golint,stylecheck
const (
// AEAD_AES128GCM is AES-128 block cipher in Galois Counter Mode (GCM).
AEAD_AES128GCM AEAD = 0x01
// AEAD_AES256GCM is AES-256 block cipher in Galois Counter Mode (GCM).
AEAD_AES256GCM AEAD = 0x02
// AEAD_ChaCha20Poly1305 is ChaCha20 stream cipher and Poly1305 MAC.
AEAD_ChaCha20Poly1305 AEAD = 0x03
)
// New instantiates an AEAD cipher from the identifier, returns an error if the
// identifier is not known.
func (a AEAD) New(key []byte) (cipher.AEAD, error) {
switch a {
case AEAD_AES128GCM, AEAD_AES256GCM:
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
return cipher.NewGCM(block)
case AEAD_ChaCha20Poly1305:
return chacha20poly1305.New(key)
default:
panic(ErrInvalidAEAD)
}
}
func (a AEAD) IsValid() bool {
switch a {
case AEAD_AES128GCM,
AEAD_AES256GCM,
AEAD_ChaCha20Poly1305:
return true
default:
return false
}
}
// KeySize returns the size in bytes of the keys used by the AEAD cipher.
func (a AEAD) KeySize() uint {
switch a {
case AEAD_AES128GCM:
return 16
case AEAD_AES256GCM:
return 32
case AEAD_ChaCha20Poly1305:
return chacha20poly1305.KeySize
default:
panic(ErrInvalidAEAD)
}
}
// NonceSize returns the size in bytes of the nonce used by the AEAD cipher.
func (a AEAD) NonceSize() uint {
switch a {
case AEAD_AES128GCM,
AEAD_AES256GCM,
AEAD_ChaCha20Poly1305:
return 12
default:
panic(ErrInvalidAEAD)
}
}
// CipherLen returns the length of a ciphertext corresponding to a message of
// length mLen.
func (a AEAD) CipherLen(mLen uint) uint {
switch a {
case AEAD_AES128GCM, AEAD_AES256GCM, AEAD_ChaCha20Poly1305:
return mLen + 16
default:
panic(ErrInvalidAEAD)
}
}
var (
dhkemp256hkdfsha256, dhkemp384hkdfsha384, dhkemp521hkdfsha512 shortKEM
dhkemx25519hkdfsha256, dhkemx448hkdfsha512 xKEM
hybridkemX25519Kyber768 hybridKEM
)
func init() {
dhkemp256hkdfsha256.Curve = elliptic.P256()
dhkemp256hkdfsha256.dhKemBase.id = KEM_P256_HKDF_SHA256
dhkemp256hkdfsha256.dhKemBase.name = "HPKE_KEM_P256_HKDF_SHA256"
dhkemp256hkdfsha256.dhKemBase.Hash = crypto.SHA256
dhkemp256hkdfsha256.dhKemBase.dhKEM = dhkemp256hkdfsha256
dhkemp384hkdfsha384.Curve = p384.P384()
dhkemp384hkdfsha384.dhKemBase.id = KEM_P384_HKDF_SHA384
dhkemp384hkdfsha384.dhKemBase.name = "HPKE_KEM_P384_HKDF_SHA384"
dhkemp384hkdfsha384.dhKemBase.Hash = crypto.SHA384
dhkemp384hkdfsha384.dhKemBase.dhKEM = dhkemp384hkdfsha384
dhkemp521hkdfsha512.Curve = elliptic.P521()
dhkemp521hkdfsha512.dhKemBase.id = KEM_P521_HKDF_SHA512
dhkemp521hkdfsha512.dhKemBase.name = "HPKE_KEM_P521_HKDF_SHA512"
dhkemp521hkdfsha512.dhKemBase.Hash = crypto.SHA512
dhkemp521hkdfsha512.dhKemBase.dhKEM = dhkemp521hkdfsha512
dhkemx25519hkdfsha256.size = x25519.Size
dhkemx25519hkdfsha256.dhKemBase.id = KEM_X25519_HKDF_SHA256
dhkemx25519hkdfsha256.dhKemBase.name = "HPKE_KEM_X25519_HKDF_SHA256"
dhkemx25519hkdfsha256.dhKemBase.Hash = crypto.SHA256
dhkemx25519hkdfsha256.dhKemBase.dhKEM = dhkemx25519hkdfsha256
dhkemx448hkdfsha512.size = x448.Size
dhkemx448hkdfsha512.dhKemBase.id = KEM_X448_HKDF_SHA512
dhkemx448hkdfsha512.dhKemBase.name = "HPKE_KEM_X448_HKDF_SHA512"
dhkemx448hkdfsha512.dhKemBase.Hash = crypto.SHA512
dhkemx448hkdfsha512.dhKemBase.dhKEM = dhkemx448hkdfsha512
hybridkemX25519Kyber768.kemBase.id = KEM_X25519_KYBER768_DRAFT00
hybridkemX25519Kyber768.kemBase.name = "HPKE_KEM_X25519_KYBER768_HKDF_SHA256"
hybridkemX25519Kyber768.kemBase.Hash = crypto.SHA256
hybridkemX25519Kyber768.kemA = dhkemx25519hkdfsha256
hybridkemX25519Kyber768.kemB = kyber768.Scheme()
}