1
2
3
4
5 package hpke
6
7 import (
8 "bytes"
9 "crypto"
10 "crypto/ecdh"
11 "crypto/fips140"
12 "crypto/internal/fips140/drbg"
13 "crypto/internal/rand"
14 "crypto/mlkem"
15 "crypto/sha3"
16 "errors"
17 "internal/byteorder"
18 )
19
20 var mlkem768X25519 = &hybridKEM{
21 id: 0x647a,
22 label: `\./` +
23 `/^\`,
24 curve: ecdh.X25519(),
25
26 curveSeedSize: 32,
27 curvePointSize: 32,
28 pqEncapsKeySize: mlkem.EncapsulationKeySize768,
29 pqCiphertextSize: mlkem.CiphertextSize768,
30
31 pqNewPublicKey: func(data []byte) (crypto.Encapsulator, error) {
32 return mlkem.NewEncapsulationKey768(data)
33 },
34 pqNewPrivateKey: func(data []byte) (crypto.Decapsulator, error) {
35 return mlkem.NewDecapsulationKey768(data)
36 },
37 }
38
39
40
41 func MLKEM768X25519() KEM {
42 return mlkem768X25519
43 }
44
45 var mlkem768P256 = &hybridKEM{
46 id: 0x0050,
47 label: "MLKEM768-P256",
48 curve: ecdh.P256(),
49
50 curveSeedSize: 32,
51 curvePointSize: 65,
52 pqEncapsKeySize: mlkem.EncapsulationKeySize768,
53 pqCiphertextSize: mlkem.CiphertextSize768,
54
55 pqNewPublicKey: func(data []byte) (crypto.Encapsulator, error) {
56 return mlkem.NewEncapsulationKey768(data)
57 },
58 pqNewPrivateKey: func(data []byte) (crypto.Decapsulator, error) {
59 return mlkem.NewDecapsulationKey768(data)
60 },
61 }
62
63
64 func MLKEM768P256() KEM {
65 return mlkem768P256
66 }
67
68 var mlkem1024P384 = &hybridKEM{
69 id: 0x0051,
70 label: "MLKEM1024-P384",
71 curve: ecdh.P384(),
72
73 curveSeedSize: 48,
74 curvePointSize: 97,
75 pqEncapsKeySize: mlkem.EncapsulationKeySize1024,
76 pqCiphertextSize: mlkem.CiphertextSize1024,
77
78 pqNewPublicKey: func(data []byte) (crypto.Encapsulator, error) {
79 return mlkem.NewEncapsulationKey1024(data)
80 },
81 pqNewPrivateKey: func(data []byte) (crypto.Decapsulator, error) {
82 return mlkem.NewDecapsulationKey1024(data)
83 },
84 }
85
86
87 func MLKEM1024P384() KEM {
88 return mlkem1024P384
89 }
90
91 type hybridKEM struct {
92 id uint16
93 label string
94 curve ecdh.Curve
95
96 curveSeedSize int
97 curvePointSize int
98 pqEncapsKeySize int
99 pqCiphertextSize int
100
101 pqNewPublicKey func(data []byte) (crypto.Encapsulator, error)
102 pqNewPrivateKey func(data []byte) (crypto.Decapsulator, error)
103 }
104
105 func (kem *hybridKEM) ID() uint16 {
106 return kem.id
107 }
108
109 func (kem *hybridKEM) encSize() int {
110 return kem.pqCiphertextSize + kem.curvePointSize
111 }
112
113 func (kem *hybridKEM) sharedSecret(ssPQ, ssT, ctT, ekT []byte) []byte {
114 h := sha3.New256()
115 h.Write(ssPQ)
116 h.Write(ssT)
117 h.Write(ctT)
118 h.Write(ekT)
119 h.Write([]byte(kem.label))
120 return h.Sum(nil)
121 }
122
123 type hybridPublicKey struct {
124 kem *hybridKEM
125 t *ecdh.PublicKey
126 pq crypto.Encapsulator
127 }
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142 func NewHybridPublicKey(pq crypto.Encapsulator, t *ecdh.PublicKey) (PublicKey, error) {
143 switch t.Curve() {
144 case ecdh.X25519():
145 if _, ok := pq.(*mlkem.EncapsulationKey768); !ok {
146 return nil, errors.New("invalid PQ KEM for X25519 hybrid")
147 }
148 return &hybridPublicKey{mlkem768X25519, t, pq}, nil
149 case ecdh.P256():
150 if _, ok := pq.(*mlkem.EncapsulationKey768); !ok {
151 return nil, errors.New("invalid PQ KEM for P-256 hybrid")
152 }
153 return &hybridPublicKey{mlkem768P256, t, pq}, nil
154 case ecdh.P384():
155 if _, ok := pq.(*mlkem.EncapsulationKey1024); !ok {
156 return nil, errors.New("invalid PQ KEM for P-384 hybrid")
157 }
158 return &hybridPublicKey{mlkem1024P384, t, pq}, nil
159 default:
160 return nil, errors.New("unsupported curve")
161 }
162 }
163
164 func (kem *hybridKEM) NewPublicKey(data []byte) (PublicKey, error) {
165 if len(data) != kem.pqEncapsKeySize+kem.curvePointSize {
166 return nil, errors.New("invalid public key size")
167 }
168 pq, err := kem.pqNewPublicKey(data[:kem.pqEncapsKeySize])
169 if err != nil {
170 return nil, err
171 }
172 var k *ecdh.PublicKey
173 fips140.WithoutEnforcement(func() {
174 k, err = kem.curve.NewPublicKey(data[kem.pqEncapsKeySize:])
175 })
176 if err != nil {
177 return nil, err
178 }
179 return NewHybridPublicKey(pq, k)
180 }
181
182 func (pk *hybridPublicKey) KEM() KEM {
183 return pk.kem
184 }
185
186 func (pk *hybridPublicKey) Bytes() []byte {
187 return append(pk.pq.Bytes(), pk.t.Bytes()...)
188 }
189
190 var testingOnlyEncapsulate func() (ss, ct []byte)
191
192 func (pk *hybridPublicKey) encap() (sharedSecret []byte, encapPub []byte, err error) {
193 var skE *ecdh.PrivateKey
194 fips140.WithoutEnforcement(func() {
195 skE, err = pk.t.Curve().GenerateKey(rand.Reader)
196 })
197 if err != nil {
198 return nil, nil, err
199 }
200 if testingOnlyGenerateKey != nil {
201 skE = testingOnlyGenerateKey()
202 }
203 var ssT []byte
204 fips140.WithoutEnforcement(func() {
205 ssT, err = skE.ECDH(pk.t)
206 })
207 if err != nil {
208 return nil, nil, err
209 }
210 ctT := skE.PublicKey().Bytes()
211
212 ssPQ, ctPQ := pk.pq.Encapsulate()
213 if testingOnlyEncapsulate != nil {
214 ssPQ, ctPQ = testingOnlyEncapsulate()
215 }
216
217 ss := pk.kem.sharedSecret(ssPQ, ssT, ctT, pk.t.Bytes())
218 ct := append(ctPQ, ctT...)
219 return ss, ct, nil
220 }
221
222 type hybridPrivateKey struct {
223 kem *hybridKEM
224 seed []byte
225 t ecdh.KeyExchanger
226 pq crypto.Decapsulator
227 }
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 func NewHybridPrivateKey(pq crypto.Decapsulator, t ecdh.KeyExchanger) (PrivateKey, error) {
245 return newHybridPrivateKey(pq, t, nil)
246 }
247
248 func (kem *hybridKEM) GenerateKey() (PrivateKey, error) {
249 seed := make([]byte, 32)
250 drbg.Read(seed)
251 return kem.NewPrivateKey(seed)
252 }
253
254 func (kem *hybridKEM) NewPrivateKey(priv []byte) (PrivateKey, error) {
255 if len(priv) != 32 {
256 return nil, errors.New("hpke: invalid hybrid KEM secret length")
257 }
258
259 s := sha3.NewSHAKE256()
260 s.Write(priv)
261
262 seedPQ := make([]byte, mlkem.SeedSize)
263 s.Read(seedPQ)
264 pq, err := kem.pqNewPrivateKey(seedPQ)
265 if err != nil {
266 return nil, err
267 }
268
269 seedT := make([]byte, kem.curveSeedSize)
270 for {
271 s.Read(seedT)
272 var k ecdh.KeyExchanger
273 fips140.WithoutEnforcement(func() {
274 k, err = kem.curve.NewPrivateKey(seedT)
275 })
276 if err != nil {
277 continue
278 }
279 return newHybridPrivateKey(pq, k, priv)
280 }
281 }
282
283 func newHybridPrivateKey(pq crypto.Decapsulator, t ecdh.KeyExchanger, seed []byte) (PrivateKey, error) {
284 switch t.Curve() {
285 case ecdh.X25519():
286 if _, ok := pq.Encapsulator().(*mlkem.EncapsulationKey768); !ok {
287 return nil, errors.New("invalid PQ KEM for X25519 hybrid")
288 }
289 return &hybridPrivateKey{mlkem768X25519, bytes.Clone(seed), t, pq}, nil
290 case ecdh.P256():
291 if _, ok := pq.Encapsulator().(*mlkem.EncapsulationKey768); !ok {
292 return nil, errors.New("invalid PQ KEM for P-256 hybrid")
293 }
294 return &hybridPrivateKey{mlkem768P256, bytes.Clone(seed), t, pq}, nil
295 case ecdh.P384():
296 if _, ok := pq.Encapsulator().(*mlkem.EncapsulationKey1024); !ok {
297 return nil, errors.New("invalid PQ KEM for P-384 hybrid")
298 }
299 return &hybridPrivateKey{mlkem1024P384, bytes.Clone(seed), t, pq}, nil
300 default:
301 return nil, errors.New("unsupported curve")
302 }
303 }
304
305 func (kem *hybridKEM) DeriveKeyPair(ikm []byte) (PrivateKey, error) {
306 suiteID := byteorder.BEAppendUint16([]byte("KEM"), kem.id)
307 dk, err := SHAKE256().labeledDerive(suiteID, ikm, "DeriveKeyPair", nil, 32)
308 if err != nil {
309 return nil, err
310 }
311 return kem.NewPrivateKey(dk)
312 }
313
314 func (k *hybridPrivateKey) KEM() KEM {
315 return k.kem
316 }
317
318 func (k *hybridPrivateKey) Bytes() ([]byte, error) {
319 if k.seed == nil {
320 return nil, errors.New("private key seed not available")
321 }
322 return k.seed, nil
323 }
324
325 func (k *hybridPrivateKey) PublicKey() PublicKey {
326 return &hybridPublicKey{
327 kem: k.kem,
328 t: k.t.PublicKey(),
329 pq: k.pq.Encapsulator(),
330 }
331 }
332
333 func (k *hybridPrivateKey) decap(enc []byte) ([]byte, error) {
334 if len(enc) != k.kem.pqCiphertextSize+k.kem.curvePointSize {
335 return nil, errors.New("invalid encapsulated key size")
336 }
337 ctPQ, ctT := enc[:k.kem.pqCiphertextSize], enc[k.kem.pqCiphertextSize:]
338 ssPQ, err := k.pq.Decapsulate(ctPQ)
339 if err != nil {
340 return nil, err
341 }
342 var pub *ecdh.PublicKey
343 fips140.WithoutEnforcement(func() {
344 pub, err = k.t.Curve().NewPublicKey(ctT)
345 })
346 if err != nil {
347 return nil, err
348 }
349 var ssT []byte
350 fips140.WithoutEnforcement(func() {
351 ssT, err = k.t.ECDH(pub)
352 })
353 if err != nil {
354 return nil, err
355 }
356 ss := k.kem.sharedSecret(ssPQ, ssT, ctT, k.t.PublicKey().Bytes())
357 return ss, nil
358 }
359
360 var mlkem768 = &mlkemKEM{
361 id: 0x0041,
362 ciphertextSize: mlkem.CiphertextSize768,
363 newPublicKey: func(data []byte) (crypto.Encapsulator, error) {
364 return mlkem.NewEncapsulationKey768(data)
365 },
366 newPrivateKey: func(data []byte) (crypto.Decapsulator, error) {
367 return mlkem.NewDecapsulationKey768(data)
368 },
369 generateKey: func() (crypto.Decapsulator, error) {
370 return mlkem.GenerateKey768()
371 },
372 }
373
374
375 func MLKEM768() KEM {
376 return mlkem768
377 }
378
379 var mlkem1024 = &mlkemKEM{
380 id: 0x0042,
381 ciphertextSize: mlkem.CiphertextSize1024,
382 newPublicKey: func(data []byte) (crypto.Encapsulator, error) {
383 return mlkem.NewEncapsulationKey1024(data)
384 },
385 newPrivateKey: func(data []byte) (crypto.Decapsulator, error) {
386 return mlkem.NewDecapsulationKey1024(data)
387 },
388 generateKey: func() (crypto.Decapsulator, error) {
389 return mlkem.GenerateKey1024()
390 },
391 }
392
393
394 func MLKEM1024() KEM {
395 return mlkem1024
396 }
397
398 type mlkemKEM struct {
399 id uint16
400 ciphertextSize int
401 newPublicKey func(data []byte) (crypto.Encapsulator, error)
402 newPrivateKey func(data []byte) (crypto.Decapsulator, error)
403 generateKey func() (crypto.Decapsulator, error)
404 }
405
406 func (kem *mlkemKEM) ID() uint16 {
407 return kem.id
408 }
409
410 func (kem *mlkemKEM) encSize() int {
411 return kem.ciphertextSize
412 }
413
414 type mlkemPublicKey struct {
415 kem *mlkemKEM
416 pq crypto.Encapsulator
417 }
418
419
420
421
422
423
424
425
426
427
428
429
430 func NewMLKEMPublicKey(pub crypto.Encapsulator) (PublicKey, error) {
431 switch pub.(type) {
432 case *mlkem.EncapsulationKey768:
433 return &mlkemPublicKey{mlkem768, pub}, nil
434 case *mlkem.EncapsulationKey1024:
435 return &mlkemPublicKey{mlkem1024, pub}, nil
436 default:
437 return nil, errors.New("unsupported public key type")
438 }
439 }
440
441 func (kem *mlkemKEM) NewPublicKey(data []byte) (PublicKey, error) {
442 pq, err := kem.newPublicKey(data)
443 if err != nil {
444 return nil, err
445 }
446 return NewMLKEMPublicKey(pq)
447 }
448
449 func (pk *mlkemPublicKey) KEM() KEM {
450 return pk.kem
451 }
452
453 func (pk *mlkemPublicKey) Bytes() []byte {
454 return pk.pq.Bytes()
455 }
456
457 func (pk *mlkemPublicKey) encap() (sharedSecret []byte, encapPub []byte, err error) {
458 ss, ct := pk.pq.Encapsulate()
459 if testingOnlyEncapsulate != nil {
460 ss, ct = testingOnlyEncapsulate()
461 }
462 return ss, ct, nil
463 }
464
465 type mlkemPrivateKey struct {
466 kem *mlkemKEM
467 pq crypto.Decapsulator
468 }
469
470
471
472
473
474
475
476
477
478
479
480
481 func NewMLKEMPrivateKey(priv crypto.Decapsulator) (PrivateKey, error) {
482 switch priv.Encapsulator().(type) {
483 case *mlkem.EncapsulationKey768:
484 return &mlkemPrivateKey{mlkem768, priv}, nil
485 case *mlkem.EncapsulationKey1024:
486 return &mlkemPrivateKey{mlkem1024, priv}, nil
487 default:
488 return nil, errors.New("unsupported public key type")
489 }
490 }
491
492 func (kem *mlkemKEM) GenerateKey() (PrivateKey, error) {
493 pq, err := kem.generateKey()
494 if err != nil {
495 return nil, err
496 }
497 return NewMLKEMPrivateKey(pq)
498 }
499
500 func (kem *mlkemKEM) NewPrivateKey(priv []byte) (PrivateKey, error) {
501 pq, err := kem.newPrivateKey(priv)
502 if err != nil {
503 return nil, err
504 }
505 return NewMLKEMPrivateKey(pq)
506 }
507
508 func (kem *mlkemKEM) DeriveKeyPair(ikm []byte) (PrivateKey, error) {
509 suiteID := byteorder.BEAppendUint16([]byte("KEM"), kem.id)
510 dk, err := SHAKE256().labeledDerive(suiteID, ikm, "DeriveKeyPair", nil, 64)
511 if err != nil {
512 return nil, err
513 }
514 return kem.NewPrivateKey(dk)
515 }
516
517 func (k *mlkemPrivateKey) KEM() KEM {
518 return k.kem
519 }
520
521 func (k *mlkemPrivateKey) Bytes() ([]byte, error) {
522 pq, ok := k.pq.(interface {
523 Bytes() []byte
524 })
525 if !ok {
526 return nil, errors.New("private key seed not available")
527 }
528 return pq.Bytes(), nil
529 }
530
531 func (k *mlkemPrivateKey) PublicKey() PublicKey {
532 return &mlkemPublicKey{
533 kem: k.kem,
534 pq: k.pq.Encapsulator(),
535 }
536 }
537
538 func (k *mlkemPrivateKey) decap(enc []byte) ([]byte, error) {
539 return k.pq.Decapsulate(enc)
540 }
541
View as plain text