GithubHelp home page GithubHelp logo

rpgp / rpgp Goto Github PK

View Code? Open in Web Editor NEW
693.0 13.0 74.0 2.08 MB

OpenPGP implemented in pure Rust, permissively licensed

Home Page: https://docs.rs/pgp

License: Apache License 2.0

Rust 99.48% Scheme 0.32% Shell 0.20%
rust pgp cryptography openpgp

rpgp's Introduction

rPGP


OpenPGP implemented in pure Rust, permissively licensed

rPGP is the only pure Rust implementation of OpenPGP, following the main RFCs

See IMPL_STATUS.md for more details on the implemented PGP features.

It offers a flexible low-level API and gives users the ability to build higher level PGP tooling in the most compatible way possible. Additionally it fully supports all functionality required by the Autocrypt 1.1 e-mail encryption specification.

Usage

> cargo add pgp

Load a key and verify a message

use std::fs;
use pgp::{SignedSecretKey, Message, Deserializable};

let key_file = "key.sec.asc";
let msg_file = "msg.asc";

let key_string = fs::read_to_string("key.sec.asc").unwrap(),
let (secret_key, _headers) = SignedSecretKey::from_string(&key_string).unwrap();
let public_key = skey.public_key();

let msg_string = fs::read_to_string("msg.asc").unwrap();
let (msg, _headres) = Message::from_string(msg_string).unwrap();

// Verify this message
msg.verify(&pkey).unwrap();

let msg_content = msg.get_content().unwrap(); // actual message content

Current Status

Last updated April 2024

Users & Libraries built using rPGP

  • Delta Chat: Cross-platform messaging app that works over e-mail
  • rpm: A pure rust library for parsing and creating RPM files
  • rpgpie: An experimental high level OpenPGP API
  • rsop: A SOP CLI tool based on rPGP and rpgpie
  • debian-packaging: a library crate for dealing with Debian packages

Don't see your project here? Please send a PR :)

FAQs

Checkout FAQ.md.

Minimum Supported Rust Version (MSRV)

All crates in this repository support Rust 1.74 or higher. In future minimally supported version of Rust can be changed, but it will be done with a minor version bump.

License

This project is licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this project by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

rpgp's People

Contributors

bcmyers avatar cjrh avatar dadleyy avatar dignifiedquire avatar drahnr avatar echedellelr avatar flub avatar fmckeogh avatar haraldh avatar hko-s avatar hpk42 avatar indygreg avatar jeamland avatar jeffreybolle avatar jikstra avatar link2xt avatar lumag avatar r10s avatar reyk avatar roblabla avatar rudxain avatar rvolgers avatar sebastinas avatar sergey-kitov avatar skgland avatar sorairolake avatar vincentwo avatar wiktor-k avatar xynnn007 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rpgp's Issues

Encrypting file with public key

Hello, I need to encrypt data with public key and save it to the file.

I found snippet in tests that exercises encryption with private key, I adapted it a bit, and ended up with something like this (where PUBLIC_KEY is my PGP key using RSA2048):

fn encrypt(text: &str) {
    let mut rng = thread_rng();
    let (key, _headers) = SignedPublicKey::from_string(PUBLIC_KEY).expect("Failed to parse key");
    let ciphertext = key.encrypt(&mut rng, text.as_bytes()).expect("Failed to encrypt data");
}

That seems to work, but I cannot figure out, how to write this ciphertext to the file, that can be later decrypted with GnuPG. I tried naively to iterate over ciphertext vector and write bytes, but that doesn't work.

gpg: no valid OpenPGP data found.
gpg: decrypt_message failed: Unknown system error

I would be really grateful for a hint what I am missing.

excessive logging

Hi, I wonder if rpgp could log with debug!() and trace!() instead of info!()? The info log level is usually the default but rpgp is quite verbose and not so helpful in applications that aren't always interested in its internals. The workaround is to use log filters but this is quite a hack.

Unused error types

error.rs defines many types that are not used anywhere, such as InvalidChecksum, InvalidArmorWrappers etc.

Should they be cleaned up?

Can't verify cross-signed ids using Signature::verify_certificate

