summaryrefslogtreecommitdiffstats
path: root/openpgp/examples/decrypt-with.rs
blob: bed1677cc15eda0a54cfc385533f3ac03e9041a9 (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
/// This program demonstrates how to decrypt a stream of data.

use std::env;
use std::io;
use std::collections::HashMap;

extern crate openpgp;
use openpgp::{
    Packet,
    KeyID,
    Key,
    TPK,
    SecretKey,
};
use openpgp::parse::PacketParserResult;

pub fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        panic!("A simple decryption filter.\n\n\
                Usage: {} <keyfile> [<keyfile>...] <input >output\n", args[0]);
    }

    // Read the transferable secret keys from the given files.
    let mut keys: HashMap<KeyID, Key> = HashMap::new();
    for f in args[1..].iter() {
        let tsk = TPK::from_reader(
            // Use an openpgp::Reader so that we accept both armored
            // and plain PGP data.
            openpgp::Reader::from_file(f)
                .expect("Failed to open file"))
            .expect("Failed to read key");
        for key in tsk.keys() {
            // XXX this is cheating, we just add all keys, even if
            // they should not be used for encryption
            keys.insert(key.fingerprint().to_keyid(), key.clone());
        }
    }

    #[derive(PartialEq)]
    enum State {
        Start(Vec<openpgp::PKESK>, Vec<openpgp::SKESK>),
        Deciphered,
        Done,
    }
    let mut state = State::Start(vec![], vec![]);
    let mut input = io::stdin();
    let mut ppr
        = openpgp::parse::PacketParser::from_reader(
            openpgp::Reader::from_reader(&mut input)
                .expect("Failed to build reader"))
        .expect("Failed to build parser");

    while let PacketParserResult::Some(mut pp) = ppr {
        state = match state {
            // Look for an PKESK or SKESK packet.
            State::Start(mut pkesks, mut skesks) =>
                match pp.packet {
                    Packet::SEIP(_) => {
                        let mut state = None;
                        for pkesk in pkesks.iter() {
                            if let Some(tsk) = keys.get(&pkesk.recipient) {
                                if let Some(SecretKey::Unencrypted{ref mpis}) =
                                    tsk.secret()
                                {
                                    if let Ok((algo, key)) = pkesk.decrypt(tsk, mpis) {
	                                let r = pp.decrypt(algo, &key[..]);
                                        if r.is_ok() {
                                            state = Some(State::Deciphered);
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        state.unwrap_or(State::Start(pkesks, skesks))
                    },
                    _ => State::Start(pkesks, skesks),
                },

            // Look for the literal data packet.
            State::Deciphered =>
                if let Packet::Literal(_) = pp.packet {
                    io::copy(&mut pp, &mut io::stdout())
                        .expect("Failed to copy data");
                    State::Done
                } else {
                    State::Deciphered
                },

            // We continue to parse, useful for dumping
            // encrypted packets.
            State::Done => State::Done,
        };

        let (packet, _, ppr_tmp, _) = pp.recurse()
            .expect("Failed to recurse");
        ppr = ppr_tmp;

        state = match state {
            // Look for an PKESK or SKESK packet.
            State::Start(mut pkesks, mut skesks) =>
                match packet {
                    Packet::PKESK(pkesk) => {
                        pkesks.push(pkesk);
                        State::Start(pkesks, skesks)
                    },
                    Packet::SKESK(skesk) => {
                        skesks.push(skesk);
                        State::Start(pkesks, skesks)
                    },
                    _ => State::Start(pkesks, skesks),
                },

            // Do nothing in all other states.
            s => s,
        };
    }

    if state != State::Done {
        panic!("decryption failed");
    }
}