openpgp 0.2.0

Read and write OpenPGP (RFC4880) files
openpgp-0.2.0 doesn't have any documentation.

The goal of this crate is to interact with the OpenPGP-format, i.e. parse it and produce correct PGP files. OpenPGP can describe so many things that parsing is much more pleasant to write in an event-driven way, and the resulting API is also smaller.

This version is not yet able to produce encrypted content, but signed messages should work, as demonstrated by the following example, which reads a private key (in the format output by gpg --export-secret-keys -a), signs a message and reads it back, verifying the signature.

PGP files are split into packets, with different meanings.

use openpgp::*;
use openpgp::key::*;
use std::collections::HashMap;

struct P {
    keys: HashMap<u64, key::PGPKey>,
    data: Vec<u8>,
    password: &'static [u8],
}

impl PGP for P {

    fn get_key<'a>(&'a mut self, keyid: u64) -> Option<&'a key::Key> {
        self.keys.get(&keyid).and_then(|x| Some(&x.key))
    }

    fn get_signed_data(&mut self, _: signature::Type) -> &[u8] {
        &self.data
    }
   
    fn get_password(&mut self) -> &[u8] {
        &self.password
    }
   
    fn public_key(&mut self, public_key: key::PGPKey) -> Result<(), Error> {
        let id = public_key.long_id();
        println!("public key {:?}", id);
        if !self.keys.contains_key(&id) {
            self.keys.insert(id, public_key);
        }
        Ok(())
    }

    fn secret_key(&mut self, secret_key: key::PGPKey) -> Result<(), Error> {
        self.public_key(secret_key)
    }
   
    fn literal(&mut self, file_name:&str, date:u32, literal: &[u8]) -> Result<(), Error> {
        println!("literal: {:?} {:?}", file_name, date);
        self.data.clear();
        self.data.extend(literal);
        Ok(())
    }
   
    fn signature_verified(&mut self, is_ok:bool) -> Result<(), Error> {
        println!("Verified: {:?}", is_ok);
        Ok(())
    }

}
let secret_key = "-----BEGIN PGP PRIVATE KEY BLOCK-----\nVersion: GnuPG v2\n\nlQPGBFeWBdYBCADZtx24u+o/1nN+7L/OzXY8icC72AI93U8TGMg4jEDmuDJkMThu\nWviYQpC4JbJJMBHeZcfzXragSVJKJNZCKsRcZ+lbJqv/EARlfkgIdP0aN0tcPMjp\nmN4sZU8BD2dCmWGG9ZBiZ3dpPfvKPzOiWuMrabsznDDWBSRVWviceiqASjdD6Q58\nGGXie5xwlnh2PbfENtCImn+Kuzn/nNa1iaL+g4TEo4fMMEyuarMU79PI4OSf3x78\nujKY77i2upZ4NYMoPqqEG89CgtuTnQkMGGg8T1HAU+AD00OYZS+DesoUWCf3BuyF\nAcUuuQdi9pZbXYM1SbWLtI1/fQqFTzufmmppABEBAAH+BwMCatGKnKN96hnrz8F/\n02ACLJinv+781dfKfcPFHoQ24zplM9AjIRASpV6PC3CJb+rtKsj8vdeFv253Nhpp\nWWlA/T58ZQjTfuXEg72cvij9HdMU70FF2WDt8ZOUszoTHfbQouf3leFQovTcmwZu\ndNRQMEGn/bcder3+dt5gg3ZC0C2mzpQxlXY9Z3R9RaUuhiimleh7eKfEPTZXlnaO\nLHMQ4yIOHD9ML8CPZtbEPRcx7h9GBjyxea9D55I7czgMC92fvkWbfykNDmbo6RPl\nqBDjgHwJlnJH9JphTExbxblWam/18u7Rjov8geAY0r3EUV0wpFJQMLKbIj9ukj0k\nXsiCnUpXD/IH25fDxya+7SzQAHJ4p70czB62O764BeeVD996XTpnVOPYAG3DE/sm\n9rPRD2cihQwRmvwVviO60BkiWjCmXRtU/gExgKIxyyHmBgEWv6B7dMBVg5VrifHd\n8/V4vYLlXbqIN++S7AabRp9ucBXVopsvH3B38tfvzbcQwELpDHvT3DXVBbikotzl\nshJeAqDGbaZSKSejuVHgWJHNHyxziTcM5fmOgpxm2yuRsvSzK3yuSzUKvjCXvfUi\nsgvrvtyKed2C+Wf47+nXsWkEImi/+S5Gyi0/xFn7L0BbRS32SEpB4tST7o6KbCRi\nBNgCoh1rdeER/D5snDAjKOzX/kq/x/7cV8wuylODXL1yNa6kvhNpXWjEuq0vtsUJ\nbee8zNsH+WEj4vO5gXRWm2IBvWOKUwwN2j+Mu7IO3SBwcraGHQ4SAYo4+JzrAp4n\naoQL8jf8aQucqPnyXSjc0nG9QciF4NjQp58iPCb3umy2rjo+upYJ2ZZASH3RnIx5\nbyri7cdeZUTP6zyixmjui3vn8c1SK7Ie2j/GBphy+rm5MlonNjTemnX62eWubkxH\nxDkmlI1eOAlttCZQaWVycmUtw4l0aWVubmUgTWV1bmllciA8cGVAcGlqdWwub3Jn\nPokBNwQTAQgAIQUCV5YF1gIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgAAKCRAU\nelLpMLYCImgCB/4mrdC6Wa0nmQqmfP+VZX9Z+zxbceSgbkYSpPW6PEzlprM/pZs0\niOUuAXPRSOnNeGmqPKyT9uU2FnrIVg5MVSB3D27cn0DFSAsteP7CCEAldUeJrhod\nawibqrrbCz00+Sx4u5HxmugcYxn/L6TGkUFuiKocV1DxaUSdVmRqYxrLz0aBqVqT\ng8B7l9y6dJvzMMUBeW4ROtQZbJjznd3gMa77PkhHjaFoMqd0pCBcl7Kv4CC9OGx2\nnvMda9pVERujF1MOwz25CBQLZsS6fEzVRJh+9qj5RtId6VRjZyVYWFqlUkEAZZ8Z\nc/wG75zGj2TnAx40gllJ09tgiyqbWG/0s7ppnQPGBFeWBdYBCADtRNwTUXaTxVts\nvAKLWrlosmcpSDoNci9jqrF/+OYJcHeE89m2ouv8lrvJlRWSX85i2PMYqp3kEa2I\nW5/Eh3i13USoAScCYMoCqeTSfDefX4X24Q3i3JTu2CUxJm5Nacmn7lf0vaNjxYNP\n8mWHujG0CaiEdjW1x+8lx15eoMENfo7eScgEdrQVuLcafOduPZpbrplUtKYYOM8/\n4vvNfxYkPMhL//BiuVXG4r5nQpvc96lS4083N5J14NeKwTduS6J68w92J3SbigTB\nV1RVqZ296CNIJTrGdjPYz/4LQaCa1P0jFeNJHAdPqdBPwO1/PYm4BIpMXGlCdMEm\nJHGvdgyHABEBAAH+BwMC9g9MFatna+jr33gZZ4avfhBpobRc4gNtL/zO6bKVKW1b\nNhBqGnBKVa3IOdD86QduTyNGqiZ8o6GXEWs4U4bvsOfJIiuhaN2EOlOJ7ic/qRU2\nCLo2CkurXmNI8ThH9Y6FldxhqmMLEpZZexo6FsknOd3iTVlW8E8wmjOQTpu7DprJ\nu92vOiFwa6jnsWJREDdqEPnZH/2Ymmz5aoNrS/+AmgIrE+nOH2o8vOTeBSdMg9sj\nCcPdToWSAuYgdDQvrV+7RblqV1HFVPy3kNOoLCB98F3DZrDe5zkoI68EAExyJelO\nKVR6oxXyNStyyB2odOCrUJgNW4SEUrqH3La9MxxVQRkZACKTLQa2lBgskOz0mKDy\nrrX8sQl7p4OwdPLf6s0rTPs6PVw5WZj+F9lnzf4akIRXfnScWZvnqLDzYE/iiPd1\n7x4pr2iQhLMs9ilPmq0QGWHOqlfo/HT3RgQF5P5wf0cJXjtUsE6ZGvSygMl+KAgu\nQZsP+vf96USRyOMQuMULi7EctNrimPko1AxvsSPgSw9FX+cRXaFyBEsSihsGsK2i\nXcMIKGU9D90NFiW7qehgM3Hb/BkwwKeRxAG46DvMtCV06eV3inp82ZtjWU7WWZ1z\nIVO2hprrehPRz6BVz/vDRF8fPnqhGJMKzBWlIwB4LpQIFKZHbYpQ/3SP1MBMe4I/\nwJz6BxdKrXQD6YVVoiq/5L88KXmd3X1Snu+th4oaBdU/bexlBcUtA8Lpw6GoA7Ot\ns5ZQ+ms2ANAyELYYDth12FYIMEKxuf/rJGhuNKoSLWTYrSZae/vGRnG5cSDZKEsC\nuxeVGbb6ug4uyVnDFQ/EHyuKHs4iUMq37KzkiKRUTw8RDPU70tWK27bJ08MROwyt\niOnitjE+sOHU+lxiVq4sQEAIAUQklPa8l+/8WwQkFzczPtk1iQEfBBgBCAAJBQJX\nlgXWAhsMAAoJEBR6UukwtgIiBOEH/Rc9c21Ljpe6OWC1XslV0AVeQWeTc0pZKTR4\nCW1nqSzqin2ajAmfxFXP3Ngtb6z90FzF2unTubwxiiwWvM61oZ3+RLK4L0yd8TmX\n5Zbk+eQ4ucz0XXrsDPC+aPV3aWjAZb8NflIQYlYiRvTEX9ZMgy7DgVBsgJCqTmUG\nihjoTLeKdjYQTFEIsPsePfbvRdDqdtZUXd9JCq+eMr/dLd4oJmCsvFMDPPGfW7rw\n5rPd0/9nwNu0Bst0PAiOliHYmRfSYy9l15wy8FrVIsJGqpEDotzo+sXicZWTtUuA\nIbBVag5seqXE70GhZ+pdSx+dJNE55NOlCzw4Y2yc6HbeVeguIXY=\n=USRz\n-----END PGP PRIVATE KEY BLOCK-----\n";

let contents = b"Moi non plus, Bob";
let mut p = P {
    keys: HashMap::new(),
    data: contents.to_vec(),
    password: b"blabla blibli",
};

{
    let mut sk = secret_key.as_bytes();
    let sk = read_armored(&mut sk);
    let mut sk = &sk[..];
    parse(&mut p, &mut sk).unwrap();
};

let mut s = Vec::new();
{
    let mut buf = Vec::new();

    let now = std::time::SystemTime::now();
    let now = now.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as u32;
    if let Some(&Key::Secret(ref sk)) = p.keys.get(&1475582989415350818).and_then(|pgp| Some(&pgp.key)) {
        sk.sign(&mut buf,
                contents,
                signature::Type::Binary,
                &[signature::Subpacket::SignatureCreationTime(now)],
                &[signature::Subpacket::Issuer(1475582989415350818)])
          .unwrap();
        packet::write(&mut s, packet::Tag::Signature, &buf).unwrap();
    }
}
let mut slice = &s[..];
parse(&mut p, &mut slice).unwrap();