pgp::packet::Signature::verify_certificate assumes that the issuing key is also the key that had the id signed to it. This isn't the case when you have signed someone else's identity, in that case you're signing their (PublicKey, UserId) pair using your key.

It might be a while till I can throw together a small testcase, but I encountered this while verifying my signatures from https://nemo157.com/gpg, and adding an extra parameter to take both keys appears to verify at least the cross-signing CertGeneric signatures fine.

Support for DSA and ElGamal

Currently, DSA and ElGamal (encrypt-only) are still MUST algorithms of RFC4880. Are there any plans to support them for reasonable key sizes (i.e. >= 2048/256)?

Benchmarks

There should be some, to make sure things are fast

Repo is quite big

The repository is quite big, currently cloning and it seems like it's around 1gb. If i remember it correctly there's some huge test data laying around, can we remove that or move it into another repository? Or any other ideas? I'm currently building -desktop on various platforms and cloning 1gb of data every time is no fun :D

Message.encrypt_to_keys can't accept both SignedPublicKey and SignedPublicSubKey

encrypt_to_keys accepts pkeys: &[&impl PublicKeyTrait], so the slice has to consist of structures of the same type.

One solution would be to accept trait objects. Another is to accept some type which implements From both for SignedPublicKey and SignedPublicSubKey, and maybe some other types implementing PublicKeyTrait.

This is needed to implement proper key seletion in Delta Chat, see deltachat/deltachat-core-rust#817

Implement EdDSA encryption

It prevents usage of ECC keys in Delta Chat, leading to issues like this: deltachat/deltachat-core-rust#802 Keys are imported successfully, but an attempt to send a message to myself in DC command line client results in this error:

> send Hi!
[DC_EVENT_ERROR] PGP: Unimplemented("encryption with EdDSA")
{Received MsgFailed { chat_id: 25, msg_id: MsgId(1000) }}
Error: PGP: Unimplemented("encryption with EdDSA")

ECC keys support is also needed to resolve deltachat/deltachat-core-rust#509

Going to try implementing it.

Lack of documentation

The lack of documentation and examples makes it really difficult to get started with this exquisite library, especially since the names do not allow to derive clear usage from them since there are many types with overlapping names.
I.e. key loading works from multiple types, Vec<u8>, &[u8], String but it is not specified what formatting those types should have inherent.

Clear secrects

Need to as a baseline, zero out memory that was used to store secret data.

Write fuzz tests

Should fuzz all inputs, to ensure stability against malicious inputs

no_std support

This will allow using rpgp on any platform LLVM can target. For the use-cases I am wanting, alloc is fine.

There may be a bug public.rs, please see code section with comment.

        PublicParams::ECDSA { ref curve, ref p } => f
            .debug_struct("PublicParams::ECDSA")
            .field("curve", curve)
            .field("p", &p)
            .finish(),
        PublicParams::ECDH {
            ref curve,
            ref p,
            hash,
            alg_sym,
        } => f
            .debug_struct("PublicParams::ECDSA")
                                                          // Should be ECDH?
            .field("curve", curve)
            .field("hash", hash)
            .field("alg_sym", alg_sym)
            .field("p", &p)
            .finish(),

