@@ -53,9 +53,68 @@ pub fn hkdf(salt: &[u8], label: &[u8], ikm: &[u8]) -> [u8; 32] {
5353 okm
5454}
5555
56+ /// `HPKE.SealBase(pk_recip, info, aad = "", plaintext)`
57+ ///
58+ /// HPKE from [RFC 9180] with:
59+ /// - KDF: HKDF-SHA256
60+ /// - AEAD: ChaCha20Poly1305
61+ /// - `aad = ""` (empty)
62+ ///
63+ /// # Panics
64+ ///
65+ /// Panics if the configured `Kem` produces an error. The native age recipient types that
66+ /// use HPKE are configured with parameters that ensure errors either cannot occur or are
67+ /// cryptographically negligible. If you are using this method for an age plugin, ensure
68+ /// that you choose a KEM with equivalent properties.
69+ ///
70+ /// [RFC 9180]: https://tools.ietf.org/html/rfc9180
71+ pub fn hpke_seal < Kem : hpke:: Kem , R : rand:: RngCore + rand:: CryptoRng > (
72+ pk_recip : & Kem :: PublicKey ,
73+ info : & [ u8 ] ,
74+ plaintext : & [ u8 ] ,
75+ rng : & mut R ,
76+ ) -> ( Kem :: EncappedKey , Vec < u8 > ) {
77+ hpke:: single_shot_seal :: < hpke:: aead:: ChaCha20Poly1305 , hpke:: kdf:: HkdfSha256 , Kem , R > (
78+ & hpke:: OpModeS :: Base ,
79+ pk_recip,
80+ info,
81+ plaintext,
82+ & [ ] ,
83+ rng,
84+ )
85+ . expect ( "no errors should occur with these HPKE parameters" )
86+ }
87+
88+ /// `HPKE.OpenBase(enc, sk_recip, info, aad = "", ciphertext)`
89+ ///
90+ /// HPKE from [RFC 9180] with:
91+ /// - KDF: HKDF-SHA256
92+ /// - AEAD: ChaCha20Poly1305
93+ /// - `aad = ""` (empty)
94+ ///
95+ /// [RFC 9180]: https://tools.ietf.org/html/rfc9180
96+ pub fn hpke_open < Kem : hpke:: Kem > (
97+ encapped_key : & Kem :: EncappedKey ,
98+ sk_recip : & Kem :: PrivateKey ,
99+ info : & [ u8 ] ,
100+ ciphertext : & [ u8 ] ,
101+ ) -> Result < Vec < u8 > , hpke:: HpkeError > {
102+ hpke:: single_shot_open :: < hpke:: aead:: ChaCha20Poly1305 , hpke:: kdf:: HkdfSha256 , Kem > (
103+ & hpke:: OpModeR :: Base ,
104+ sk_recip,
105+ encapped_key,
106+ info,
107+ ciphertext,
108+ & [ ] ,
109+ )
110+ }
111+
56112#[ cfg( test) ]
57113mod tests {
58- use super :: { aead_decrypt, aead_encrypt} ;
114+ use hpke:: Kem ;
115+ use rand:: rngs:: OsRng ;
116+
117+ use super :: { aead_decrypt, aead_encrypt, hpke_open, hpke_seal} ;
59118
60119 #[ test]
61120 fn aead_round_trip ( ) {
@@ -65,4 +124,20 @@ mod tests {
65124 let decrypted = aead_decrypt ( & key, plaintext. len ( ) , & encrypted) . unwrap ( ) ;
66125 assert_eq ! ( decrypted, plaintext) ;
67126 }
127+
128+ #[ test]
129+ fn hpke_round_trip ( ) {
130+ type Kem = hpke:: kem:: DhP256HkdfSha256 ;
131+ let mut rng = OsRng ;
132+
133+ let ( sk_recip, pk_recip) = Kem :: gen_keypair ( & mut rng) ;
134+
135+ let info = b"foobar" ;
136+ let plaintext = b"12345678" ;
137+
138+ let ( encapped_key, ciphertext) = hpke_seal :: < Kem , _ > ( & pk_recip, info, plaintext, & mut rng) ;
139+ let decrypted = hpke_open :: < Kem > ( & encapped_key, & sk_recip, info, & ciphertext) . unwrap ( ) ;
140+
141+ assert_eq ! ( decrypted, plaintext) ;
142+ }
68143}
0 commit comments