Skip to content

Commit

Permalink
Polishing
Browse files Browse the repository at this point in the history
  • Loading branch information
neuhalje committed Feb 10, 2017
1 parent b0a599f commit 1ab3a7d
Show file tree
Hide file tree
Showing 14 changed files with 214 additions and 87 deletions.
124 changes: 63 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
[![codecov](https://codecov.io/gh/neuhalje/bouncy-gpg/branch/master/graph/badge.svg)](https://codecov.io/gh/neuhalje/bouncy-gpg)
[![license](http://www.wtfpl.net/wp-content/uploads/2012/12/wtfpl-badge-4.png)](http://www.wtfpl.net/)


Mission Statement
=======================

Expand All @@ -17,38 +16,38 @@ This project gives you the following super-powers
Examples
==========

_Bouncy GPG_ comes with several [examples](examples) build in.

Encrypting a file
-------------------

The following snippet encrypts `/tmp/plaintext.txt` to `recipient@exmaple.com` and signs with `sender@example.com`.
The following snippet encrypts `/tmp/plaintext.txt` to `recipient@example.com` and signs with `sender@example.com`.
The encrypted file is written to `/tmp/encrypted.gpg`.

```java
final KeyringConfig keyringConfig = KeyringConfigs
.withKeyRingsFromFiles(
"pubring.gpg",
"secring.gpg",
KeyringConfigCallbacks.withPassword("s3cr3t"));


try (
final FileOutputStream fileOutput = new FileOutputStream("/tmp/encrypted.gpg");
final BufferedOutputStream bufferedOut = new BufferedOutputStream(fileOutput);

final OutputStream outputStream = BouncyGPG
.encryptToStream()
.withConfig(keyringConfig)
.withStrongAlgorithms()
.toRecipient("recipient@example.com")
.andSignWith("sender@example.com")
.binaryOutput()
.andWriteTo(bufferedOut);

final FileInputStream is = new FileInputStream("/tmp/plaintext.txt")
) {
Streams.pipeAll(is, outputStream);
}

final KeyringConfig keyringConfig = KeyringConfigs
.withKeyRingsFromFiles(
"pubring.gpg",
"secring.gpg",
KeyringConfigCallbacks.withPassword("s3cr3t"));

try (
final FileOutputStream fileOutput = new FileOutputStream("/tmp/encrypted.gpg");
final BufferedOutputStream bufferedOut = new BufferedOutputStream(fileOutput);

final OutputStream outputStream = BouncyGPG
.encryptToStream()
.withConfig(keyringConfig)
.withStrongAlgorithms()
.toRecipient("recipient@example.com")
.andSignWith("sender@example.com")
.binaryOutput()
.andWriteTo(bufferedOut);

final FileInputStream is = new FileInputStream("/tmp/plaintext.txt")
) {
Streams.pipeAll(is, outputStream);
}
```

Decrypting a file and validating the signature
Expand All @@ -58,45 +57,53 @@ The following snippet decrypts the file created in the snippet above.


```java
final KeyringConfig keyringConfig = KeyringConfigs
.withKeyRingsFromFiles(
"pubring.gpg",
"secring.gpg",
KeyringConfigCallbacks.withPassword("s3cr3t"));

try (
final FileInputStream cipherTextStream = new FileInputStream("/tmp/encrypted.gpg");

final FileOutputStream fileOutput = new FileOutputStream(destFile);
final BufferedOutputStream bufferedOut = new BufferedOutputStream("/tmp/plaintext.txt");

final InputStream plaintextStream = BouncyGPG
.decryptAndVerifyStream()
.withConfig(keyringConfig)
.andIgnoreSignatures()
.fromEncryptedInputStream(cipherTextStream)

) {
Streams.pipeAll(plaintextStream, bufferedOut);
}

final KeyringConfig keyringConfig = KeyringConfigs
.withKeyRingsFromFiles(
"pubring.gpg",
"secring.gpg",
KeyringConfigCallbacks.withPassword("s3cr3t"));

try (
final FileInputStream cipherTextStream = new FileInputStream("/tmp/encrypted.gpg");

final FileOutputStream fileOutput = new FileOutputStream(destFile);
final BufferedOutputStream bufferedOut = new BufferedOutputStream("/tmp/plaintext.txt");

final InputStream plaintextStream = BouncyGPG
.decryptAndVerifyStream()
.withConfig(keyringConfig)
.andIgnoreSignatures()
.fromEncryptedInputStream(cipherTextStream)

) {
Streams.pipeAll(plaintextStream, bufferedOut);
}
```

Demos
=========

The directory [examples](examples) contains several examples that show how easy some common usecases are implemented.
The directory [examples](examples) contains several examples that show how easy some common use cases are implemented.

[demo_dencrypt.sh](examples/decrypt)
[demo_decrypt.sh](examples/decrypt)
-----------------------------------------

Decrypt a file and verify the signature.

* `decrypt.sh SOURCEFILE DESTFILE`

Uses the testing keys to decrypt a file. Useful for performance measurements and `gpg` interoperability.

[demo_encrypt.sh](examples/encrypt)
-----------------------------------------

Encrypt and sign a file.

* `encrypt.sh SOURCEFILE DESTFILE`

Uses the testing keys to encrypt a file. Useful for performance measurements and `gpg` interoperability.


[demo_reencrypt.sh](examples/reencrypt)
-----------------------------------------

Expand All @@ -105,9 +112,9 @@ A GPG encrypted ZIP file is decrypted on the fly. The structure of the ZIP is th
* `demo_reencrypt.sh TARGET` -- decrypts an encrypted ZIP file containing three files (total size: 1.2 GB) AND
re-encrypts each of the files in the ZIP to the `TARGET` dir.

[The sample](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/example/MainExplodedSinglethreaded.java)
[The sample](examples/reencrypt/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/example/MainExplodedSinglethreaded.java)
shows how e.g. batch jobs can work with large files without leaving plaintext on disk (together with
[Transparent GPG decryption](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/decrypting/DecryptWithOpenPGPInputStreamFactory.java)).
[Transparent GPG decryption](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/decrypting/SignatureValidatingInputStream.java)).

This scheme has some very appealing benefits:
* Data in transit is _always_ encrypted with public key cryptography. Indispensable when you have to use `ftp`,
Expand All @@ -128,10 +135,6 @@ Consider the following batch job:
2. And transparently encrypted with GPG and stored for further processing
4. The `processing` job [transparently reads](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/decrypting/SignatureValidatingInputStream.java) the files without writing plaintext to the disk.

encrypt.sh
-----------

* `encrypt.sh SOURCEFILE DESTFILE` -- uses the testing keys to encrypt a file. Useful for performance measurements.

HOWTO
===========
Expand All @@ -154,6 +157,8 @@ dependencies {
compile 'org.bouncycastle:bcpg-jdk15on:1.56'
// ...
compile 'name.neuhalfen.projects.crypto.bouncycastle.openpgp:bouncy-gpg:2.+'
// ...
}
```

### Install Provider
Expand All @@ -175,8 +180,7 @@ dependencies {
| [`KeyringConfigs`](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/KeyringConfigs.java) | Create default implementations for GPG keyring access. You can also create your own implementations by implementing [`KeyringConfig`](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/KeyringConfig.java). |
| [`KeyringConfigCallbacks`](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/callbacks/KeyringConfigCallbacks.java) | Used by [`KeyringConfigs`](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/KeyringConfigs.java). Create default implementations to provide secret-key passwords. |
| [`DefaultPGPAlgorithmSuites`](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/algorithms/DefaultPGPAlgorithmSuites.java) | Select from predefined algorithms suites or create your won with `PGPAlgorithmSuite`. |


| ['ReencryptExplodedZipSinglethread'](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/reencryption/ReencryptExplodedZipSinglethread.java) | [Work with encrypted ZIPs](examples/reencrypt/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/example/MainExplodedSinglethreaded.java) |

FAQ
=====
Expand Down Expand Up @@ -207,7 +211,6 @@ FAQ
<dd>'secring.gpg' has been <a href="https://gnupg.org/faq/whats-new-in-2.1.html#nosecring">removed in gpg 2.1</a>. Use the other methods to read private keys.</dd>
</dl>


Building
=======

Expand All @@ -222,7 +225,6 @@ CAVE
* Only one signing key per userid supported.
* [TODOs](TODO.md)


## LICENSE

This code is placed under the WTFPL. Don't forget to adhere to the BouncyCastle License (http://bouncycastle.org/license.html).
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

public final class BouncyGPG {

private BouncyGPG() {
}

/**
* Entry point for stream based decryption.
* .
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@

public final class DefaultPGPAlgorithmSuites {

// no construction
private DefaultPGPAlgorithmSuites() {
}

/**
* GPG default algorithms
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,7 @@ public int read() throws IOException {

@Override
public int read(@Nonnull byte[] b) throws IOException {
int read = super.read(b);
if (read != -1) {
state.updateOnePassSignatures(b, 0, read);
} else {
validateSignature();
}
return read;
return read(b, 0, b.length);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,10 @@ public static OutputStream create(final KeyringConfig config,
* @param signingUid Sign with this uid. null: do not sign
* @param pubEncKey the pub enc key
* @param armor if OutputStream should be "armored", that means base64 encoded
* @throws IOException Signals that an I/O exception has occurred.
* @throws NoSuchAlgorithmException the no such algorithm exception
* @throws NoSuchProviderException the no such provider exception
* @throws PGPException the pGP exception
* @throws SignatureException the signature exception
* {@link org.bouncycastle.bcpg.HashAlgorithmTags}
* {@link org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags}
* @throws IOException Signals that an I/O exception has occurred.
* @throws PGPException the pGP exception
* {@link org.bouncycastle.bcpg.HashAlgorithmTags}
* {@link org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags}
*/
private void setup(final OutputStream cipherTextSink,
@Nullable final String signingUid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,18 @@
public final class PGPUtilities {
private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory.getLogger(PGPUtilities.class);

// No instances
private PGPUtilities() {
}

/**
* Find secret key.
*
* @param pgpSec the pgp sec
* @param keyID the key id
* @param pass the pass
* @return the decrypted secret key
* @throws PGPException the pGP exception
* @throws PGPException the pGP exception
*/
public static PGPPrivateKey findSecretKey(final PGPSecretKeyRingCollection pgpSec, final long keyID, final char[] pass)
throws PGPException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
* {@link KeyringConfigCallback}
*/
public final class KeyringConfigCallbacks {
// no construction
private KeyringConfigCallbacks() {
}

public static KeyringConfigCallback withPassword(char[] passphrase) {
return new StaticPasswordKeyringConfigCallback(passphrase);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.FileNotFoundException;
import java.io.IOException;
Expand All @@ -17,12 +18,16 @@

abstract class DefaultKeyringConfig implements KeyringConfig {

@Nonnull
private final KeyringConfigCallback callback;
private PGPPublicKeyRingCollection publicKeyRings;
private PGPSecretKeyRingCollection secretKeyRings;
private final KeyFingerPrintCalculator keyFingerPrintCalculator = new BcKeyFingerprintCalculator();

DefaultKeyringConfig(KeyringConfigCallback callback) {
if (callback == null) {
throw new NullPointerException("callback mus not be null");
}
this.callback = callback;
}

Expand All @@ -38,6 +43,7 @@ public String toString() {
* @return Stream that connects to secring.gpg
* @throws FileNotFoundException File not found
*/

protected abstract InputStream getSecretKeyRingStream() throws IOException;

/**
Expand Down Expand Up @@ -71,11 +77,7 @@ public PGPSecretKeyRingCollection getSecretKeyRings() throws IOException, PGPExc
public
@Nullable
char[] decryptionSecretKeyPassphraseForSecretKeyId(long keyID) {
if (callback != null) {
return callback.decryptionSecretKeyPassphraseForSecretKeyId(keyID);
} else {
return null;
}
return callback.decryptionSecretKeyPassphraseForSecretKeyId(keyID);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,32 @@

import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks.KeyringConfigCallback;

import javax.annotation.Nonnull;
import java.io.*;

/**
* Load keyrings from files. These files are created and managed via gpg.
*/
final class FileBasedKeyringConfig extends DefaultKeyringConfig {

@Nonnull
private final File publicKeyring;
@Nonnull
private final File secretKeyring;

public FileBasedKeyringConfig(KeyringConfigCallback callback, File publicKeyring, File secretKeyring) {
public FileBasedKeyringConfig(@Nonnull KeyringConfigCallback callback, @Nonnull File publicKeyring, @Nonnull File secretKeyring) {
super(callback);
this.publicKeyring = publicKeyring;
this.secretKeyring = secretKeyring;
}

@Nonnull
@Override
protected InputStream getPublicKeyRingStream() throws IOException {
return new FileInputStream(publicKeyring);
}

@Nonnull
@Override
protected InputStream getSecretKeyRingStream() throws FileNotFoundException {
return new FileInputStream(secretKeyring);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@
*/
public final class KeyringConfigs {

// no instances
private KeyringConfigs() {
}

/**
* Create a decryption config by reading keyrings from files.
*
Expand Down
Loading

0 comments on commit 1ab3a7d

Please sign in to comment.