PublicParams::Elgamal {

Fingerprints?

Hello,

In the current implementation is there any way of retrieving the fingerprint from a public key?

Can signatures be read, added and removed? I can't find much on Docs.rs but the current codebase is newer.

Thanks!

Error after make on OSX 10.12

When I run make in /pgp-ffi/ I get an error:
/Users/me/rpgp/pgp-ffi/../ && cargo test --release -p pgp_ffi error: failed to parse manifest at /Users/me/rpgp/Cargo.toml
Caused by: feature 'rename-dependency' is required

I have cargo 1.30.0
I had no rust installed (it was installed by running make)

Update curve25519 crate?

curve25519-dalek has been forked into curve25519-dalek-ng: https://twitter.com/hdevalence/status/1356831666124197890
It has not much changes yet, but updates rand and rand_core packages.

We still can't update to curve25519-dalek-ng because rpgp depends on curve25519-dalek indirectly through ed25519-dalek which has not been forked and still depends on version 3 of curve25519-dalek, while the fork has bumped the version to 4. See related issue zkcrypto/curve25519-dalek-ng#8

Generate a SignedSecretKey unlocked from one that's locked

I'm trying to generate a SignedSecretKey that's unlocked from a locked one, but the only thing I can do is unlock each secret key in the SignedSecretKey individually. Is there a way to do so, on top of that, i also need to do the inverse step. I can go down to the SecretParams and unlock those but then I cannot create the SecretKey because the attributes are private.

Invalid handling of encoding when decrypting

Hello,
while trying to decrypt a message I stumbled upon errors in the handling of UTF-8 data.

I attached the test message generated by opengpgjs. I can decrypt this totally fine with gpg shipped in ubuntu 18.04. When decrypting this here I get {"secret":"â¦Â·â^¨Ë~üöä-.,#+"}.
The input is {"secret":"…·–^¨˝’~üöä-.,#+"}

test_message.zip
Key password: asd

Test Code

Oh and also your docs.rs are not building currently.

Cleartext signature framework support (gpg --clearsign)

Currently there does not appear to be support for the plaintext signature framework as described in RFC4880 section 7.

This style of signature involves a message which starts with a "-----BEGIN PGP SIGNED MESSAGE-----" header, followed by an inline, non-base64-encoded cleartext message body, followed by a regular ASCII armored PGP signature.

The GPG command line tool produces such signatures when invoked with --clearsign.

signature time is not equal before and after parsing

I tried the following where signing key and verification key are both loaded successfully.

        let digest = &[0u8; 32][..];

        // stage 1
        let signature = signing_key
            .create_signature(passwd_fn, ::pgp::crypto::HashAlgorithm::SHA2_256, digest)
            .expect("Failed to crate signature");

        verification_key
            .verify_signature(
                ::pgp::crypto::HashAlgorithm::SHA2_256,
                digest,
                &signature,
            )
            .expect("Failed to validate signature");

        // stage 2: check parsing success
        let wrapped = ::pgp::Signature::new(
            ::pgp::types::Version::Old,
            ::pgp::packet::SignatureVersion::V4,
            ::pgp::packet::SignatureType::Binary,
            ::pgp::crypto::public_key::PublicKeyAlgorithm::RSA,
             ::pgp::crypto::hash::HashAlgorithm::SHA2_256,
            [digest[0], digest[1]],
            signature,
            vec![
                ::pgp::packet::Subpacket::SignatureCreationTime(::chrono::offset::Utc::now()),
                ::pgp::packet::Subpacket::Issuer(signing_key.key_id()),
            ],
             vec![],
        );

        let mut x = Vec::with_capacity(1024);
        use std::io::Cursor;

        let mut buff = Cursor::new(&mut x);
        ::pgp::packet::write_packet(&mut buff, &wrapped).expect("Write should be ok");

        log::debug!("{:02x?}", &x[0..15]);
        use itertools::Itertools;
        let mut parser = ::pgp::packet::PacketParser::new(x.as_slice());
        assert!(parser.any(|packet| {
            match packet {
                Ok(::pgp::packet::Packet::Signature(sig_packet)) => { dbg!(sig_packet) == wrapped },
                x => { let _ = dbg!(x); false}
            }
        }));

but the equivalence sign never seems to trigger, there is one instance of a key packet, and from the debugger view it seems to be equivalent.

Is there any issue in the above code?

pgp no longer builds due to ed25519-dalek moving to v1.0.0-pre.4

Since ed25519-dalek moved to v1.0.0-pre.4 (from v1.0.0-pre.3) approximately 15 hours ago, pgp no longer builds due to a change in the ed25519-dalek API.

Concurrent with this issue, I'm submitting a PR that fixes this.

The fix involves:

  • Using the following now required traits in src/crypto/eddsa.rs: signature::{Signature, Signer, Verifier}
  • Bringing in the signature crate as an explicit dependency (as this is where the above traits are exported)

pgp-ffi not building anymore

I'm currently getting this error on all ci/local deb building scripts:

Step 12/12 : RUN true     && cd /rpgp/pgp-ffi     && PREFIX=/opt/DeltaChat/rpgp make install
 ---> Running in 76480efd4de7
cd /rpgp/pgp-ffi/../ && RUSTFLAGS="-C codegen-units=1" cargo build --release --features nightly -p pgp_ffi
    Updating crates.io index
error: no matching package named `pgp` found
location searched: /rpgp
perhaps you meant: pgp
required by package `pgp_ffi v0.1.0 (/rpgp/pgp-ffi)`
make: *** [build-stamp] Error 101
Makefile:45: recipe for target 'build-stamp' failed
The command '/bin/sh -c true     && cd /rpgp/pgp-ffi     && PREFIX=/opt/DeltaChat/rpgp make install' returned a non-zero code: 2

What's the correct way to build and install rpgp? We should maybe also put that in the README.

Can we make a new git tag?

Cloning from a specific commit is not that easy (sure it is, it just needs 2 git commands but i need to update all ci scripts for this), having a git tag would be easier.

Loading keys

KeyType implements Serialize which offres a to_bytes function, but there doesn't appear to be a function to load such serialization.

Signing based on `Read` trait instead of slices

It would be advantageous to provide a way to sign multiple existing slices.
The easiest way would be to introduce API consuming a R: Read type which the user can than implement as desired. Otherwise, especially if parsing chunked external data, it would be necessary to copy the data.

tests directory makes pulling from this repo unwiedly

the "tests" directory clocks in at 466MB -- that's a bit unwiedly in eg docker steps that simply pull from rpg. also i am uploading docker files to the docker hub and that then means i need to upload 500MB as well from my 5Mbit upload connection (if even that). And when RPGP changes i need to do it again ...

What i'd like to have: the most recent RPGP version that was built and tested in this repository here, and getting just enough data to compile and install RPGP.

update to rand 0.7

Hi,

rpgp uses rand 0.6 while we're currently at rand 0.7. The APIs are not compatible but rpgp needs an "old"-style rng for encryption. I could prepare a diff but unfortunately some of rpgp's dependencies are also stuck on the old rand crate so it isn't that easy.

My current hack...workaround with the release version of rpgp is to include both rand crates in my project:

rand = "0.7"
old_rand = { version = "0.6", package = "rand" }

..to use it for encrypt_to_keys:

let mut rng = old_rand::thread_rng();

Reyk

Message::verify() succeeds when gpg does not

I'm trying to verify a message has been signed by the given public key. To test this I tried modifying the contents of the ASCII message, expecting Message::verify() to produce an error, but it did not. I then used gpg --verify signed_message.sig, which produced

gpg: CRC error; 2E424B - 1BE5BF
gpg: no signature found
gpg: the signature could not be verified.

Code Snippet:

let message = Message::from_armor_single(data).unwrap().0;
let verify = &message.verify(&public_key);

When I dbg!(message) I can see it is Message::Compressed. As a test I produced a new signed message using gpg --output signed_message.sig --sign --compress-level 0 --armor message.toml. This produced a Message::Signed and after modifying the contents of the message, Message::verify() produced an Error as expected.

bug: dearmor hangs forever if end marker is missing.

The following test case for src/armor/reader.rs triggers an issue where the dearmor code hangs forever. I figured out that it's related to the fact that the end marker is missing.

    #[test]
    #[should_panic]
    fn test_parse_armor_missing_end_marker() {
        let c = Cursor::new(
            "-----BEGIN PGP PUBLIC KEY BLOCK-----\n\
             Version: GnuPG v1\n",
        );
        // pgp 0.4.0 would hang forever if the end marker is missing.
        let _ = parse(c).unwrap();
    }

Other input examples:

  • "-----END PGP\n" correctly returns an error.
  • "Hello, World!" hangs forever.

Allow usage of externally loaded keys

Currently it is very difficult to work with keys already present i.e. an RSAPrivateKey without re-encoding it to asc and then decoding it which is a needless roundtrip.

Could this be possibly added, such that there is public API to take SecretKeyParams and PublicKeyParams from "outside"?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.