summaryrefslogtreecommitdiffstats
path: root/openpgp/benches/common/decrypt.rs
blob: 48f157c5978e034312de2bb7f44436548a570a70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
use sequoia_openpgp::cert::Cert;
use sequoia_openpgp::crypto::{Password, SessionKey};
use sequoia_openpgp::packet::prelude::*;
use sequoia_openpgp::packet::{PKESK, SKESK};
use sequoia_openpgp::parse::stream::{
    DecryptionHelper, DecryptorBuilder, MessageStructure, VerificationHelper,
};
use sequoia_openpgp::parse::Parse;
use sequoia_openpgp::policy::StandardPolicy;
use sequoia_openpgp::types::SymmetricAlgorithm;
use sequoia_openpgp::{Fingerprint, KeyHandle, Result};

use std::io::Write;

// Borrowed from the examples at
// sequoia_openpgp::parse::stream::DecryptionHelper
// sequoia_openpgp::parse::stream::Decryptor
struct PasswordHelper {
    password: Password,
}

impl VerificationHelper for PasswordHelper {
    fn get_certs(&mut self, _ids: &[KeyHandle]) -> Result<Vec<Cert>> {
        Ok(Vec::new())
    }
    fn check(&mut self, _structure: MessageStructure) -> Result<()> {
        Ok(())
    }
}

impl DecryptionHelper for PasswordHelper {
    fn decrypt<D>(
        &mut self,
        _pkesks: &[PKESK],
        skesks: &[SKESK],
        _sym_algo: Option<SymmetricAlgorithm>,
        mut decrypt: D,
    ) -> Result<Option<Fingerprint>>
    where
        D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool,
    {
        // Finally, try to decrypt using the SKESKs.
        for skesk in skesks {
            if skesk
                .decrypt(&self.password)
                .map(|(algo, sk)| decrypt(algo, &sk))
                .unwrap_or(false)
            {
                return Ok(None);
            }
        }

        Err(anyhow::anyhow!("Wrong password!"))
    }
}

// This is marked as dead_code. Seems that using a function only from within
// a benchmark loop hides it from the compiler.
#[allow(dead_code)]
// Decrypts the given message using the given password.
pub fn decrypt_with_password(
    sink: &mut dyn Write,
    ciphertext: &[u8],
    password: &str,
) -> sequoia_openpgp::Result<()> {
    let password = password.into();
    // Make a helper that that feeds the password to the decryptor.
    let helper = PasswordHelper { password };

    // Now, create a decryptor with a helper using the given Certs.
    let p = &StandardPolicy::new();
    let mut decryptor = DecryptorBuilder::from_bytes(ciphertext)?
        .with_policy(p, None, helper)?;

    // Decrypt the data.
    std::io::copy(&mut decryptor, sink)?;

    Ok(())
}

// Borrowed from the examples at
// sequoia_openpgp::parse::stream::DecryptionHelper
// sequoia_openpgp::parse::stream::Decryptor
struct CertHelper<'a> {
    cert: &'a Cert,
}

impl VerificationHelper for CertHelper<'_> {
    fn get_certs(&mut self, _ids: &[KeyHandle]) -> Result<Vec<Cert>> {
        Ok(Vec::new())
    }
    fn check(&mut self, _structure: MessageStructure) -> Result<()> {
        Ok(())
    }
}

impl DecryptionHelper for CertHelper<'_> {
    fn decrypt<D>(
        &mut self,
        pkesks: &[PKESK],
        _skesks: &[SKESK],
        sym_algo: Option<SymmetricAlgorithm>,
        mut decrypt: D,
    ) -> Result<Option<Fingerprint>>
    where
        D: FnMut(SymmetricAlgorithm, &SessionKey) -> bool,
    {
        let p = &StandardPolicy::new();

        // check that pkesk has right recipient
        // if yes, use decrypt function
        let keys: Vec<Key<key::SecretParts, key::UnspecifiedRole>> = self
            .cert
            .keys()
            .with_policy(p, None)
            .for_transport_encryption()
            .for_storage_encryption()
            .secret()
            .map(|amalgamation| amalgamation.key().clone().into())
            .collect();

        let successful_key = keys
            .iter()
            .cloned()
            .filter_map(|key| {
                pkesks
                    .into_iter()
                    .find(|pkesk| pkesk.recipient() == &key.keyid())
                    .map(|pkesk| (pkesk, key))
            })
            .find(|(pkesk, key)| {
                let mut keypair = key.clone().into_keypair().unwrap();
                pkesk
                    .decrypt(&mut keypair, sym_algo)
                    .map(|(algo, sk)| decrypt(algo, &sk))
                    .unwrap_or(false)
            })
            .map(|(_, key)| key.fingerprint());

        match successful_key {
            Some(key) => Ok(Some(key)),
            None => Err(anyhow::anyhow!("Wrong cert!")),
        }
    }
}

// This is marked as dead_code. Seems that using a function only from within
// a benchmark loop hides it from the compiler.
#[allow(dead_code)]
// Decrypts the given message using the given password.
pub fn decrypt_with_cert(
    sink: &mut dyn Write,
    ciphertext: &[u8],
    cert: &Cert,
) -> sequoia_openpgp::Result<()> {
    // Make a helper that that feeds the password to the decryptor.
    let helper = CertHelper { cert };

    // Now, create a decryptor with a helper using the given Certs.
    let p = &StandardPolicy::new();
    let mut decryptor = DecryptorBuilder::from_bytes(ciphertext)?
        .with_policy(p, None, helper)?;

    // Decrypt the data.
    std::io::copy(&mut decryptor, sink)?;

    Ok(())
}