From 21f2a732ee7c9d511e50049e2e957f2fa1917fbb Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 27 May 2021 17:11:38 +0200 Subject: [PATCH] Update README --- README.md | 225 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 116 insertions(+), 109 deletions(-) diff --git a/README.md b/README.md index a2486cca..14b7bf0b 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,130 @@ -PGPainless - Use OpenPGP Painlessly! -==================================== +# PGPainless - Use OpenPGP Painlessly! [![Travis (.com)](https://travis-ci.com/pgpainless/pgpainless.svg?branch=master)](https://travis-ci.com/pgpainless/pgpainless) [![Git Tag](https://badgen.now.sh/github/tag/pgpainless/pgpainless)](https://github.com/pgpainless/pgpainless/tags) [![Coverage Status](https://coveralls.io/repos/github/pgpainless/pgpainless/badge.svg?branch=master)](https://coveralls.io/github/pgpainless/pgpainless?branch=master) [![JavaDoc](https://badgen.net/badge/javadoc/yes/green)](https://pgpainless.org/releases/latest/javadoc/) -[![Interoperability Test-Suite](https://badgen.net/badge/interoperable/yes/green)](https://tests.sequoia-pgp.org/) +[![Interoperability Test-Suite](https://badgen.net/badge/Sequoia%20Test%20Suite/%232/green)](https://tests.sequoia-pgp.org/) -About ------ +## 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 / decrytion operations, as well as straight forward key generation. +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. -### NOTE: PGPainless is in an early state of development. There may be dragons! +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](tests.sequoia-pgp.org). + +## 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](https://pgpainless.org/releases/latest/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. + +```java + // RSA key without additional subkeys + PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() + .simpleRsaKeyRing("Juliet ", RsaLength._4096); + + // EdDSA primary key with EdDSA signing- and XDH encryption subkeys + PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() + .modernKeyRing("Romeo ", "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 ") + .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. + +```java + 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. + +```java + 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 @@ -29,111 +137,10 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:0.1.0' + implementation 'org.pgpainless:pgpainless-core:0.2.0-alpha12' } ``` -## How to use PGPainless - -The entry point to the API is the `PGPainless` class. Here you can find methods for a quick start :) - -### Generate Keys - -The first thing you probably want to do is generate you some nice tasty Key Pairs. The most straight forward way to do so is by calling - -```java - PGPKeyRing keyRing = PGPainless.generateKeyRing() - .simpleRsaKeyRing("Juliet ", RsaLength._4096); -``` - -but feel free to explore the API further. PGPainless allows you to create Key Pairs consisting of a master key plus several sub keys, even with different algorithms at the same time! -Take for example a look at this delicious key: - -```java - 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 ") - .withPassphrase("romeo_oh_Romeo<3") - .build(); -``` - -### Encrypt / Sign Data - -Encrypting and signingOptions data is pretty straight forward as well. -```java - EncryptionStream encryptor = PGPainless.encryptAndOrSign() - .onOutputStream(targetOuputStream) - .toRecipients(publicKeyRings) - .usingSecureAlgorithms() - .signWith(secretKeyDecryptor, signingKeyRing) - .noArmor(); -``` - -Note: Despite the name, the `EncryptionStream` can be used to sign only as well. Simply replace the `.toRecipients()` option with `doNotEncrypt()`. - -The resulting `EncryptionStream` can then be used to encrypt data like follows: - -```java - Streams.pipeAll(sourceInputStream, encryptor); - sourceInputStream.close(); - encryptor.close(); -``` - -The encrypted data will be written to the provided `targetOutputStream`. - -Additionally you can get information about the encrypted data by calling - -```java - OpenPgpMetadata result = encryptor.getResult(); -``` - -This object will contain information like to which keys the message is encrypted, which keys were used for signingOptions and so on. - -### Decrypt / Verify Encrypted Data - -To process incoming encrypted / signed data, just do the following: - -```java - DecryptionStream decryptor = PGPainless.decryptAndOrVerify() - .onInputStream(sourceInputStream) // insert encrypted data here - .decryptWith(secretKeyDecryptor, secretKey) - .verifyWith(trustedKeyIds, senderKeys) - .ignoreMissingPublicKeys() - .build(); -``` - -Again, the resulting `DecryptionStream` can be used like a normal stream. - -```java - Streams.pipeAll(decryptor, targetOutputStream); - decryptor.close(); -``` - -*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. - -```java - OpenPgpMetadata result = decryptor.getResult(); -``` - -For further details you should check out the [javadoc](https://pgpainless.org/releases/latest/javadoc/)! - ## About PGPainless is a by-product of my [Summer of Code 2018 project](https://blog.jabberhead.tk/summer-of-code-2018/). For that project I was in need of a simple to use OpenPGP library.