use std::io;
use std::io::BufReader;
use std::time::SystemTime;
use pgp::composed::{Esk, Message, PlainSessionKey};
use pgp::types::{DecryptionKey, EskType, KeyDetails, Password};
use rpgpie::certificate::Certificate;
use sop::errors::Error;
use crate::card::get_card;
use crate::util::DebugWrapper;
use crate::{card, util, Certs, Keys, RPGSOPOCT};
#[derive(Default)]
pub(crate) struct Decrypt {
verify: Vec<Certificate>,
_session_keys: Vec<sop::SessionKey>,
decryption_keys: Vec<Certificate>,
key_passwords: Vec<sop::Password>, skesk_passwords: Vec<sop::Password>,
}
impl Decrypt {
pub(crate) fn new() -> Self {
Default::default()
}
}
impl<'a> sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> for Decrypt {
fn verify_not_before(
self: Box<Self>,
_t: SystemTime,
) -> Box<dyn sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> + 'a> {
todo!();
}
fn verify_not_after(
self: Box<Self>,
_t: SystemTime,
) -> Box<dyn sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> + 'a> {
todo!()
}
fn verify_with_certs(
mut self: Box<Self>,
certs: &Certs,
) -> sop::Result<Box<dyn sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> + 'a>> {
certs.certs.iter().for_each(|c| self.verify.push(c.clone()));
Ok(self)
}
fn with_session_key(
self: Box<Self>,
_session_key: sop::SessionKey,
) -> sop::Result<Box<dyn sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> + 'a>> {
todo!()
}
fn with_password(
mut self: Box<Self>,
password: sop::Password,
) -> sop::Result<Box<dyn sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> + 'a>> {
self.skesk_passwords.push(password);
Ok(self)
}
fn with_keys(
mut self: Box<Self>,
keys: &Keys,
) -> sop::Result<Box<dyn sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> + 'a>> {
keys.keys
.iter()
.for_each(|tsk| self.decryption_keys.push(tsk.clone()));
Ok(self)
}
fn with_key_password(
mut self: Box<Self>,
password: sop::Password,
) -> sop::Result<Box<dyn sop::ops::Decrypt<'a, RPGSOPOCT, Certs, Keys> + 'a>> {
self.key_passwords.push(password);
Ok(self)
}
fn ciphertext<'d>(
self: Box<Self>,
ciphertext: &'d mut (dyn io::Read + Send + Sync),
) -> sop::Result<
Box<dyn sop::ops::Ready<(Option<sop::SessionKey>, Vec<sop::ops::Verification>)> + 'd>,
>
where
'a: 'd,
{
Ok(Box::new(DecryptReady {
decrypt: *self,
ciphertext,
}))
}
}
struct DecryptReady<'a> {
decrypt: Decrypt,
ciphertext: &'a mut (dyn io::Read + Send + Sync),
}
impl sop::ops::Ready<(Option<sop::SessionKey>, Vec<sop::ops::Verification>)> for DecryptReady<'_> {
fn to_writer(
self: Box<Self>,
sink: &mut (dyn io::Write + Send + Sync),
) -> sop::Result<(Option<sop::SessionKey>, Vec<sop::ops::Verification>)> {
let (msg, _) =
Message::from_reader(DebugWrapper(BufReader::new(self.ciphertext))).expect("FIXME");
let Message::Encrypted { esk, .. } = &msg else {
panic!("not encrypted");
};
let mut sk = None;
for cert in &self.decrypt.decryption_keys {
for dec in cert.decryption_capable_component_keys() {
let mut card = get_card(
dec.public_params(),
openpgp_card::ocard::KeyType::Decryption,
)
.expect("FIXME");
for e in esk {
if let Esk::PublicKeyEncryptedSessionKey(pkesk) = e {
let res = card::do_on_card(
&mut card,
openpgp_card::ocard::KeyType::Decryption,
&self.decrypt.key_passwords,
&|| {},
|cs| {
let sk = if let Ok(Ok(plain_session_key)) = cs.decrypt(
&Password::empty(),
pkesk.values().expect("FIXME"),
EskType::V3_4,
) {
Some(plain_session_key)
} else {
None
};
Ok(sk)
},
);
if let Ok(Some(psk)) = res {
sk = Some(psk);
break;
}
}
}
}
}
let Some(sk) = sk else {
unimplemented!("no session key obtained")
};
let inner = msg.decrypt_with_session_key(sk.clone()).unwrap();
let Ok(mr) =
rpgpie::message::unpack(inner, vec![], vec![], vec![], &[], &self.decrypt.verify)
else {
return Err(Error::BadData);
};
let session_key = match sk {
PlainSessionKey::V3_4 { sym_alg, ref key } => {
sop::SessionKey::new(u8::from(sym_alg), key).ok()
}
_ => None,
};
let verifications = util::result_to_verifications(&mr);
sink.write_all(&mr.cleartext).expect("FIXME");
Ok((session_key, verifications))
}
}