diff options
-rw-r--r-- | guide/src/chapter_02.md | 48 | ||||
-rw-r--r-- | ipc/tests/gpg-agent.rs | 11 | ||||
-rw-r--r-- | openpgp-ffi/src/serialize.rs | 34 | ||||
-rw-r--r-- | openpgp/examples/encrypt-for.rs | 14 | ||||
-rw-r--r-- | openpgp/examples/generate-encrypt-decrypt.rs | 12 | ||||
-rw-r--r-- | openpgp/examples/pad.rs | 13 | ||||
-rw-r--r-- | openpgp/src/autocrypt.rs | 5 | ||||
-rw-r--r-- | openpgp/src/serialize/stream.rs | 229 | ||||
-rw-r--r-- | tool/src/commands/mod.rs | 22 |
9 files changed, 243 insertions, 145 deletions
diff --git a/guide/src/chapter_02.md b/guide/src/chapter_02.md index d00fa669..acc2cb2e 100644 --- a/guide/src/chapter_02.md +++ b/guide/src/chapter_02.md @@ -50,7 +50,7 @@ fn main() { # fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. -# let recipients = +# let mut recipients = # recipient.keys_valid() # .key_flags(KeyFlags::default() # .set_encrypt_at_rest(true) @@ -62,10 +62,12 @@ fn main() { # let message = Message::new(sink); # # // We want to encrypt a literal data packet. -# let encryptor = Encryptor::new(message, -# &[], // No symmetric encryption. -# &recipients, -# None, None)?; +# let mut encryptor = Encryptor::for_recipient( +# message, recipients.pop().expect("No encryption key found")); +# for r in recipients { +# encryptor = encryptor.add_recipient(r) +# } +# let encryptor = encryptor.build().expect("Failed to create encryptor"); # # // Emit a literal data packet. # let mut literal_writer = LiteralWriter::new(encryptor).build()?; @@ -191,7 +193,7 @@ fn generate() -> openpgp::Result<openpgp::TPK> { # fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. -# let recipients = +# let mut recipients = # recipient.keys_valid() # .key_flags(KeyFlags::default() # .set_encrypt_at_rest(true) @@ -203,10 +205,12 @@ fn generate() -> openpgp::Result<openpgp::TPK> { # let message = Message::new(sink); # # // We want to encrypt a literal data packet. -# let encryptor = Encryptor::new(message, -# &[], // No symmetric encryption. -# &recipients, -# None, None)?; +# let mut encryptor = Encryptor::for_recipient( +# message, recipients.pop().expect("No encryption key found")); +# for r in recipients { +# encryptor = encryptor.add_recipient(r) +# } +# let encryptor = encryptor.build().expect("Failed to create encryptor"); # # // Emit a literal data packet. # let mut literal_writer = LiteralWriter::new(encryptor).build()?; @@ -332,7 +336,7 @@ implements [`io::Write`], and we simply write the plaintext to it. fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) -> openpgp::Result<()> { // Build a vector of recipients to hand to Encryptor. - let recipients = + let mut recipients = recipient.keys_valid() .key_flags(KeyFlags::default() .set_encrypt_at_rest(true) @@ -344,10 +348,12 @@ fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) let message = Message::new(sink); // We want to encrypt a literal data packet. - let encryptor = Encryptor::new(message, - &[], // No symmetric encryption. - &recipients, - None, None)?; + let mut encryptor = Encryptor::for_recipient( + message, recipients.pop().expect("No encryption key found")); + for r in recipients { + encryptor = encryptor.add_recipient(r) + } + let encryptor = encryptor.build().expect("Failed to create encryptor"); // Emit a literal data packet. let mut literal_writer = LiteralWriter::new(encryptor).build()?; @@ -487,7 +493,7 @@ Decrypted data can be read from this using [`io::Read`]. # fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::TPK) # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. -# let recipients = +# let mut recipients = # recipient.keys_valid() # .key_flags(KeyFlags::default() # .set_encrypt_at_rest(true) @@ -499,10 +505,12 @@ Decrypted data can be read from this using [`io::Read`]. # let message = Message::new(sink); # # // We want to encrypt a literal data packet. -# let encryptor = Encryptor::new(message, -# &[], // No symmetric encryption. -# &recipients, -# None, None)?; +# let mut encryptor = Encryptor::for_recipient( +# message, recipients.pop().expect("No encryption key found")); +# for r in recipients { +# encryptor = encryptor.add_recipient(r) +# } +# let encryptor = encryptor.build().expect("Failed to create encryptor"); # # // Emit a literal data packet. # let mut literal_writer = LiteralWriter::new(encryptor).build()?; diff --git a/ipc/tests/gpg-agent.rs b/ipc/tests/gpg-agent.rs index 2dd5bb2b..01adcc6f 100644 --- a/ipc/tests/gpg-agent.rs +++ b/ipc/tests/gpg-agent.rs @@ -207,21 +207,18 @@ fn decrypt() { let mut message = Vec::new(); { - // Build a vector of recipients to hand to Encryptor. - let recipients = + let recipient = tpk.keys_valid().key_flags( KeyFlags::default().set_encrypt_for_transport(true)) .map(|(_, _, key)| key.into()) - .collect::<Vec<Recipient>>(); + .nth(0).unwrap(); // Start streaming an OpenPGP message. let message = Message::new(&mut message); // We want to encrypt a literal data packet. - let encryptor = Encryptor::new(message, - &[], // No symmetric encryption. - recipients, - None, None).unwrap(); + let encryptor = + Encryptor::for_recipient(message, recipient).build().unwrap(); // Emit a literal data packet. let mut literal_writer = LiteralWriter::new( diff --git a/openpgp-ffi/src/serialize.rs b/openpgp-ffi/src/serialize.rs index 7046b667..d5d7afa6 100644 --- a/openpgp-ffi/src/serialize.rs +++ b/openpgp-ffi/src/serialize.rs @@ -309,6 +309,8 @@ fn pgp_recipients_from_key_iter<'a>( /// which will be encrypted using the given passwords, and all /// encryption-capable subkeys of the given TPKs. /// +/// The recipients are consumed. +/// /// The stream is encrypted using `cipher_algo`. Pass 0 for the /// default (which is what you usually want). #[::sequoia_ffi_macros::extern_fn] #[no_mangle] @@ -316,7 +318,7 @@ pub extern "C" fn pgp_encryptor_new<'a> (errp: Option<&mut *mut crate::error::Error>, inner: *mut writer::Stack<'a, Cookie>, passwords: Option<&*const c_char>, passwords_len: size_t, - recipients: Option<&*const Recipient<'a>>, recipients_len: size_t, + recipients: Option<&*mut Recipient<'a>>, recipients_len: size_t, cipher_algo: u8, aead_algo: u8) -> *mut writer::Stack<'a, Cookie> @@ -341,7 +343,7 @@ pub extern "C" fn pgp_encryptor_new<'a> slice::from_raw_parts(recipients, recipients_len) }; for recipient in recipients { - recipients_.push(recipient.ref_raw()); + recipients_.push(recipient.move_from_raw()); } }; let cipher_algo : Option<SymmetricAlgorithm> = if cipher_algo == 0 { @@ -354,9 +356,27 @@ pub extern "C" fn pgp_encryptor_new<'a> } else { Some(aead_algo.into()) }; - ffi_try_box!(Encryptor::new(*inner, - passwords_.iter().collect::<Vec<_>>(), - recipients_, - cipher_algo, - aead_algo)) + if passwords_.len() + recipients_.len() == 0 { + ffi_try!(Err(failure::format_err!( + "Neither recipient nor password given"))); + } + + let mut encryptor = if let Some(p) = passwords_.pop() { + Encryptor::with_password(*inner, p) + } else { + Encryptor::for_recipient(*inner, recipients_.pop().unwrap()) + }; + for p in passwords_ { + encryptor = encryptor.add_password(p); + } + for r in recipients_ { + encryptor = encryptor.add_recipient(r); + } + if let Some(algo) = cipher_algo { + encryptor = encryptor.sym_algo(algo); + } + if let Some(algo) = aead_algo { + encryptor = encryptor.aead_algo(algo); + } + ffi_try_box!(encryptor.build()) } diff --git a/openpgp/examples/encrypt-for.rs b/openpgp/examples/encrypt-for.rs index 3076c7a4..82f636d9 100644 --- a/openpgp/examples/encrypt-for.rs +++ b/openpgp/examples/encrypt-for.rs @@ -35,7 +35,7 @@ fn main() { }).collect(); // Build a vector of recipients to hand to Encryptor. - let recipients = + let mut recipients = tpks.iter() .flat_map(|tpk| tpk.keys_valid().key_flags(mode.clone())) .map(|(_, _, key)| key.into()) @@ -51,11 +51,13 @@ fn main() { let message = Message::new(sink); // We want to encrypt a literal data packet. - let encryptor = Encryptor::new(message, - &[], // No symmetric encryption. - &recipients, - None, None) - .expect("Failed to create encryptor"); + let mut encryptor = Encryptor::for_recipient( + message, recipients.pop().expect("No encryption key found")); + for r in recipients { + encryptor = encryptor.add_recipient(r) + } + let encryptor = encryptor.build().expect("Failed to create encryptor"); + let mut literal_writer = LiteralWriter::new(encryptor).build() .expect("Failed to create literal writer"); diff --git a/openpgp/examples/generate-encrypt-decrypt.rs b/openpgp/examples/generate-encrypt-decrypt.rs index f8eeb05f..d20219ab 100644 --- a/openpgp/examples/generate-encrypt-decrypt.rs +++ b/openpgp/examples/generate-encrypt-decrypt.rs @@ -41,7 +41,7 @@ fn generate() -> openpgp::Result<openpgp::TPK> { fn encrypt(sink: &mut dyn Write, plaintext: &str, recipient: &openpgp::TPK) -> openpgp::Result<()> { // Build a vector of recipients to hand to Encryptor. - let recipients = + let mut recipients = recipient.keys_valid() .key_flags(KeyFlags::default() .set_encrypt_at_rest(true) @@ -53,10 +53,12 @@ fn encrypt(sink: &mut dyn Write, plaintext: &str, recipient: &openpgp::TPK) let message = Message::new(sink); // We want to encrypt a literal data packet. - let encryptor = Encryptor::new(message, - &[], // No symmetric encryption. - &recipients, - None, None)?; + let mut encryptor = Encryptor::for_recipient( + message, recipients.pop().expect("No encryption key found")); + for r in recipients { + encryptor = encryptor.add_recipient(r) + } + let encryptor = encryptor.build().expect("Failed to create encryptor"); // Emit a literal data packet. let mut literal_writer = LiteralWriter::new(encryptor).build()?; diff --git a/openpgp/examples/pad.rs b/openpgp/examples/pad.rs index 76d4ebc0..6a3d7c96 100644 --- a/openpgp/examples/pad.rs +++ b/openpgp/examples/pad.rs @@ -37,7 +37,7 @@ fn main() { }).collect(); // Build a vector of recipients to hand to Encryptor. - let recipients = + let mut recipients = tpks.iter() .flat_map(|tpk| tpk.keys_valid().key_flags(mode.clone())) .map(|(_, _, key)| Recipient::new(KeyID::wildcard(), key)) @@ -53,11 +53,12 @@ fn main() { let message = Message::new(sink); // We want to encrypt a literal data packet. - let encryptor = Encryptor::new(message, - &[], // No symmetric encryption. - &recipients, - None, None) - .expect("Failed to create encryptor"); + let mut encryptor = Encryptor::for_recipient( + message, recipients.pop().expect("No encryption key found")); + for r in recipients { + encryptor = encryptor.add_recipient(r) + } + let encryptor = encryptor.build().expect("Failed to create encryptor"); let padder = Padder::new(encryptor, padme) .expect("Failed to create padder"); diff --git a/openpgp/src/autocrypt.rs b/openpgp/src/autocrypt.rs index 4f7596bb..d283ca1d 100644 --- a/openpgp/src/autocrypt.rs +++ b/openpgp/src/autocrypt.rs @@ -467,9 +467,8 @@ impl AutocryptSetupMessage { // Passphrase-Format header with value numeric9x4 let m = Message::new(w); - let w = Encryptor::new(m, - vec![ self.passcode.as_ref().unwrap() ], - &[], None, None)?; + let w = Encryptor::with_password(m, self.passcode.clone().unwrap()) + .build()?; let mut w = LiteralWriter::new(w).build()?; diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs index 50313108..22f7e44c 100644 --- a/openpgp/src/serialize/stream.rs +++ b/openpgp/src/serialize/stream.rs @@ -9,7 +9,6 @@ //! //! [encryption example]: struct.Encryptor.html#example -use std::borrow::Borrow; use std::fmt; use std::io::{self, Write}; use time; @@ -910,6 +909,10 @@ impl<'a> Recipient<'a> { /// Encrypts a packet stream. pub struct Encryptor<'a> { inner: Option<writer::BoxStack<'a, Cookie>>, + recipients: Vec<Recipient<'a>>, + passwords: Vec<Password>, + sym_algo: SymmetricAlgorithm, + aead_algo: Option<AEADAlgorithm>, hash: crypto::hash::Context, cookie: Cookie, } @@ -979,46 +982,109 @@ impl<'a> Encryptor<'a> { /// ).unwrap(); /// /// // Build a vector of recipients to hand to Encryptor. - /// let recipients = + /// let recipient = /// tpk.keys_valid() /// .key_flags(KeyFlags::default() /// .set_encrypt_at_rest(true) /// .set_encrypt_for_transport(true)) /// .map(|(_, _, key)| key.into()) - /// .collect::<Vec<_>>(); + /// .nth(0).unwrap(); /// /// let mut o = vec![]; /// let message = Message::new(&mut o); - /// let encryptor = Encryptor::new(message, - /// &["совершенно секретно".into()], - /// &recipients, None, None) - /// .expect("Failed to create encryptor"); + /// let encryptor = + /// Encryptor::for_recipient(message, recipient) + /// .build().expect("Failed to create encryptor"); /// let mut w = LiteralWriter::new(encryptor).build()?; /// w.write_all(b"Hello world.")?; /// w.finalize()?; /// # Ok(()) /// # } /// ``` - pub fn new<'r, P, R, C, A>(inner: writer::Stack<'a, Cookie>, - passwords: P, recipients: R, - cipher_algo: C, aead_algo: A) - -> Result<writer::Stack<'a, Cookie>> - where P: IntoIterator, - P::Item: Borrow<Password>, - R: IntoIterator, - R::Item: Borrow<Recipient<'r>>, - C: Into<Option<SymmetricAlgorithm>>, - A: Into<Option<AEADAlgorithm>>, - { - let passwords = passwords.into_iter().collect::<Vec<_>>(); - let passwords_ref = passwords.iter().map(|r| r.borrow()).collect(); - let recipients = recipients.into_iter().collect::<Vec<_>>(); - let recipients_ref = recipients.iter().map(|r| r.borrow()).collect(); - Self::make(inner, - passwords_ref, - recipients_ref, - cipher_algo.into().unwrap_or_default(), - aead_algo.into()) + pub fn for_recipient(inner: writer::Stack<'a, Cookie>, + recipient: Recipient<'a>) -> Self { + Self { + inner: Some(inner.into()), + recipients: vec![recipient], + passwords: Vec::new(), + sym_algo: Default::default(), + aead_algo: Default::default(), + hash: HashAlgorithm::SHA1.context().unwrap(), + cookie: Default::default(), // Will be fixed in build. + } + } + + /// Creates a new encryptor. + /// + /// The stream will be encrypted using a generated session key, + /// which will be encrypted using the given passwords, and all + /// encryption-capable subkeys of the given TPKs. + /// + /// Unless otherwise specified, the stream is encrypted using + /// AES256. If `aead_algo` is `None`, a `SEIP` packet is emitted, + /// otherwise the given AEAD algorithm is used. + /// + /// Key preferences of the recipients are not honored. + /// + /// # Example + /// + /// ``` + /// use std::io::Write; + /// extern crate sequoia_openpgp as openpgp; + /// use openpgp::constants::KeyFlags; + /// use openpgp::serialize::stream::{ + /// Message, Encryptor, LiteralWriter, + /// }; + /// # use openpgp::Result; + /// # use openpgp::parse::Parse; + /// # fn main() { f().unwrap(); } + /// # fn f() -> Result<()> { + /// let mut o = vec![]; + /// let message = Message::new(&mut o); + /// let encryptor = + /// Encryptor::with_password(message, "совершенно секретно".into()) + /// .build().expect("Failed to create encryptor"); + /// let mut w = LiteralWriter::new(encryptor).build()?; + /// w.write_all(b"Hello world.")?; + /// w.finalize()?; + /// # Ok(()) + /// # } + /// ``` + pub fn with_password(inner: writer::Stack<'a, Cookie>, + password: Password) -> Self { + Self { + inner: Some(inner.into()), + recipients: Vec::new(), + passwords: vec![password], + sym_algo: Default::default(), + aead_algo: Default::default(), + hash: HashAlgorithm::SHA1.context().unwrap(), + cookie: Default::default(), // Will be fixed in build. + } + } + + /// Adds a recipient. + pub fn add_recipient(mut self, recipient: Recipient<'a>) -> Self { + self.recipients.push(recipient); + self + } + + /// Adds a password. + pub fn add_password(mut self, password: Password) -> Self { + self.passwords.push(password); + self + } + + /// Sets the symmetric algorithm to use. + pub fn sym_algo(mut self, algo: SymmetricAlgorithm) -> Self { + self.sym_algo = algo; + self + } + + /// Enables AEAD and sets the AEAD algorithm to use. + pub fn aead_algo(mut self, algo: AEADAlgorithm) -> Self { + self.aead_algo = Some(algo); + self } // The default chunk size. @@ -1026,17 +1092,10 @@ impl<'a> Encryptor<'a> { // A page, 3 per mille overhead. const AEAD_CHUNK_SIZE : usize = 4096; - fn make(mut inner: writer::Stack<'a, Cookie>, - passwords: Vec<&Password>, - recipients: Vec<&Recipient>, - algo: SymmetricAlgorithm, - aead_algo: Option<AEADAlgorithm>) - -> Result<writer::Stack<'a, Cookie>> - { - if recipients.len() + passwords.len() == 0 { - return Err(Error::InvalidArgument( - "Neither recipient keys nor passwords given".into()).into()); - } + /// Finalizes the encryptor, returning the writer stack. + pub fn build(mut self) -> Result<writer::Stack<'a, Cookie>> { + assert!(self.recipients.len() + self.passwords.len() > 0, + "The constructors add at least one recipient or password"); struct AEADParameters { algo: AEADAlgorithm, @@ -1044,7 +1103,7 @@ impl<'a> Encryptor<'a> { nonce: Box<[u8]>, } - let aead = if let Some(algo) = aead_algo { + let aead = if let Some(algo) = self.aead_algo { let mut nonce = vec![0; algo.iv_size()?]; crypto::random(&mut nonce); Some(AEADParameters { @@ -1056,38 +1115,41 @@ impl<'a> Encryptor<'a> { None }; + let mut inner = self.inner.take().expect("Added in constructors"); let level = inner.as_ref().cookie_ref().level + 1; // Generate a session key. - let sk = SessionKey::new(algo.key_size()?); + let sk = SessionKey::new(self.sym_algo.key_size()?); // Write the PKESK packet(s). - for recipient in recipients { - let recipient = recipient.borrow(); - let mut pkesk = PKESK3::for_recipient(algo, &sk, recipient.key)?; + for recipient in self.recipients.iter() { + let mut pkesk = + PKESK3::for_recipient(self.sym_algo, &sk, recipient.key)?; pkesk.set_recipient(recipient.keyid.clone()); Packet::PKESK(pkesk.into()).serialize(&mut inner)?; } // Write the SKESK packet(s). - for password in passwords { + for password in self.passwords.iter() { if let Some(aead) = aead.as_ref() { - let skesk = SKESK5::with_password(algo, aead.algo, + let skesk = SKESK5::with_password(self.sym_algo, aead.algo, Default::default(), &sk, password).unwrap(); Packet::SKESK(skesk.into()).serialize(&mut inner)?; } else { - let skesk = SKESK4::with_password(algo, Default::default(), + let skesk = SKESK4::with_password(self.sym_algo, + Default::default(), &sk, password).unwrap(); Packet::SKESK(skesk.into()).serialize(&mut inner)?; } } - let encryptor = if let Some(aead) = aead { + if let Some(aead) = aead { // Write the AED packet. CTB::new(Tag::AED).serialize(&mut inner)?; - let mut inner = PartialBodyFilter::new(inner, Cookie::new(level)); - let aed = AED1::new(algo, aead.algo, aead.chunk_size, aead.nonce)?; + let mut inner = PartialBodyFilter::new(writer::Stack::from(inner), + Cookie::new(level)); + let aed = AED1::new(self.sym_algo, aead.algo, aead.chunk_size, aead.nonce)?; aed.serialize_headers(&mut inner)?; writer::AEADEncryptor::new( @@ -1098,38 +1160,34 @@ impl<'a> Encryptor<'a> { aed.chunk_size(), aed.iv(), &sk, - )? + ) } else { // Write the SEIP packet. CTB::new(Tag::SEIP).serialize(&mut inner)?; - let mut inner = PartialBodyFilter::new(inner, Cookie::new(level)); + let mut inner = PartialBodyFilter::new(writer::Stack::from(inner), + Cookie::new(level)); inner.write_all(&[1])?; // Version. - let encryptor = writer::Encryptor::new( + // Install encryptor. + self.inner = Some(writer::Encryptor::new( inner.into(), Cookie::new(level), - algo, + self.sym_algo, &sk, - )?; - - // The hash for the MDC must include the initialization - // vector, hence we build the object here. - let mut encryptor = writer::Stack::from(Box::new(Self{ - inner: Some(encryptor.into()), - hash: HashAlgorithm::SHA1.context().unwrap(), - cookie: Cookie::new(level), - })); - - // Write the initialization vector, and the quick-check bytes. - let mut iv = vec![0; algo.block_size()?]; + )?.into()); + self.cookie = Cookie::new(level); + + // Write the initialization vector, and the quick-check + // bytes. The hash for the MDC must include the + // initialization vector, hence we must write this to + // self after installing the encryptor at self.inner. + let mut iv = vec![0; self.sym_algo.block_size()?]; crypto::random(&mut iv); - encryptor.write_all(&iv)?; - encryptor.write_all(&iv[iv.len() - 2..])?; - - encryptor - }; + self.write_all(&iv)?; + self.write_all(&iv[iv.len() - 2..])?; - Ok(encryptor) + Ok(writer::Stack::from(Box::new(self))) + } } /// Emits the MDC packet and recovers the original writer. @@ -1462,10 +1520,9 @@ mod test { let mut o = vec![]; { let m = Message::new(&mut o); - let encryptor = Encryptor::new( - m, &passwords, - &[], None, None) - .unwrap(); + let encryptor = Encryptor::with_password(m, passwords[0].clone()) + .add_password(passwords[1].clone()) + .build().unwrap(); let mut literal = LiteralWriter::new(encryptor).build() .unwrap(); literal.write_all(message).unwrap(); @@ -1599,15 +1656,6 @@ mod test { .add_encryption_subkey() .generate().unwrap(); - // Build a vector of recipients to hand to Encryptor. - let recipients = - tsk.keys_all() - .key_flags(KeyFlags::default() - .set_encrypt_at_rest(true) - .set_encrypt_for_transport(true)) - .map(|(_, _, key)| key.into()) - .collect::<Vec<_>>(); - struct Helper<'a> { tsk: &'a TPK, }; @@ -1651,9 +1699,16 @@ mod test { let mut msg = vec![]; { let m = Message::new(&mut msg); - let encryptor = Encryptor::new( - m, &[], &recipients, None, AEADAlgorithm::EAX) - .unwrap(); + let recipient = + tsk.keys_all() + .key_flags(KeyFlags::default() + .set_encrypt_at_rest(true) + .set_encrypt_for_transport(true)) + .map(|(_, _, key)| key.into()) + .nth(0).unwrap(); + let encryptor = Encryptor::for_recipient(m, recipient) + .aead_algo(AEADAlgorithm::EAX) + .build().unwrap(); let mut literal = LiteralWriter::new(encryptor).build() .unwrap(); literal.write_all(&content).unwrap(); |