pub struct Encryptor<'a, 'b>where
'b: 'a,{ /* private fields */ }Expand description
Encrypts a message.
The stream will be encrypted using a generated session key, which will be encrypted using the given passwords, and for all given recipients.
An Recipient is an encryption-capable (sub)key. Note that a
certificate may have more than one encryption-capable subkey, and
even the primary key may be encryption-capable.
To encrypt for more than one certificate, iterate over the certificates and select encryption-capable keys, making sure that at least one key is selected from each certificate.
§Examples
This demonstrates encrypting for multiple certificates.
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
use openpgp::policy::StandardPolicy;
let p = &StandardPolicy::new();
let recipient_certs = vec![cert_0, cert_1];
let mut recipients = Vec::new();
for cert in recipient_certs.iter() {
// Make sure we add at least one subkey from every
// certificate.
let mut found_one = false;
for key in cert.keys().with_policy(p, None)
.supported().alive().revoked(false).for_transport_encryption()
{
recipients.push(key);
found_one = true;
}
if ! found_one {
return Err(anyhow::anyhow!("No suitable encryption subkey for {}",
cert));
}
}
let message = Message::new(&mut sink);
let message = Encryptor::for_recipients(message, recipients).build()?;
let mut w = LiteralWriter::new(message).build()?;
w.write_all(b"Hello world.")?;
w.finalize()?;Implementations§
Source§impl<'a, 'b> Encryptor<'a, 'b>
impl<'a, 'b> Encryptor<'a, 'b>
Sourcepub fn for_recipients<R>(inner: Message<'a>, recipients: R) -> Encryptor<'a, 'b> ⓘ
pub fn for_recipients<R>(inner: Message<'a>, recipients: R) -> Encryptor<'a, 'b> ⓘ
Creates a new encryptor for the given recipients.
To add more recipients, use Encryptor::add_recipients. To
add passwords, use Encryptor::add_passwords. To change
the symmetric encryption algorithm, use
Encryptor::symmetric_algo.
§Examples
use std::io::Write;
use sequoia_openpgp as openpgp;
use openpgp::cert::prelude::*;
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
use openpgp::policy::StandardPolicy;
let p = &StandardPolicy::new();
let cert = Cert::from_bytes(
"-----BEGIN PGP PUBLIC KEY BLOCK-----
xjMEWlNvABYJKwYBBAHaRw8BAQdA+EC2pvebpEbzPA9YplVgVXzkIG5eK+7wEAez
...
-----END PGP PUBLIC KEY BLOCK-----"
)?;
let recipients =
cert.keys().with_policy(p, None).supported().alive().revoked(false)
// Or `for_storage_encryption()`, for data at rest.
.for_transport_encryption();
let message = Message::new(&mut sink);
let message = Encryptor::for_recipients(message, recipients).build()?;
let mut w = LiteralWriter::new(message).build()?;
w.write_all(b"Hello world.")?;
w.finalize()?;Sourcepub fn with_passwords<P>(inner: Message<'a>, passwords: P) -> Encryptor<'a, 'b> ⓘ
pub fn with_passwords<P>(inner: Message<'a>, passwords: P) -> Encryptor<'a, 'b> ⓘ
Creates a new encryptor for the given passwords.
To add more passwords, use Encryptor::add_passwords. To
add recipients, use Encryptor::add_recipients. To change
the symmetric encryption algorithm, use
Encryptor::symmetric_algo.
§Examples
use std::io::Write;
use sequoia_openpgp as openpgp;
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
let message = Message::new(&mut sink);
let message = Encryptor::with_passwords(
message, Some("совершенно секретно")).build()?;
let mut w = LiteralWriter::new(message).build()?;
w.write_all(b"Hello world.")?;
w.finalize()?;Sourcepub fn with_session_key(
inner: Message<'a>,
sym_algo: SymmetricAlgorithm,
session_key: SessionKey,
) -> Result<Encryptor<'a, 'b>, Error>
pub fn with_session_key( inner: Message<'a>, sym_algo: SymmetricAlgorithm, session_key: SessionKey, ) -> Result<Encryptor<'a, 'b>, Error>
Creates a new encryptor for the given algorithm and session key.
Usually, the encryptor creates a session key and decrypts it for the given recipients and passwords. Using this function, the session key can be supplied instead. There are two main use cases for this:
-
Replying to an encrypted message usually requires the encryption (sub)keys for every recipient. If even one key is not available, it is not possible to encrypt the new session key. Rather than falling back to replying unencrypted, one can reuse the original message’s session key that was encrypted for every recipient and reuse the original
PKESKs. -
Using the encryptor if the session key is transmitted or derived using a scheme not supported by Sequoia.
To add more passwords, use Encryptor::add_passwords. To
add recipients, use Encryptor::add_recipients.
§Examples
This example demonstrates how to fall back to the original message’s session key in order to encrypt a reply.
// Generate two keys.
let (alice, _) = CertBuilder::general_purpose(
Some("Alice Lovelace <alice@example.org>")).generate()?;
let (bob, _) = CertBuilder::general_purpose(
Some("Bob Babbage <bob@example.org>")).generate()?;
// Encrypt a message for both keys.
let recipients = vec![&alice, &bob].into_iter().flat_map(|cert| {
cert.keys().with_policy(p, None).supported().alive().revoked(false)
.for_transport_encryption()
});
let mut original = vec![];
let message = Message::new(&mut original);
let message = Encryptor::for_recipients(message, recipients).build()?;
let mut w = LiteralWriter::new(message).build()?;
w.write_all(b"Original message")?;
w.finalize()?;
// Decrypt original message using Alice's key.
let mut decryptor = DecryptorBuilder::from_bytes(&original)?
.with_policy(p, None, Helper::new(alice))?;
io::copy(&mut decryptor, &mut io::sink())?;
let (algo, sk, pkesks) = decryptor.into_helper().recycling_bin.unwrap();
// Compose the reply using the same session key.
let mut reply = vec![];
let mut message = Message::new(&mut reply);
for p in pkesks { // Emit the stashed PKESK packets.
Packet::from(p).serialize(&mut message)?;
}
let message = Encryptor::with_session_key(
message, algo.unwrap_or_default(), sk)?
.aead_algo(Default::default())
.build()?;
let mut w = LiteralWriter::new(message).build()?;
w.write_all(b"Encrypted reply")?;
w.finalize()?;
// Check that Bob can decrypt it.
let mut decryptor = DecryptorBuilder::from_bytes(&reply)?
.with_policy(p, None, Helper::new(bob))?;
io::copy(&mut decryptor, &mut io::sink())?;
/// Decrypts the message preserving algo, session key, and PKESKs.
struct Helper {
key: Cert,
recycling_bin: Option<(Option<SymmetricAlgorithm>, SessionKey, Vec<PKESK>)>,
}
impl DecryptionHelper for Helper {
fn decrypt(&mut self, pkesks: &[PKESK], _skesks: &[SKESK],
sym_algo: Option<SymmetricAlgorithm>,
decrypt: &mut dyn FnMut(Option<SymmetricAlgorithm>, &SessionKey) -> bool)
-> Result<Option<Cert>>
{
let p = &StandardPolicy::new();
let mut encryption_context = None;
for pkesk in pkesks { // Try each PKESK until we succeed.
for ka in self.key.keys().with_policy(p, None)
.supported().unencrypted_secret()
.key_handles(pkesk.recipient())
.for_storage_encryption().for_transport_encryption()
{
let mut pair = ka.key().clone().into_keypair().unwrap();
if pkesk.decrypt(&mut pair, sym_algo)
.map(|(algo, session_key)| {
let success = decrypt(algo, &session_key);
if success {
// Copy algor, session key, and PKESKs.
encryption_context =
Some((algo, session_key.clone(),
pkesks.iter().cloned().collect()));
}
success
})
.unwrap_or(false)
{
break; // Decryption successful.
}
}
}
self.recycling_bin = encryption_context; // Store for the reply.
Ok(Some(self.key.clone()))
}
}
impl VerificationHelper for Helper {
// ...
}Sourcepub fn add_recipients<R>(self, recipients: R) -> Encryptor<'a, 'b> ⓘ
pub fn add_recipients<R>(self, recipients: R) -> Encryptor<'a, 'b> ⓘ
Adds recipients.
The resulting message can be encrypted by any recipient and with any password.
§Examples
use std::io::Write;
use sequoia_openpgp as openpgp;
use openpgp::cert::prelude::*;
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
use openpgp::policy::StandardPolicy;
let p = &StandardPolicy::new();
let cert = Cert::from_bytes(
"-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFpxtsABCADZcBa1Q3ZLZnju18o0+t8LoQuIIeyeUQ0H45y6xUqyrD5HSkVM
...
-----END PGP PUBLIC KEY BLOCK-----"
)?;
let recipients =
cert.keys().with_policy(p, None).supported().alive().revoked(false)
// Or `for_storage_encryption()`, for data at rest.
.for_transport_encryption();
let message = Message::new(&mut sink);
let message =
Encryptor::with_passwords(message, Some("совершенно секретно"))
.add_recipients(recipients)
.build()?;
let mut message = LiteralWriter::new(message).build()?;
message.write_all(b"Hello world.")?;
message.finalize()?;Sourcepub fn add_passwords<P>(self, passwords: P) -> Encryptor<'a, 'b> ⓘ
pub fn add_passwords<P>(self, passwords: P) -> Encryptor<'a, 'b> ⓘ
Adds passwords to encrypt with.
The resulting message can be encrypted with any password and by any recipient.
§Examples
use std::io::Write;
use sequoia_openpgp as openpgp;
use openpgp::cert::prelude::*;
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
use openpgp::policy::StandardPolicy;
let p = &StandardPolicy::new();
let cert = Cert::from_bytes(
"-----BEGIN PGP PUBLIC KEY BLOCK-----
mQENBFpxtsABCADZcBa1Q3ZLZnju18o0+t8LoQuIIeyeUQ0H45y6xUqyrD5HSkVM
...
-----END PGP PUBLIC KEY BLOCK-----"
)?;
let recipients =
cert.keys().with_policy(p, None).supported().alive().revoked(false)
// Or `for_storage_encryption()`, for data at rest.
.for_transport_encryption();
let message = Message::new(&mut sink);
let message =
Encryptor::for_recipients(message, recipients)
.add_passwords(Some("совершенно секретно"))
.build()?;
let mut message = LiteralWriter::new(message).build()?;
message.write_all(b"Hello world.")?;
message.finalize()?;Sourcepub fn symmetric_algo(self, algo: SymmetricAlgorithm) -> Encryptor<'a, 'b> ⓘ
pub fn symmetric_algo(self, algo: SymmetricAlgorithm) -> Encryptor<'a, 'b> ⓘ
Sets the symmetric algorithm to use.
§Examples
use std::io::Write;
use sequoia_openpgp as openpgp;
use openpgp::types::SymmetricAlgorithm;
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
let message = Message::new(&mut sink);
let message =
Encryptor::with_passwords(message, Some("совершенно секретно"))
.symmetric_algo(SymmetricAlgorithm::AES128)
.build()?;
let mut message = LiteralWriter::new(message).build()?;
message.write_all(b"Hello world.")?;
message.finalize()?;Sourcepub fn aead_algo(self, algo: AEADAlgorithm) -> Encryptor<'a, 'b> ⓘ
pub fn aead_algo(self, algo: AEADAlgorithm) -> Encryptor<'a, 'b> ⓘ
Enables AEAD and sets the AEAD algorithm to use.
§Examples
use std::io::Write;
use sequoia_openpgp as openpgp;
use openpgp::types::AEADAlgorithm;
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
let message = Message::new(&mut sink);
let message =
Encryptor::with_passwords(message, Some("совершенно секретно"))
.aead_algo(AEADAlgorithm::default())
.build()?;
let mut message = LiteralWriter::new(message).build()?;
message.write_all(b"Hello world.")?;
message.finalize()?;Sourcepub fn build(self) -> Result<Message<'a>, Error>
pub fn build(self) -> Result<Message<'a>, Error>
Builds the encryptor, returning the writer stack.
The most useful filters to push to the writer stack next are
the Padder or Compressor, and after that the
Signer. Finally, literal data must be wrapped using the
LiteralWriter.
§Examples
use std::io::Write;
use sequoia_openpgp as openpgp;
use openpgp::serialize::stream::{
Message, Encryptor, LiteralWriter,
};
let message = Message::new(&mut sink);
let message =
Encryptor::with_passwords(message, Some("совершенно секретно"))
// Customize the `Encryptor` here.
.build()?;
// Optionally add a `Padder` or `Compressor` here.
// Optionally add a `Signer` here.
let mut message = LiteralWriter::new(message).build()?;
message.write_all(b"Hello world.")?;
message.finalize()?;Trait Implementations§
Source§impl<'a, 'b> Write for Encryptor<'a, 'b>where
'b: 'a,
impl<'a, 'b> Write for Encryptor<'a, 'b>where
'b: 'a,
Source§fn write(&mut self, buf: &[u8]) -> Result<usize, Error>
fn write(&mut self, buf: &[u8]) -> Result<usize, Error>
Source§fn flush(&mut self) -> Result<(), Error>
fn flush(&mut self) -> Result<(), Error>
Source§fn is_write_vectored(&self) -> bool
fn is_write_vectored(&self) -> bool
can_vector)1.0.0 · Source§fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>
fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>
Source§fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<(), Error>
fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> Result<(), Error>
write_all_vectored)Auto Trait Implementations§
impl<'a, 'b> !RefUnwindSafe for Encryptor<'a, 'b>
impl<'a, 'b> !UnwindSafe for Encryptor<'a, 'b>
impl<'a, 'b> Freeze for Encryptor<'a, 'b>
impl<'a, 'b> Send for Encryptor<'a, 'b>
impl<'a, 'b> Sync for Encryptor<'a, 'b>
impl<'a, 'b> Unpin for Encryptor<'a, 'b>
impl<'a, 'b> UnsafeUnpin for Encryptor<'a, 'b>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<W> ElfWrite for W
impl<W> ElfWrite for W
Source§fn write_word(
&mut self,
class: Class,
byte_order: ByteOrder,
value: u64,
) -> Result<(), Error>
fn write_word( &mut self, class: Class, byte_order: ByteOrder, value: u64, ) -> Result<(), Error>
Source§fn write_word_as_u32(
&mut self,
class: Class,
byte_order: ByteOrder,
value: u32,
) -> Result<(), Error>
fn write_word_as_u32( &mut self, class: Class, byte_order: ByteOrder, value: u32, ) -> Result<(), Error>
value.Source§impl<T> ExecutableCommand for T
impl<T> ExecutableCommand for T
Source§fn execute(&mut self, command: impl Command) -> Result<&mut T, Error>
fn execute(&mut self, command: impl Command) -> Result<&mut T, Error>
Executes the given command directly.
The given command its ANSI escape code will be written and flushed onto Self.
§Arguments
-
The command that you want to execute directly.
§Example
use std::io;
use crossterm::{ExecutableCommand, style::Print};
fn main() -> io::Result<()> {
// will be executed directly
io::stdout()
.execute(Print("sum:\n".to_string()))?
.execute(Print(format!("1 + 1= {} ", 1 + 1)))?;
Ok(())
// ==== Output ====
// sum:
// 1 + 1 = 2
}Have a look over at the Command API for more details.
§Notes
- In the case of UNIX and Windows 10, ANSI codes are written to the given ‘writer’.
- In case of Windows versions lower than 10, a direct WinAPI call will be made.
The reason for this is that Windows versions lower than 10 do not support ANSI codes,
and can therefore not be written to the given
writer. Therefore, there is no difference between execute and queue for those old Windows versions.
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<W> LittleEndianWriteExt for W
impl<W> LittleEndianWriteExt for W
impl<T> MaybeSend for T
impl<T> MaybeSync for T
Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> QueueableCommand for T
impl<T> QueueableCommand for T
Source§fn queue(&mut self, command: impl Command) -> Result<&mut T, Error>
fn queue(&mut self, command: impl Command) -> Result<&mut T, Error>
Queues the given command for further execution.
Queued commands will be executed in the following cases:
- When
flushis called manually on the given type implementingio::Write. - The terminal will
flushautomatically if the buffer is full. - Each line is flushed in case of
stdout, because it is line buffered.
§Arguments
-
The command that you want to queue for later execution.
§Examples
use std::io::{self, Write};
use crossterm::{QueueableCommand, style::Print};
fn main() -> io::Result<()> {
let mut stdout = io::stdout();
// `Print` will executed executed when `flush` is called.
stdout
.queue(Print("foo 1\n".to_string()))?
.queue(Print("foo 2".to_string()))?;
// some other code (no execution happening here) ...
// when calling `flush` on `stdout`, all commands will be written to the stdout and therefore executed.
stdout.flush()?;
Ok(())
// ==== Output ====
// foo 1
// foo 2
}Have a look over at the Command API for more details.
§Notes
- In the case of UNIX and Windows 10, ANSI codes are written to the given ‘writer’.
- In case of Windows versions lower than 10, a direct WinAPI call will be made.
The reason for this is that Windows versions lower than 10 do not support ANSI codes,
and can therefore not be written to the given
writer. Therefore, there is no difference between execute and queue for those old Windows versions.
Source§impl<W> SynchronizedUpdate for W
impl<W> SynchronizedUpdate for W
Source§fn sync_update<T>(
&mut self,
operations: impl FnOnce(&mut W) -> T,
) -> Result<T, Error>
fn sync_update<T>( &mut self, operations: impl FnOnce(&mut W) -> T, ) -> Result<T, Error>
Performs a set of actions within a synchronous update.
Updates will be suspended in the terminal, the function will be executed against self, updates will be resumed, and a flush will be performed.
§Arguments
-
Function
A function that performs the operations that must execute in a synchronized update.
§Examples
use std::io;
use crossterm::{ExecutableCommand, SynchronizedUpdate, style::Print};
fn main() -> io::Result<()> {
let mut stdout = io::stdout();
stdout.sync_update(|stdout| {
stdout.execute(Print("foo 1\n".to_string()))?;
stdout.execute(Print("foo 2".to_string()))?;
// The effects of the print command will not be present in the terminal
// buffer, but not visible in the terminal.
std::io::Result::Ok(())
})?;
// The effects of the commands will be visible.
Ok(())
// ==== Output ====
// foo 1
// foo 2
}§Notes
This command is performed only using ANSI codes, and will do nothing on terminals that do not support ANSI codes, or this specific extension.
When rendering the screen of the terminal, the Emulator usually iterates through each visible grid cell and renders its current state. With applications updating the screen a at higher frequency this can cause tearing.
This mode attempts to mitigate that.
When the synchronization mode is enabled following render calls will keep rendering the last rendered state. The terminal Emulator keeps processing incoming text and sequences. When the synchronized update mode is disabled again the renderer may fetch the latest screen buffer state again, effectively avoiding the tearing effect by unintentionally rendering in the middle a of an application screen update.