hpke.go 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. // Package hpke implements the Hybrid Public Key Encryption (HPKE) standard
  2. // specified by draft-irtf-cfrg-hpke-07.
  3. //
  4. // HPKE works for any combination of a public-key encapsulation mechanism
  5. // (KEM), a key derivation function (KDF), and an authenticated encryption
  6. // scheme with additional data (AEAD).
  7. //
  8. // Specification in
  9. // https://datatracker.ietf.org/doc/draft-irtf-cfrg-hpke
  10. //
  11. // BUG(cjpatton): This package does not implement the "Export-Only" mode of the
  12. // HPKE context. In particular, it does not recognize the AEAD codepoint
  13. // reserved for this purpose (0xFFFF).
  14. package hpke
  15. import (
  16. "crypto/rand"
  17. "encoding"
  18. "errors"
  19. "io"
  20. "github.com/cloudflare/circl/kem"
  21. )
  22. const versionLabel = "HPKE-v1"
  23. // Context defines the capabilities of an HPKE context.
  24. type Context interface {
  25. encoding.BinaryMarshaler
  26. // Export takes a context string exporterContext and a desired length (in
  27. // bytes), and produces a secret derived from the internal exporter secret
  28. // using the corresponding KDF Expand function. It panics if length is
  29. // greater than 255*N bytes, where N is the size (in bytes) of the KDF's
  30. // output.
  31. Export(exporterContext []byte, length uint) []byte
  32. // Suite returns the cipher suite corresponding to this context.
  33. Suite() Suite
  34. }
  35. // Sealer encrypts a plaintext using an AEAD encryption.
  36. type Sealer interface {
  37. Context
  38. // Seal takes a plaintext and associated data to produce a ciphertext.
  39. // The nonce is handled by the Sealer and incremented after each call.
  40. Seal(pt, aad []byte) (ct []byte, err error)
  41. }
  42. // Opener decrypts a ciphertext using an AEAD encryption.
  43. type Opener interface {
  44. Context
  45. // Open takes a ciphertext and associated data to recover, if successful,
  46. // the plaintext. The nonce is handled by the Opener and incremented after
  47. // each call.
  48. Open(ct, aad []byte) (pt []byte, err error)
  49. }
  50. // modeID represents an HPKE variant.
  51. type modeID = uint8
  52. const (
  53. // modeBase to enable encryption to the holder of a given KEM private key.
  54. modeBase modeID = 0x00
  55. // modePSK extends the base mode by allowing the Receiver to authenticate
  56. // that the sender possessed a given pre-shared key (PSK).
  57. modePSK modeID = 0x01
  58. // modeAuth extends the base mode by allowing the Receiver to authenticate
  59. // that the sender possessed a given KEM private key.
  60. modeAuth modeID = 0x02
  61. // modeAuthPSK provides a combination of the PSK and Auth modes.
  62. modeAuthPSK modeID = 0x03
  63. )
  64. // Suite is an HPKE cipher suite consisting of a KEM, KDF, and AEAD algorithm.
  65. type Suite struct {
  66. kemID KEM
  67. kdfID KDF
  68. aeadID AEAD
  69. }
  70. // NewSuite builds a Suite from a specified set of algorithms. Panics
  71. // if an algorithm identifier is not valid.
  72. func NewSuite(kemID KEM, kdfID KDF, aeadID AEAD) Suite {
  73. s := Suite{kemID, kdfID, aeadID}
  74. if !s.isValid() {
  75. panic(ErrInvalidHPKESuite)
  76. }
  77. return s
  78. }
  79. type state struct {
  80. Suite
  81. modeID modeID
  82. skS kem.PrivateKey
  83. pkS kem.PublicKey
  84. psk []byte
  85. pskID []byte
  86. info []byte
  87. }
  88. // Sender performs hybrid public-key encryption.
  89. type Sender struct {
  90. state
  91. pkR kem.PublicKey
  92. }
  93. // NewSender creates a Sender with knowledge of the receiver's public-key.
  94. func (suite Suite) NewSender(pkR kem.PublicKey, info []byte) (*Sender, error) {
  95. return &Sender{
  96. state: state{Suite: suite, info: info},
  97. pkR: pkR,
  98. }, nil
  99. }
  100. // Setup generates a new HPKE context used for Base Mode encryption.
  101. // Returns the Sealer and corresponding encapsulated key.
  102. func (s *Sender) Setup(rnd io.Reader) (enc []byte, seal Sealer, err error) {
  103. s.modeID = modeBase
  104. return s.allSetup(rnd)
  105. }
  106. // SetupAuth generates a new HPKE context used for Auth Mode encryption.
  107. // Returns the Sealer and corresponding encapsulated key.
  108. func (s *Sender) SetupAuth(rnd io.Reader, skS kem.PrivateKey) (
  109. enc []byte, seal Sealer, err error,
  110. ) {
  111. s.modeID = modeAuth
  112. s.state.skS = skS
  113. return s.allSetup(rnd)
  114. }
  115. // SetupPSK generates a new HPKE context used for PSK Mode encryption.
  116. // Returns the Sealer and corresponding encapsulated key.
  117. func (s *Sender) SetupPSK(rnd io.Reader, psk, pskID []byte) (
  118. enc []byte, seal Sealer, err error,
  119. ) {
  120. s.modeID = modePSK
  121. s.state.psk = psk
  122. s.state.pskID = pskID
  123. return s.allSetup(rnd)
  124. }
  125. // SetupAuthPSK generates a new HPKE context used for Auth-PSK Mode encryption.
  126. // Returns the Sealer and corresponding encapsulated key.
  127. func (s *Sender) SetupAuthPSK(rnd io.Reader, skS kem.PrivateKey, psk, pskID []byte) (
  128. enc []byte, seal Sealer, err error,
  129. ) {
  130. s.modeID = modeAuthPSK
  131. s.state.skS = skS
  132. s.state.psk = psk
  133. s.state.pskID = pskID
  134. return s.allSetup(rnd)
  135. }
  136. // Receiver performs hybrid public-key decryption.
  137. type Receiver struct {
  138. state
  139. skR kem.PrivateKey
  140. enc []byte
  141. }
  142. // NewReceiver creates a Receiver with knowledge of a private key.
  143. func (suite Suite) NewReceiver(skR kem.PrivateKey, info []byte) (
  144. *Receiver, error,
  145. ) {
  146. return &Receiver{state: state{Suite: suite, info: info}, skR: skR}, nil
  147. }
  148. // Setup generates a new HPKE context used for Base Mode encryption.
  149. // Setup takes an encapsulated key and returns an Opener.
  150. func (r *Receiver) Setup(enc []byte) (Opener, error) {
  151. r.modeID = modeBase
  152. r.enc = enc
  153. return r.allSetup()
  154. }
  155. // SetupAuth generates a new HPKE context used for Auth Mode encryption.
  156. // SetupAuth takes an encapsulated key and a public key, and returns an Opener.
  157. func (r *Receiver) SetupAuth(enc []byte, pkS kem.PublicKey) (Opener, error) {
  158. r.modeID = modeAuth
  159. r.enc = enc
  160. r.state.pkS = pkS
  161. return r.allSetup()
  162. }
  163. // SetupPSK generates a new HPKE context used for PSK Mode encryption.
  164. // SetupPSK takes an encapsulated key, and a pre-shared key; and returns an
  165. // Opener.
  166. func (r *Receiver) SetupPSK(enc, psk, pskID []byte) (Opener, error) {
  167. r.modeID = modePSK
  168. r.enc = enc
  169. r.state.psk = psk
  170. r.state.pskID = pskID
  171. return r.allSetup()
  172. }
  173. // SetupAuthPSK generates a new HPKE context used for Auth-PSK Mode encryption.
  174. // SetupAuthPSK takes an encapsulated key, a public key, and a pre-shared key;
  175. // and returns an Opener.
  176. func (r *Receiver) SetupAuthPSK(
  177. enc, psk, pskID []byte, pkS kem.PublicKey,
  178. ) (Opener, error) {
  179. r.modeID = modeAuthPSK
  180. r.enc = enc
  181. r.state.psk = psk
  182. r.state.pskID = pskID
  183. r.state.pkS = pkS
  184. return r.allSetup()
  185. }
  186. func (s *Sender) allSetup(rnd io.Reader) ([]byte, Sealer, error) {
  187. scheme := s.kemID.Scheme()
  188. if rnd == nil {
  189. rnd = rand.Reader
  190. }
  191. seed := make([]byte, scheme.EncapsulationSeedSize())
  192. _, err := io.ReadFull(rnd, seed)
  193. if err != nil {
  194. return nil, nil, err
  195. }
  196. var enc, ss []byte
  197. switch s.modeID {
  198. case modeBase, modePSK:
  199. enc, ss, err = scheme.EncapsulateDeterministically(s.pkR, seed)
  200. case modeAuth, modeAuthPSK:
  201. enc, ss, err = scheme.AuthEncapsulateDeterministically(s.pkR, s.skS, seed)
  202. }
  203. if err != nil {
  204. return nil, nil, err
  205. }
  206. ctx, err := s.keySchedule(ss, s.info, s.psk, s.pskID)
  207. if err != nil {
  208. return nil, nil, err
  209. }
  210. return enc, &sealContext{ctx}, nil
  211. }
  212. func (r *Receiver) allSetup() (Opener, error) {
  213. var err error
  214. var ss []byte
  215. scheme := r.kemID.Scheme()
  216. switch r.modeID {
  217. case modeBase, modePSK:
  218. ss, err = scheme.Decapsulate(r.skR, r.enc)
  219. case modeAuth, modeAuthPSK:
  220. ss, err = scheme.AuthDecapsulate(r.skR, r.enc, r.pkS)
  221. }
  222. if err != nil {
  223. return nil, err
  224. }
  225. ctx, err := r.keySchedule(ss, r.info, r.psk, r.pskID)
  226. if err != nil {
  227. return nil, err
  228. }
  229. return &openContext{ctx}, nil
  230. }
  231. var (
  232. ErrInvalidHPKESuite = errors.New("hpke: invalid HPKE suite")
  233. ErrInvalidKDF = errors.New("hpke: invalid KDF identifier")
  234. ErrInvalidKEM = errors.New("hpke: invalid KEM identifier")
  235. ErrInvalidAEAD = errors.New("hpke: invalid AEAD identifier")
  236. ErrInvalidKEMPublicKey = errors.New("hpke: invalid KEM public key")
  237. ErrInvalidKEMPrivateKey = errors.New("hpke: invalid KEM private key")
  238. ErrInvalidKEMSharedSecret = errors.New("hpke: invalid KEM shared secret")
  239. ErrAEADSeqOverflows = errors.New("hpke: AEAD sequence number overflows")
  240. )