summaryrefslogtreecommitdiffstats
path: root/tool
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-10-14 11:43:23 +0200
committerJustus Winter <justus@sequoia-pgp.org>2020-10-14 12:16:15 +0200
commit653960de3dfe19c9b46daad38efbc4a49a7676f2 (patch)
treedd1c0c5963667dd06b717e69a0dd40df0a94cd68 /tool
parent2079449be080b4da3cdc8c6f9972f4ac48e58aaf (diff)
sq: Rename module to 'sequoia-sq'.
Diffstat (limited to 'tool')
-rw-r--r--tool/Cargo.toml62
-rw-r--r--tool/Makefile45
-rw-r--r--tool/build.rs22
-rw-r--r--tool/make-usage.sh54
-rw-r--r--tool/src/commands/decrypt.rs354
-rw-r--r--tool/src/commands/dump.rs946
-rw-r--r--tool/src/commands/inspect.rs412
-rw-r--r--tool/src/commands/key.rs248
-rw-r--r--tool/src/commands/mod.rs515
-rw-r--r--tool/src/commands/sign.rs347
-rw-r--r--tool/src/sq-usage.rs768
-rw-r--r--tool/src/sq.rs739
-rw-r--r--tool/src/sq_cli.rs601
-rw-r--r--tool/tests/sq-sign.rs813
14 files changed, 0 insertions, 5926 deletions
diff --git a/tool/Cargo.toml b/tool/Cargo.toml
deleted file mode 100644
index ada5b3fe..00000000
--- a/tool/Cargo.toml
+++ /dev/null
@@ -1,62 +0,0 @@
-[package]
-name = "sequoia-tool"
-description = "Command-line frontends for Sequoia"
-version = "0.19.0"
-authors = [
- "Justus Winter <justus@sequoia-pgp.org>",
- "Kai Michaelis <kai@sequoia-pgp.org>",
- "Neal H. Walfield <neal@sequoia-pgp.org>",
-]
-build = "build.rs"
-documentation = "https://docs.sequoia-pgp.org/0.19.0/sq"
-homepage = "https://sequoia-pgp.org/"
-repository = "https://gitlab.com/sequoia-pgp/sequoia"
-readme = "../README.md"
-keywords = ["cryptography", "openpgp", "pgp", "encryption", "signing"]
-categories = ["cryptography", "authentication", "command-line-utilities"]
-license = "GPL-2.0-or-later"
-edition = "2018"
-
-[badges]
-gitlab = { repository = "sequoia-pgp/sequoia" }
-maintenance = { status = "actively-developed" }
-
-[dependencies]
-buffered-reader = { path = "../buffered-reader", version = "0.18", default-features = false }
-sequoia-openpgp = { path = "../openpgp", version = "0.19", default-features = false }
-sequoia-autocrypt = { path = "../autocrypt", version = "0.19", default-features = false }
-sequoia-core = { path = "../core", version = "0.19", default-features = false }
-sequoia-ipc = { path = "../ipc", version = "0.19", default-features = false }
-sequoia-net = { path = "../net", version = "0.19", default-features = false }
-sequoia-store = { path = "../store", version = "0.19", default-features = false }
-anyhow = "1"
-chrono = "0.4"
-clap = "2.32.0"
-itertools = "0.9"
-prettytable-rs = "0.8.0"
-tempfile = "3.0.4"
-crossterm = "0.13"
-tokio-core = "0.1"
-rpassword = "5.0"
-
-[build-dependencies]
-clap = "2.32.0"
-
-[dev-dependencies]
-assert_cli = "0.6"
-
-[[bin]]
-name = "sq"
-path = "src/sq-usage.rs"
-
-[features]
-default = [
- "buffered-reader/compression",
- "sequoia-openpgp/default",
- "sequoia-store/background-services"
-]
-crypto-nettle = ["sequoia-openpgp/crypto-nettle"]
-crypto-cng = ["sequoia-openpgp/crypto-cng"]
-compression = ["buffered-reader/compression", "sequoia-openpgp/compression"]
-compression-deflate = ["buffered-reader/compression-deflate", "sequoia-openpgp/compression-deflate"]
-compression-bzip2 = ["buffered-reader/compression-bzip2", "sequoia-openpgp/compression-bzip2"]
diff --git a/tool/Makefile b/tool/Makefile
deleted file mode 100644
index 44428c96..00000000
--- a/tool/Makefile
+++ /dev/null
@@ -1,45 +0,0 @@
-# Configuration.
-CARGO_TARGET_DIR ?= $(shell pwd)/../target
-# We currently only support absolute paths.
-CARGO_TARGET_DIR := $(abspath $(CARGO_TARGET_DIR))
-SQ ?= $(CARGO_TARGET_DIR)/debug/sq
-
-# Tools.
-CARGO ?= cargo
-
-ifneq ($(filter Darwin BSD,$(shell uname -s)),"")
- INSTALL ?= ginstall
-else
- INSTALL ?= install
-endif
-
-all: src/sq-usage.rs
-
-# Installation.
-.PHONY: build-release
-build-release:
- CARGO_TARGET_DIR=$(CARGO_TARGET_DIR) \
- $(CARGO) build $(CARGO_FLAGS) --release --package sequoia-tool
- $(MAKE) -C../store build-release
-
-.PHONY: install
-install: build-release
- $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
- $(INSTALL) -t $(DESTDIR)$(PREFIX)/bin $(CARGO_TARGET_DIR)/release/sq
- $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/zsh/site-functions
- $(INSTALL) -t $(DESTDIR)$(PREFIX)/share/zsh/site-functions \
- $(CARGO_TARGET_DIR)/_sq
- $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/bash-completion/completions
- $(INSTALL) $(CARGO_TARGET_DIR)/sq.bash \
- $(DESTDIR)$(PREFIX)/share/bash-completion/completions/sq
- $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/fish/completions
- $(INSTALL) -t $(DESTDIR)$(PREFIX)/share/fish/completions \
- $(CARGO_TARGET_DIR)/sq.fish
- $(MAKE) -C../store install
-
-# Maintenance.
-.PHONY: update-usage
-update-usage: src/sq-usage.rs
-
-src/sq-usage.rs: make-usage.sh $(SQ)
- sh make-usage.sh $(SQ) >$@~ && mv $@~ $@
diff --git a/tool/build.rs b/tool/build.rs
deleted file mode 100644
index b7d3147d..00000000
--- a/tool/build.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use clap;
-
-use std::env;
-use std::fs;
-use clap::Shell;
-
-mod sq_cli {
- include!("src/sq_cli.rs");
-}
-
-fn main() {
- let outdir = match env::var_os("CARGO_TARGET_DIR") {
- None => return,
- Some(outdir) => outdir,
- };
- fs::create_dir_all(&outdir).unwrap();
- let mut sq = sq_cli::build();
- for shell in &[Shell::Bash, Shell::Fish, Shell::Zsh, Shell::PowerShell,
- Shell::Elvish] {
- sq.gen_completions("sq", *shell, &outdir);
- }
-}
diff --git a/tool/make-usage.sh b/tool/make-usage.sh
deleted file mode 100644
index 7bcbfcf2..00000000
--- a/tool/make-usage.sh
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/sh
-
-tool=$1
-
-quote() {
- sed 's@^@//! @' | sed 's/ $//'
-}
-
-begin_code() {
- printf '```text\n'
-}
-
-end_code() {
- printf '```\n'
-}
-
-dump_help() { # subcommand, indentation
- if [ -z "$1" ]
- then
- printf "\n# Usage\n\n"
- set "" "#"
- else
- printf "\n$2 Subcommand$1\n\n"
- fi
-
- help="`$tool $1 --help`"
-
- begin_code
- printf "$help\n" | tail -n +2
- end_code
-
- if echo $help | fgrep -q SUBCOMMANDS
- then
- printf "$help\n" |
- sed -n '/^SUBCOMMANDS:/,$p' |
- tail -n+2 |
- grep '^ [^ ]' |
- while read subcommand desc
- do
- if [ "$subcommand" = help ]; then
- continue
- fi
-
- dump_help "$1 $subcommand" "#$2"
- done
- fi
-}
-
-(
- printf "A command-line frontend for Sequoia.\n"
- dump_help
-) | quote
-
-printf '\ninclude!("'"$(basename $tool)"'.rs");\n'
diff --git a/tool/src/commands/decrypt.rs b/tool/src/commands/decrypt.rs
deleted file mode 100644
index 07adabe6..00000000
--- a/tool/src/commands/decrypt.rs
+++ /dev/null
@@ -1,354 +0,0 @@
-use crossterm::terminal;
-use anyhow::Context as _;
-use std::collections::HashMap;
-use std::io;
-use rpassword;
-
-use sequoia_openpgp as openpgp;
-use sequoia_core::Context;
-use crate::openpgp::types::SymmetricAlgorithm;
-use crate::openpgp::fmt::hex;
-use crate::openpgp::crypto::{self, SessionKey};
-use crate::openpgp::{Fingerprint, Cert, KeyID, Result};
-use crate::openpgp::packet;
-use crate::openpgp::packet::prelude::*;
-use crate::openpgp::parse::{
- Parse,
- PacketParser,
- PacketParserResult,
-};
-use crate::openpgp::parse::stream::{
- VerificationHelper, DecryptionHelper, DecryptorBuilder, MessageStructure,
-};
-use crate::openpgp::policy::Policy;
-use sequoia_store as store;
-
-use super::{dump::PacketDumper, VHelper};
-
-struct Helper<'a> {
- vhelper: VHelper<'a>,
- secret_keys:
- HashMap<KeyID, Key<key::SecretParts, key::UnspecifiedRole>>,
- key_identities: HashMap<KeyID, Fingerprint>,
- key_hints: HashMap<KeyID, String>,
- dump_session_key: bool,
- dumper: Option<PacketDumper>,
-}
-
-impl<'a> Helper<'a> {
- fn new(ctx: &'a Context, policy: &'a dyn Policy,
- mapping: &'a mut store::Mapping,
- signatures: usize, certs: Vec<Cert>, secrets: Vec<Cert>,
- dump_session_key: bool, dump: bool)
- -> Self
- {
- let mut keys = HashMap::new();
- let mut identities: HashMap<KeyID, Fingerprint> = HashMap::new();
- let mut hints: HashMap<KeyID, String> = HashMap::new();
- for tsk in secrets {
- let hint = match tsk.with_policy(policy, None)
- .and_then(|valid_cert| valid_cert.primary_userid()).ok()
- {
- Some(uid) => format!("{} ({})", uid.userid(),
- KeyID::from(tsk.fingerprint())),
- None => format!("{}", KeyID::from(tsk.fingerprint())),
- };
-
- for ka in tsk.keys()
- // XXX: Should use the message's creation time that we do not know.
- .with_policy(policy, None)
- .for_transport_encryption().for_storage_encryption()
- .secret()
- {
- let id: KeyID = ka.key().fingerprint().into();
- keys.insert(id.clone(), ka.key().clone().into());
- identities.insert(id.clone(), tsk.fingerprint());
- hints.insert(id, hint.clone());
- }
- }
-
- Helper {
- vhelper: VHelper::new(ctx, mapping, signatures, certs),
- secret_keys: keys,
- key_identities: identities,
- key_hints: hints,
- dump_session_key: dump_session_key,
- dumper: if dump {
- let width = terminal::size().ok().map(|(cols, _)| cols as usize)
- .unwrap_or(80);
- Some(PacketDumper::new(width, false))
- } else {
- None
- },
- }
- }
-
- /// Tries to decrypt the given PKESK packet with `keypair` and try
- /// to decrypt the packet parser using `decrypt`.
- fn try_decrypt<D>(&self, pkesk: &PKESK,
- sym_algo: Option<SymmetricAlgorithm>,
- keypair: &mut dyn crypto::Decryptor,
- decrypt: &mut D)
- -> Option<Option<Fingerprint>>
- where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool
- {
- let keyid = keypair.public().fingerprint().into();
- match pkesk.decrypt(keypair, sym_algo)
- .and_then(|(algo, sk)| {
- if decrypt(algo, &sk) { Some(sk) } else { None }
- })
- {
- Some(sk) => {
- if self.dump_session_key {
- eprintln!("Session key: {}", hex::encode(&sk));
- }
- Some(self.key_identities.get(&keyid).map(|fp| fp.clone()))
- },
- None => None,
- }
- }
-}
-
-impl<'a> VerificationHelper for Helper<'a> {
- fn inspect(&mut self, pp: &PacketParser) -> Result<()> {
- if let Some(dumper) = self.dumper.as_mut() {
- dumper.packet(&mut io::stderr(),
- pp.recursion_depth() as usize,
- pp.header().clone(), pp.packet.clone(),
- pp.map().map(|m| m.clone()), None)?;
- }
- Ok(())
- }
-
- fn get_certs(&mut self, ids: &[openpgp::KeyHandle]) -> Result<Vec<Cert>> {
- self.vhelper.get_certs(ids)
- }
- fn check(&mut self, structure: MessageStructure) -> Result<()> {
- self.vhelper.check(structure)
- }
-}
-
-impl<'a> DecryptionHelper for Helper<'a> {
- fn decrypt<D>(&mut self, pkesks: &[PKESK], skesks: &[SKESK],
- sym_algo: Option<SymmetricAlgorithm>,
- mut decrypt: D) -> openpgp::Result<Option<Fingerprint>>
- where D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool
- {
- // First, we try those keys that we can use without prompting
- // for a password.
- for pkesk in pkesks {
- let keyid = pkesk.recipient();
- if let Some(key) = self.secret_keys.get(&keyid) {
- if ! key.secret().is_encrypted() {
- if let Some(fp) = key.clone().into_keypair().ok()
- .and_then(|mut k|
- self.try_decrypt(pkesk, sym_algo, &mut k, &mut decrypt))
- {
- return Ok(fp);
- }
- }
- }
- }
-
- // Second, we try those keys that are encrypted.
- for pkesk in pkesks {
- // Don't ask the user to decrypt a key if we don't support
- // the algorithm.
- if ! pkesk.pk_algo().is_supported() {
- continue;
- }
-
- let keyid = pkesk.recipient();
- if let Some(key) = self.secret_keys.get_mut(&keyid) {
- let mut keypair = loop {
- if ! key.secret().is_encrypted() {
- break key.clone().into_keypair().unwrap();
- }
-
- let p = rpassword::read_password_from_tty(Some(
- &format!(
- "Enter password to decrypt key {}: ",
- self.key_hints.get(&keyid).unwrap())))?.into();
-
- let algo = key.pk_algo();
- if let Some(()) =
- key.secret_mut().decrypt_in_place(algo, &p).ok() {
- break key.clone().into_keypair().unwrap()
- } else {
- eprintln!("Bad password.");
- }
- };
-
- if let Some(fp) =
- self.try_decrypt(pkesk, sym_algo, &mut keypair,
- &mut decrypt)
- {
- return Ok(fp);
- }
- }
- }
-
- // Third, we try to decrypt PKESK packets with wildcard
- // recipients using those keys that we can use without
- // prompting for a password.
- for pkesk in pkesks.iter().filter(|p| p.recipient().is_wildcard()) {
- for key in self.secret_keys.values() {
- if ! key.secret().is_encrypted() {
- if let Some(fp) = key.clone().into_keypair().ok()
- .and_then(|mut k|
- self.try_decrypt(pkesk, sym_algo, &mut k, &mut decrypt))
- {
- return Ok(fp);
- }
- }
- }
- }
-
- // Fourth, we try to decrypt PKESK packets with wildcard
- // recipients using those keys that are encrypted.
- for pkesk in pkesks.iter().filter(|p| p.recipient().is_wildcard()) {
- // Don't ask the user to decrypt a key if we don't support
- // the algorithm.
- if ! pkesk.pk_algo().is_supported() {
- continue;
- }
-
- // To appease the borrow checker, iterate over the
- // hashmap, awkwardly.
- for keyid in self.secret_keys.keys().cloned().collect::<Vec<_>>()
- {
- let mut keypair = loop {
- let key = self.secret_keys.get_mut(&keyid).unwrap(); // Yuck
-
- if ! key.secret().is_encrypted() {
- break key.clone().into_keypair().unwrap();
- }
-
- let p = rpassword::read_password_from_tty(Some(
- &format!(
- "Enter password to decrypt key {}: ",
- self.key_hints.get(&keyid).unwrap())))?.into();
-
- let algo = key.pk_algo();
- if let Some(()) =
- key.secret_mut().decrypt_in_place(algo, &p).ok() {
- break key.clone().into_keypair().unwrap()
- } else {
- eprintln!("Bad password.");
- }
- };
-
- if let Some(fp) =
- self.try_decrypt(pkesk, sym_algo, &mut keypair,
- &mut decrypt)
- {
- return Ok(fp);
- }
- }
- }
-
- if skesks.is_empty() {
- return
- Err(anyhow::anyhow!("No key to decrypt message"));
- }
-
- // Finally, try to decrypt using the SKESKs.
- loop {
- let password =
- rpassword::read_password_from_tty(Some(
- "Enter password to decrypt message: "))?.into();
-
- for skesk in skesks {
- if let Some(sk) = skesk.decrypt(&password).ok()
- .and_then(|(algo, sk)| { if decrypt(algo, &sk) { Some(sk) } else { None }})
- {
- if self.dump_session_key {
- eprintln!("Session key: {}", hex::encode(&sk));
- }
- return Ok(None);
- }
- }
-
- eprintln!("Bad password.");
- }
- }
-}
-
-pub fn decrypt(ctx: &Context, policy: &dyn Policy, mapping: &mut store::Mapping,
- input: &mut dyn io::Read, output: &mut dyn io::Write,
- signatures: usize, certs: Vec<Cert>, secrets: Vec<Cert>,
- dump_session_key: bool,
- dump: bool, hex: bool)
- -> Result<()> {
- let helper = Helper::new(ctx, policy, mapping, signatures, certs, secrets,
- dump_session_key, dump || hex);
- let mut decryptor = DecryptorBuilder::from_reader(input)?
- .mapping(hex)
- .with_policy(policy, None, helper)
- .context("Decryption failed")?;
-
- io::copy(&mut decryptor, output).context("Decryption failed")?;
-
- let helper = decryptor.into_helper();
- if let Some(dumper) = helper.dumper.as_ref() {
- dumper.flush(&mut io::stderr())?;
- }
- helper.vhelper.print_status();
- return Ok(());
-}
-
-pub fn decrypt_unwrap(ctx: &Context, policy: &dyn Policy,
- mapping: &mut store::Mapping,
- input: &mut dyn io::Read, output: &mut dyn io::Write,
- secrets: Vec<Cert>, dump_session_key: bool)
- -> Result<()>
-{
- let mut helper = Helper::new(ctx, policy, mapping, 0, Vec::new(), secrets,
- dump_session_key, false);
-
- let mut ppr = PacketParser::from_reader(input)?;
-
- let mut pkesks: Vec<packet::PKESK> = Vec::new();
- let mut skesks: Vec<packet::SKESK> = Vec::new();
- while let PacketParserResult::Some(mut pp) = ppr {
- let sym_algo_hint = if let Packet::AED(ref aed) = pp.packet {
- Some(aed.symmetric_algo())
- } else {
- None
- };
-
- match pp.packet {
- Packet::SEIP(_) | Packet::AED(_) => {
- {
- let decrypt = |algo, secret: &SessionKey| {
- pp.decrypt(algo, secret).is_ok()
- };
- helper.decrypt(&pkesks[..], &skesks[..], sym_algo_hint,
- decrypt)?;
- }
- if pp.encrypted() {
- return Err(
- openpgp::Error::MissingSessionKey(
- "No session key".into()).into());
- }
-
- io::copy(&mut pp, output)?;
- return Ok(());
- },
- Packet::MDC(ref mdc) => if ! mdc.valid() {
- return Err(openpgp::Error::ManipulatedMessage.into());
- },
- _ => (),
- }
-
- let (p, ppr_tmp) = pp.recurse()?;
- match p {
- Packet::PKESK(pkesk) => pkesks.push(pkesk),
- Packet::SKESK(skesk) => skesks.push(skesk),
- _ => (),
- }
- ppr = ppr_tmp;
- }
-
- Ok(())
-}
diff --git a/tool/src/commands/dump.rs b/tool/src/commands/dump.rs
deleted file mode 100644
index 6f35f56d..00000000
--- a/tool/src/commands/dump.rs
+++ /dev/null
@@ -1,946 +0,0 @@
-use std::io::{self, Read};
-
-use sequoia_openpgp as openpgp;
-use self::openpgp::types::{Duration, Timestamp, SymmetricAlgorithm};
-use self::openpgp::fmt::hex;
-use self::openpgp::crypto::mpi;
-use self::openpgp::{Packet, Result};
-use self::openpgp::packet::prelude::*;
-use self::openpgp::packet::header::CTB;
-use self::openpgp::packet::{Header, header::BodyLength, Signature};
-use self::openpgp::packet::signature::subpacket::{Subpacket, SubpacketValue};
-use self::openpgp::crypto::{SessionKey, S2K};
-use self::openpgp::parse::{map::Map, Parse, PacketParserResult};
-
-#[derive(Debug)]
-pub enum Kind {
- Message {
- encrypted: bool,
- },
- Keyring,
- Cert,
- Unknown,
-}
-
-/// Converts sequoia_openpgp types for rendering.
-pub trait Convert<T> {
- /// Performs the conversion.
- fn convert(self) -> T;
-}
-
-impl Convert<chrono::Duration> for std::time::Duration {
- fn convert(self) -> chrono::Duration {
- chrono::Duration::seconds(self.as_secs() as i64)
- }
-}
-
-impl Convert<chrono::Duration> for Duration {
- fn convert(self) -> chrono::Duration {
- chrono::Duration::seconds(self.as_secs() as i64)
- }
-}
-
-impl Convert<chrono::DateTime<chrono::offset::Utc>> for std::time::SystemTime {
- fn convert(self) -> chrono::DateTime<chrono::offset::Utc> {
- chrono::DateTime::<chrono::offset::Utc>::from(self)
- }
-}
-
-impl Convert<chrono::DateTime<chrono::offset::Utc>> for Timestamp {
- fn convert(self) -> chrono::DateTime<chrono::offset::Utc> {
- std::time::SystemTime::from(self).convert()
- }
-}
-
-pub fn dump<W>(input: &mut dyn io::Read, output: &mut dyn io::Write,
- mpis: bool, hex: bool, sk: Option<&SessionKey>,
- width: W)
- -> Result<Kind>
- where W: Into<Option<usize>>
-{
- let mut ppr
- = self::openpgp::parse::PacketParserBuilder::from_reader(input)?
- .map(hex).build()?;
- let mut message_encrypted = false;
- let width = width.into().unwrap_or(80);
- let mut dumper = PacketDumper::new(width, mpis);
-
- while let PacketParserResult::Some(mut pp) = ppr {
- let additional_fields = match pp.packet {
- Packet::Literal(_) => {
- let mut prefix = vec![0; 40];
- let n = pp.read(&mut prefix)?;
- Some(vec![
- format!("Content: {:?}{}",
- String::from_utf8_lossy(&prefix[..n]),
- if n == prefix.len() { "..." } else { "" }),
- ])
- },
- Packet::SEIP(_) if sk.is_none() => {
- message_encrypted = true;
- Some(vec!["No session key supplied".into()])
- }
- Packet::SEIP(_) if sk.is_some() => {
- message_encrypted = true;
- let sk = sk.as_ref().unwrap();
- let mut decrypted_with = None;
- for algo in 1..20 {
- let algo = SymmetricAlgorithm::from(algo);
- if let Ok(size) = algo.key_size() {
- if size != sk.len() { continue; }
- } else {
- continue;
- }
-
- if let Ok(_) = pp.decrypt(algo, sk) {
- decrypted_with = Some(algo);
- break;
- }
- }
- let mut fields = Vec::new();
- fields.push(format!("Session key: {}", hex::encode(sk)));
- if let Some(algo) = decrypted_with {
- fields.push(format!("Symmetric algo: {}", algo));
- fields.push("Decryption successful".into());
- } else {
- fields.push("Decryption failed".into());
- }
- Some(fields)
- },
- Packet::AED(_) if sk.is_none() => {
- message_encrypted = true;
- Some(vec!["No session key supplied".into()])
- }
- Packet::AED(_) if sk.is_some() => {
- message_encrypted = true;
- let sk = sk.as_ref().unwrap();
- let algo = if let Packet::AED(ref aed) = pp.packet {
- aed.symmetric_algo()
- } else {
- unreachable!()
- };
-
- let