@@ -160,6 +160,20 @@ fn select_pk_for_encryption(key: &SignedPublicKey) -> Option<&SignedPublicSubKey
160160 . find ( |subkey| subkey. is_encryption_key ( ) )
161161}
162162
163+ /// Version of SEIPD packet to use.
164+ ///
165+ /// See
166+ /// <https://www.rfc-editor.org/rfc/rfc9580#name-avoiding-ciphertext-malleab>
167+ /// for the discussion on when v2 SEIPD should be used.
168+ #[ derive( Debug ) ]
169+ pub enum SeipdVersion {
170+ /// Use v1 SEIPD, for compatibility.
171+ V1 ,
172+
173+ /// Use v2 SEIPD when we know that v2 SEIPD is supported.
174+ V2 ,
175+ }
176+
163177/// Encrypts `plain` text using `public_keys_for_encryption`
164178/// and signs it using `private_key_for_signing`.
165179pub async fn pk_encrypt (
@@ -168,31 +182,63 @@ pub async fn pk_encrypt(
168182 private_key_for_signing : SignedSecretKey ,
169183 compress : bool ,
170184 anonymous_recipients : bool ,
185+ seipd_version : SeipdVersion ,
171186) -> Result < String > {
172187 Handle :: current ( )
173188 . spawn_blocking ( move || {
174189 let mut rng = thread_rng ( ) ;
175190
176- let pkeys = public_keys_for_encryption
177- . iter ( )
178- . filter_map ( select_pk_for_encryption) ;
179-
180191 let msg = MessageBuilder :: from_bytes ( "" , plain) ;
181- let mut msg = msg. seipd_v1 ( & mut rng, SYMMETRIC_KEY_ALGORITHM ) ;
182- for pkey in pkeys {
183- if anonymous_recipients {
184- msg. encrypt_to_key_anonymous ( & mut rng, & pkey) ?;
185- } else {
186- msg. encrypt_to_key ( & mut rng, & pkey) ?;
187- }
188- }
189192
190- msg. sign ( & * private_key_for_signing, Password :: empty ( ) , HASH_ALGORITHM ) ;
191- if compress {
192- msg. compression ( CompressionAlgorithm :: ZLIB ) ;
193- }
194-
195- let encoded_msg = msg. to_armored_string ( & mut rng, Default :: default ( ) ) ?;
193+ let encoded_msg = match seipd_version {
194+ SeipdVersion :: V1 => {
195+ let mut msg = msg. seipd_v1 ( & mut rng, SYMMETRIC_KEY_ALGORITHM ) ;
196+ let pkeys = public_keys_for_encryption
197+ . iter ( )
198+ . filter_map ( select_pk_for_encryption) ;
199+
200+ for pkey in pkeys {
201+ if anonymous_recipients {
202+ msg. encrypt_to_key_anonymous ( & mut rng, & pkey) ?;
203+ } else {
204+ msg. encrypt_to_key ( & mut rng, & pkey) ?;
205+ }
206+ }
207+
208+ msg. sign ( & * private_key_for_signing, Password :: empty ( ) , HASH_ALGORITHM ) ;
209+ if compress {
210+ msg. compression ( CompressionAlgorithm :: ZLIB ) ;
211+ }
212+
213+ msg. to_armored_string ( & mut rng, Default :: default ( ) ) ?
214+ }
215+ SeipdVersion :: V2 => {
216+ let mut msg = msg. seipd_v2 (
217+ & mut rng,
218+ SYMMETRIC_KEY_ALGORITHM ,
219+ AeadAlgorithm :: Ocb ,
220+ ChunkSize :: C8KiB ,
221+ ) ;
222+ let pkeys = public_keys_for_encryption
223+ . iter ( )
224+ . filter_map ( select_pk_for_encryption) ;
225+
226+ for pkey in pkeys {
227+ if anonymous_recipients {
228+ msg. encrypt_to_key_anonymous ( & mut rng, & pkey) ?;
229+ } else {
230+ msg. encrypt_to_key ( & mut rng, & pkey) ?;
231+ }
232+ }
233+
234+ msg. sign ( & * private_key_for_signing, Password :: empty ( ) , HASH_ALGORITHM ) ;
235+ if compress {
236+ msg. compression ( CompressionAlgorithm :: ZLIB ) ;
237+ }
238+
239+ msg. to_armored_string ( & mut rng, Default :: default ( ) ) ?
240+ }
241+ } ;
196242
197243 Ok ( encoded_msg)
198244 } )
@@ -547,6 +593,7 @@ mod tests {
547593 KEYS . alice_secret . clone ( ) ,
548594 compress,
549595 anonymous_recipients,
596+ SeipdVersion :: V2 ,
550597 )
551598 . await
552599 . unwrap ( )
@@ -716,6 +763,7 @@ mod tests {
716763 KEYS . alice_secret . clone ( ) ,
717764 true ,
718765 true ,
766+ SeipdVersion :: V2 ,
719767 )
720768 . await ?;
721769
0 commit comments