File: algs.go

package info (click to toggle)
golang-github-cloudflare-circl 1.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 18,064 kB
  • sloc: asm: 20,492; ansic: 1,292; makefile: 68
file content (287 lines) | stat: -rw-r--r-- 8,183 bytes parent folder | download | duplicates (2)
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
279
280
281
282
283
284
285
286
287
package hpke

import (
	"crypto"
	"crypto/aes"
	"crypto/cipher"
	"crypto/ecdh"
	_ "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/kem"
	"github.com/cloudflare/circl/kem/kyber/kyber768"
	"github.com/cloudflare/circl/kem/xwing"
	"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
	// KEM_XWING is a hybrid KEM using X25519 and ML-KEM-768.
	KEM_XWING KEM = 0x647a
)

// 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,
		KEM_XWING:
		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.Scheme {
	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
	case KEM_XWING:
		return kemXwing
	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
	kemXwing                                                      genericNoAuthKEM
)

func init() {
	dhkemp256hkdfsha256.Curve = ecdh.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 = ecdh.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 = ecdh.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()

	kemXwing.Scheme = xwing.Scheme()
	kemXwing.name = "HPKE_KEM_XWING"
}