Simple to use OpenPGP API based on Bouncycastle https://pgpainless.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Paul Schaub 8fffa3079a
PGPainless-0.2.1-SNAPSHOT
2 weeks ago
assets/test_vectors Add signed message of cryptie as test vector 1 year ago
config/checkstyle Bump checkstyle to 8.18 1 year ago
gradle/wrapper Bump gradle wrapper to 6.4rc1 10 months ago
pgpainless-core Add tests for PublicKeyAlgorithmPolicy 2 weeks ago
pgpainless-sop Prevent NPE in SOP when reading certificates 2 weeks ago
.editorconfig Add .editorconfig file 2 months ago
.gitignore Add bin/ to gitignore 2 years ago
.travis.yml Update travis ubuntu image to bionic 3 weeks ago
CHANGELOG.md PGPainless 0.2.1 2 weeks ago
CODE_OF_CONDUCT.md Add code of conduct 3 years ago
LICENSE Add license 3 years ago
README.md Fix link in README 2 weeks ago
build.gradle Remove build dependency on Android SDK 3 weeks ago
gradlew Bump gradle wrapper to 6.4rc1 10 months ago
gradlew.bat Bump gradle wrapper to 6.4rc1 10 months ago
settings.gradle Wip: Start implementing a SOP client 6 months ago
version.gradle PGPainless-0.2.1-SNAPSHOT 2 weeks ago

README.md

PGPainless - Use OpenPGP Painlessly!

Travis (.com) Maven Central Coverage Status JavaDoc Interoperability Test-Suite PGP

About

PGPainless aims to make using OpenPGP in Java projects as simple as possible. It does so by introducing an intuitive Builder structure, which allows easy setup of encryptionOptions / decryption operations, as well as straight forward key generation.

PGPainless is based around the Bouncycastle java library and can be used on Android down to API level 10. It can be configured to either use the Java Cryptographic Engine (JCE), or Bouncycastles lightweight reimplementation.

While signature verification in Bouncycastle is limited to signature correctness, PGPainless goes much further. It also checks if signing subkeys are properly bound to their primary key, if keys are expired or revoked, as well as if keys are allowed to create signatures in the first place.

These rigorous checks make PGPainless stand out from other Java-based OpenPGP libraries and are the reason why PGPainless currently scores second place on Sequoia-PGPs Interoperability Test-Suite.

At FlowCrypt we are using PGPainless in our Kotlin code bases on Android and on server side. The ergonomy of legacy PGP tooling on Java is not very good, and PGPainless improves it greatly. We were so happy with our initial tests and with Paul - the maintainer, that we decided to sponsor further development of this library.

-Tom @ FlowCrypt.com

Features

Most of PGPainless' features can be accessed directly from the PGPainless class. If you want to get started, this class is your friend :)

For further details you should check out the javadoc!

Easily Generate Keys

PGPainless comes with a simple to use KeyRingBuilder class that helps you to quickly generate modern OpenPGP keys. There are some predefined key archetypes, but it is possible to fully customize key generation to your needs.

        // RSA key without additional subkeys
        PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
                .simpleRsaKeyRing("Juliet <juliet@montague.lit>", RsaLength._4096);
                
        // EdDSA primary key with EdDSA signing- and XDH encryption subkeys
        PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
                .modernKeyRing("Romeo <romeo@montague.lit>", "I defy you, stars!");

        // Customized key
        PGPSecretKeyRing keyRing = PGPainless.generateKeyRing()
                .withSubKey(
                        KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256))
                                .withKeyFlags(KeyFlag.SIGN_DATA)
                                .withDetailedConfiguration()
                                .withDefaultSymmetricAlgorithms()
                                .withDefaultHashAlgorithms()
                                .withPreferredCompressionAlgorithms(CompressionAlgorithm.ZLIB)
                                .withFeature(Feature.MODIFICATION_DETECTION)
                                .done()
                ).withSubKey(
                        KeySpec.getBuilder(ECDH.fromCurve(EllipticCurve._P256))
                                .withKeyFlags(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)
                                .withDefaultAlgorithms()
                ).withMasterKey(
                        KeySpec.getBuilder(RSA.withLength(RsaLength._8192))
                                .withKeyFlags(KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER)
                                .withDefaultAlgorithms()
                ).withPrimaryUserId("Juliet <juliet@montague.lit>")
                .withAdditionalUserId("xmpp:juliet@capulet.lit")
                .withPassphrase("romeo_oh_Romeo<3")
                .build();

Encrypt and Sign Data

PGPainless makes it easy and painless to encrypt and/or sign data. Passed in keys are automatically evaluated, so that you don't accidentally encrypt to revoked or expired keys. PGPainless will furthermore detect which algorithms are supported by recipient keys and will negotiate algorithms accordingly. Still it allows you to manually specify which algorithms to use of course.

        EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
                .onOutputStream(outputStream)
                .withOptions(
                        ProducerOptions.signAndEncrypt(
                                new EncryptionOptions()
                                        .addRecipient(aliceKey)
                                        .addRecipient(bobsKey)
                                        // optionally encrypt to a passphrase
                                        .addPassphrase(Passphrase.fromPassword("password123"))
                                        // optionally override symmetric encryption algorithm
                                        .overrideEncryptionAlgorithm(SymmetricKeyAlgorithm.AES_192),
                                new SigningOptions()
                                        // Sign in-line (using one-pass-signature packet)
                                        .addInlineSignature(secretKeyDecryptor, aliceSecKey, signatureType)
                                        // Sign using a detached signature
                                        .addDetachedSignature(secretKeyDecryptor, aliceSecKey, signatureType)
                                        // optionally override hash algorithm
                                        .overrideHashAlgorithm(HashAlgorithm.SHA256)
                        ).setAsciiArmor(true) // Ascii armor or not
                );

        Streams.pipeAll(plaintextInputStream, encryptionStream);
        encryptionStream.close();

Decrypt and Verify Signatures

Decrypting data and verifying signatures is being done in a similar fashion. PGPainless will not only verify correctness of signatures, but also if the signing key was allowed to create the signature. A key might not be allowed to create signatures if, for example, it expired or was revoked, or was not properly bound to the key ring. Furthermore PGPainless will reject signatures made using weak algorithms like SHA-1. This behaviour can be modified though using the Policy class.

        DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
                .onInputStream(encryptedInputStream)
                .decryptWith(secretKeyProtector, bobSecKeys)
                .verifyWith(alicePubKeys)
                .ignoreMissingPublicKeys()
                .build();

        Streams.pipeAll(decryptionStream, outputStream);
        decryptionStream.close();

        // Result contains information like signature status etc.
        OpenPgpMetadata metadata = decryptionStream.getResult();

After the DecryptionStream was closed, you can get metadata about the processed data by retrieving the OpenPgpMetadata. Again, this object will contain information about how the message was encrypted, who signed it and so on.

Include PGPainless in your Project

PGPainless is available on maven central. In order to include it in your project, just add the maven central repository and add PGPainless as a dependency.

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.pgpainless:pgpainless-core:0.2.0'
}

About

PGPainless is a by-product of my Summer of Code 2018 project. For that project I was in need of a simple to use OpenPGP library.

Originally I was going to use Bouncy-GPG for my project, but ultimately I decided to create my own OpenPGP library which better fits my needs.

However, PGPainless is heavily influenced by Bouncy-GPG.

To reach out to the development team, feel free to send a mail: info@pgpainless.org

Development

PGPainless is developed in - and accepts contributions from - the following places:

Please follow the code of conduct if you want to be part of the project.