cfkem.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. // Copyright 2022 Cloudflare, Inc. All rights reserved. Use of this source code
  2. // is governed by a BSD-style license that can be found in the LICENSE file.
  3. //
  4. // Glue to add Circl's (post-quantum) hybrid KEMs.
  5. //
  6. // To enable set CurvePreferences with the desired scheme as the first element:
  7. //
  8. // import (
  9. // "github.com/cloudflare/circl/kem/tls"
  10. // "github.com/cloudflare/circl/kem/hybrid"
  11. //
  12. // [...]
  13. //
  14. // config.CurvePreferences = []tls.CurveID{
  15. // hybrid.X25519Kyber512Draft00().(tls.TLSScheme).TLSCurveID(),
  16. // tls.X25519,
  17. // tls.P256,
  18. // }
  19. package tls
  20. import (
  21. "fmt"
  22. "io"
  23. "github.com/cloudflare/circl/kem"
  24. "github.com/cloudflare/circl/kem/hybrid"
  25. )
  26. // Either ecdheParameters or kem.PrivateKey
  27. type clientKeySharePrivate interface{}
  28. var (
  29. X25519Kyber512Draft00 = CurveID(0xfe30)
  30. X25519Kyber768Draft00 = CurveID(0xfe31)
  31. invalidCurveID = CurveID(0)
  32. )
  33. func kemSchemeKeyToCurveID(s kem.Scheme) CurveID {
  34. switch s.Name() {
  35. case "Kyber512-X25519":
  36. return X25519Kyber512Draft00
  37. case "Kyber768-X25519":
  38. return X25519Kyber768Draft00
  39. default:
  40. return invalidCurveID
  41. }
  42. }
  43. // Extract CurveID from clientKeySharePrivate
  44. func clientKeySharePrivateCurveID(ks clientKeySharePrivate) CurveID {
  45. switch v := ks.(type) {
  46. case kem.PrivateKey:
  47. ret := kemSchemeKeyToCurveID(v.Scheme())
  48. if ret == invalidCurveID {
  49. panic("cfkem: internal error: don't know CurveID for this KEM")
  50. }
  51. return ret
  52. case ecdheParameters:
  53. return v.CurveID()
  54. default:
  55. panic("cfkem: internal error: unknown clientKeySharePrivate")
  56. }
  57. }
  58. // Returns scheme by CurveID if supported by Circl
  59. func curveIdToCirclScheme(id CurveID) kem.Scheme {
  60. switch id {
  61. case X25519Kyber512Draft00:
  62. return hybrid.Kyber512X25519()
  63. case X25519Kyber768Draft00:
  64. return hybrid.Kyber768X25519()
  65. }
  66. return nil
  67. }
  68. // Generate a new shared secret and encapsulates it for the packed
  69. // public key in ppk using randomness from rnd.
  70. func encapsulateForKem(scheme kem.Scheme, rnd io.Reader, ppk []byte) (
  71. ct, ss []byte, alert alert, err error,
  72. ) {
  73. pk, err := scheme.UnmarshalBinaryPublicKey(ppk)
  74. if err != nil {
  75. return nil, nil, alertIllegalParameter, fmt.Errorf("unpack pk: %w", err)
  76. }
  77. seed := make([]byte, scheme.EncapsulationSeedSize())
  78. if _, err := io.ReadFull(rnd, seed); err != nil {
  79. return nil, nil, alertInternalError, fmt.Errorf("random: %w", err)
  80. }
  81. ct, ss, err = scheme.EncapsulateDeterministically(pk, seed)
  82. return ct, ss, alertIllegalParameter, err
  83. }
  84. // Generate a new keypair using randomness from rnd.
  85. func generateKemKeyPair(scheme kem.Scheme, rnd io.Reader) (
  86. kem.PublicKey, kem.PrivateKey, error,
  87. ) {
  88. seed := make([]byte, scheme.SeedSize())
  89. if _, err := io.ReadFull(rnd, seed); err != nil {
  90. return nil, nil, err
  91. }
  92. pk, sk := scheme.DeriveKeyPair(seed)
  93. return pk, sk, nil
  94. }