Lifetime are incorrectly set for Encryptor
Hello, I was using sequoia-opengpg and I noticed that some of the lifetime guarantees are a bit weird, in particular for encryptor.
Take this code snippet
pub fn encrypt_data<'a, B: AsRef<[u8]>, R>(data: B, recipients: R) -> anyhow::Result<Vec<u8>>
where
R: IntoIterator,
R::Item: Into<Recipient<'a>>,
{
let mut sink = vec![];
let message = Message::new(&mut sink);
let armorer = Armorer::new(message).build()?;
let encryptor = Encryptor::for_recipients(armorer, recipients).build()?;
let mut writer = LiteralWriter::new(encryptor).build()?;
writer.write_all(data.as_ref())?;
writer.finalize()?;
Ok(sink)
}
If you try to run it you will get that you can not return sink because it is still borrowed, however if you look closely the sink is borrowed as mutable in message which is then pass by value inside armorer, same in encryptor, same in writer and finally when writer.finalize() is called, w is consumed, so there is no mutable borrow left to sink. However there is still a lifetime issue, you see Encryptor is defined like so:
pub struct Encryptor<'a> {
inner: writer::BoxStack<'a, Cookie>,
session_key: Option<SessionKey>,
recipients: Vec<Recipient<'a>>,
passwords: Vec<Password>,
sym_algo: SymmetricAlgorithm,
aead_algo: Option<AEADAlgorithm>,
hash: Box<dyn crypto::hash::Digest>,
cookie: Cookie,
}
If you look closely you see that inner and recipients have the same lifetime, so you are bounding the writer to the recipients, however in a real use case, your recipients will outlive your writer, so the real lifetime are
pub struct Encryptor<'a, 'b> where 'b:'a {
inner: writer::BoxStack<'a, Cookie>,
session_key: Option<SessionKey>,
recipients: Vec<Recipient<'b>>,
passwords: Vec<Password>,
sym_algo: SymmetricAlgorithm,
aead_algo: Option<AEADAlgorithm>,
hash: Box<dyn crypto::hash::Digest>,
cookie: Cookie,
}
And if you do that then your method:
pub fn for_recipients<R>(inner: Message<'a>, recipients: R) -> Self
where R: IntoIterator,
R::Item: Into<Recipient<'a>>,
becomes
pub fn for_recipients<R>(inner: Message<'a>, recipients: R) -> Self
where R: IntoIterator,
R::Item: Into<Recipient<'b>>,
and suddenly the whole issue of tying unwillingly the lifetime of your message to your recipients just goes away.
Best regards