{"id":37028525,"url":"https://github.com/neuhalje/bouncy-gpg","last_synced_at":"2026-01-14T03:24:34.866Z","repository":{"id":17278417,"uuid":"79064782","full_name":"neuhalje/bouncy-gpg","owner":"neuhalje","description":"Make using Bouncy Castle with OpenPGP fun again!","archived":false,"fork":false,"pushed_at":"2024-03-11T07:19:22.000Z","size":6000,"stargazers_count":218,"open_issues_count":32,"forks_count":53,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-10-10T18:07:57.500Z","etag":null,"topics":["batch-job","bouncy-castle","bouncycastle","encryption","gnupg","gpg","java","jvm","key-derivative-function","key-derivator","openpgp","osgi","pgp","rfc4880","security","sign"],"latest_commit_sha":null,"homepage":"https://neuhalje.github.io/bouncy-gpg/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neuhalje.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null}},"created_at":"2017-01-15T22:50:07.000Z","updated_at":"2025-08-27T14:39:50.000Z","dependencies_parsed_at":"2024-03-03T09:32:19.349Z","dependency_job_id":"5fd1bf0d-723d-4a80-abb6-c430acf49bff","html_url":"https://github.com/neuhalje/bouncy-gpg","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/neuhalje/bouncy-gpg","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuhalje%2Fbouncy-gpg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuhalje%2Fbouncy-gpg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuhalje%2Fbouncy-gpg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuhalje%2Fbouncy-gpg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neuhalje","download_url":"https://codeload.github.com/neuhalje/bouncy-gpg/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neuhalje%2Fbouncy-gpg/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28408834,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T01:52:23.358Z","status":"online","status_checked_at":"2026-01-14T02:00:06.678Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["batch-job","bouncy-castle","bouncycastle","encryption","gnupg","gpg","java","jvm","key-derivative-function","key-derivator","openpgp","osgi","pgp","rfc4880","security","sign"],"created_at":"2026-01-14T03:24:34.235Z","updated_at":"2026-01-14T03:24:34.858Z","avatar_url":"https://github.com/neuhalje.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"**Looking for contributors**: *_It's boring to work alone_ - If you are interested in contributing to an open source project please open an issue to discuss your ideas or create a PR*\n\n[![Build Status](https://github.com/neuhalje/bouncy-gpg/actions/workflows/ci.yaml/badge.svg)](https://github.com/neuhalje/bouncy-gpg/actions/workflows/ci.yaml)\n[![codecov](https://codecov.io/gh/neuhalje/bouncy-gpg/branch/master/graph/badge.svg)](https://codecov.io/gh/neuhalje/bouncy-gpg)\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/86c099743f8b484c8da833495d7dc209)](https://www.codacy.com/app/neuhalje/bouncy-gpg?utm_source=github.com\u0026amp;utm_medium=referral\u0026amp;utm_content=neuhalje/bouncy-gpg\u0026amp;utm_campaign=Badge_Grade)\n[![license](https://img.shields.io/badge/license-APACHE%202.0-brightgreen.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)\n[![Download](https://api.bintray.com/packages/neuhalje/maven/bouncy-gpg/images/download.svg)](https://bintray.com/neuhalje/maven/bouncy-gpg/_latestVersion)\n[![Known Vulnerabilities](https://snyk.io/test/github/neuhalje/bouncy-gpg/badge.svg?targetFile=build.gradle)](https://snyk.io/test/github/neuhalje/bouncy-gpg?targetFile=build.gradle)\n\n[![Say Thanks!](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/neuhalje)\n\n\nMission Statement\n=======================\n\n  **Make using [Bouncy Castle](http://bouncycastle.org/) with [OpenPGP](https://tools.ietf.org/html/rfc4880) ~~great~~ fun again!**\n\nThis project gives you the following super-powers\n\n- encrypt, decrypt, sign and verify GPG/PGP files with just a few lines of code\n- protect all the data at rest by reading encrypted files with [transparent GPG decryption](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/decrypting/DecryptionStreamFactory.java)\n- you can even [decrypt a gpg encrypted ZIP and re-encrypt each file in it again](examples/reencrypt/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/example/MainExplodedSinglethreaded.java) -- never again let plaintext hit your servers disk!\n\nExamples\n==========\n\n_Bouncy GPG_ comes with several [examples](examples) build in.\n\nKey management\n-----------------\n\n_Bouncy GPG_ supports [reading `gpg` keyrings](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/FileBasedKeyringConfig.java) and [parsing keys exported](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/InMemoryKeyring.java) via `gpg --export` and  `gpg --export-secret-key`.\n\nThe unit tests have some [examples creating/reading keyrings](src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/testtooling/Configs.java).\n\nThe easiest way to manage keyrings is to use the pre-defined [KeyringConfigs](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/KeyringConfigs.java).\n\nEncrypt \u0026 sign a file and then decrypt it \u0026 validate the signature\n-------------------\n\nThe following snippet encrypts a secret message to `recipient@example.com` (and also self-encrypts it to `sender@example.com`), and signs with `sender@example.com`.\n\nThe encrypted message is then decrypted and the signature is verified. (This is from a [documentation test](https://github.com/neuhalje/bouncy-gpg/blob/master/src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/roundtrip/EncryptionDecryptionRoundtripIntegrationTest.java#L496-L556)).\n\n```java\n\n    final String original_message = \"I love deadlines. I like the whooshing sound they make as they fly by. Douglas Adams\";\n\n    // Most likely you will use  one of the KeyringConfigs.... methods.\n    // These are wrappers for the test.\n    KeyringConfig keyringConfigOfSender = Configs\n        .keyringConfigFromResourceForSender();\n\n    ByteArrayOutputStream result = new ByteArrayOutputStream();\n\n    try (\n        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(result);\n\n        final OutputStream outputStream = BouncyGPG\n            .encryptToStream()\n            .withConfig(keyringConfigOfSender)\n            .withStrongAlgorithms()\n            .toRecipients(\"recipient@example.com\", \"sender@example.com\")\n            .andSignWith(\"sender@example.com\")\n            .binaryOutput()\n            .andWriteTo(bufferedOutputStream);\n        // Maybe read a file or a webservice?\n        final ByteArrayInputStream is = new ByteArrayInputStream(original_message.getBytes())\n    ) {\n      Streams.pipeAll(is, outputStream);\n    // It is very important that outputStream is closed before the result stream is read.\n    // The reason is that GPG writes the signature at the end of the stream.\n    // This is triggered by closing the stream.\n    // In this example outputStream is closed via the try-with-resources mechanism of Java\n    }\n\n    result.close();\n    byte[] chipertext = result.toByteArray();\n\n    //////// Now decrypt the stream and check the signature\n\n    // Most likely you will use  one of the KeyringConfigs.... methods.\n    // These are wrappers for the test.\n    KeyringConfig keyringConfigOfRecipient = Configs\n        .keyringConfigFromResourceForRecipient();\n\n    final OutputStream output = new ByteArrayOutputStream();\n    try (\n        final InputStream cipherTextStream = new ByteArrayInputStream(chipertext);\n\n        final BufferedOutputStream bufferedOut = new BufferedOutputStream(output);\n\n        final InputStream plaintextStream = BouncyGPG\n            .decryptAndVerifyStream()\n            .withConfig(keyringConfigOfRecipient)\n            .andRequireSignatureFromAllKeys(\"sender@example.com\")\n            .fromEncryptedInputStream(cipherTextStream)\n\n    ) {\n      Streams.pipeAll(plaintextStream, bufferedOut);\n    }\n\n    output.close();\n    final String decrypted_message = new String(((ByteArrayOutputStream) output).toByteArray());\n\n    assertEquals(original_message, decrypted_message);\n```\n\n\nPerformance\n--------------\n\nBouncy castle is often fast enough to _not be the bottleneck_. That said, here are some metrics to give you an indication of the performance:\n\n| Use Case                                        | MBP 2,9 GHz Intel Core i5, Java 1.8.0_111  |  (please add more via PR) |\n|:------------------------------------------------|:-------------------------------------------|:--------------------------|\n| [Encrypt \u0026 sign 1GB random](examples/encrypt)   | ~64s (16 MB/s)                             |                           |\n| [Decrypt 1GB random](examples/encrypt)          | ~32s (32 MB/s)                             |                           |\n\nDemos\n=========\n\nThe directory [examples](examples) contains several examples that show how easy some common use cases are implemented.\n\n[demo_decrypt.sh](examples/decrypt)\n-----------------------------------------\n\nDecrypt a file and verify the signature.\n\n* `decrypt.sh  SOURCEFILE DESTFILE`\n\nUses the testing keys to decrypt a file. Useful for performance measurements and `gpg` interoperability.\n\n[demo_encrypt.sh](examples/encrypt)\n-----------------------------------------\n\nEncrypt and sign a file.\n\n* `encrypt.sh  SOURCEFILE DESTFILE`\n\nUses the testing keys to encrypt a file. Useful for performance measurements and `gpg` interoperability.\n\n\n[demo_reencrypt.sh](examples/reencrypt)\n-----------------------------------------\n\nA GPG encrypted ZIP file is decrypted on the fly. The structure of the ZIP is then written to disk. All files are re-encrypted before saving them.\n\n* `demo_reencrypt.sh TARGET` -- decrypts an encrypted ZIP file containing  three files (total size: 1.2 GB) AND\n   re-encrypts each of the files in the ZIP to the `TARGET` dir.\n\n[The sample](examples/reencrypt/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/example/MainExplodedSinglethreaded.java)\nshows how e.g. batch jobs can work with large files without leaving plaintext on disk (together with\n[Transparent GPG decryption](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/decrypting/SignatureValidatingInputStream.java)).\n\nThis scheme has some very appealing benefits:\n* Data in transit is _always_ encrypted with public key cryptography. Indispensable when you have to use `ftp`,\n  comforting when you use `https` and the next Heartbleed pops up.\n* Data at rest is _always_ encrypted with public key cryptography. When (not if) you get hacked, this can make all the\n  difference between _\"Move along folks, nothing to see here!\"_ and _\"I lost confidential customer data to the competition\"_.\n* You still need to protect the private keys, but this is considerable easier than the alternatives.\n\nConsider the following batch job:\n\n1. The customer sends a large (several GB) GPG encrypted ZIP archive containing a directory structure with several\n   data files\n2. Your `pre-processing` needs to split up the data for further processing\n3. `pre-processing` stream-processes the GPG/ZIP archive\n    1. The GPG stream is decrypted using the [BouncyGPG.decryptAndVerifyStream()](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/BouncyGPG.java) `InputStream`\n    2. The ZIP file is processed with [ExplodeAndReencrypt](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/reencryption/ExplodeAndReencrypt.java)\n        1. Each file from the archive is [processed](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/reencryption/ZipEntityStrategy.java)\n        2. And transparently  encrypted with GPG and stored for further processing\n4. 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.\n\n\nHOWTO\n===========\n\nHave a look at the example classes to see how easy it is to use Bouncy Castle PGP.\n\n#1 Register Bouncy Castle Provider\n-------------------------------\n\nAdd bouncy castle as a dependency and then install the provider before in your application.\n\n### Add Build Dependency\n\n#### Gradle\n\n```groovy\n// build.gradle\n// in build.gradle add a dependency to bouncy castle and bouncy-gpg\n\n//...\n\nrepositories {\n    mavenCentral()\n    // jcenter() - optional.\n}\n\n//...\n\n//  ...\ndependencies {\n    compile 'org.bouncycastle:bcprov-jdk15on:1.67'\n    compile 'org.bouncycastle:bcpg-jdk15on:1.67'\n    //  ...\n    compile 'name.neuhalfen.projects.crypto.bouncycastle.openpgp:bouncy-gpg:2.+'\n   // ...\n  }\n```\n#### Maven\n\n```xml\n    \u003cdependency\u003e\n        \u003cgroupId\u003ename.neuhalfen.projects.crypto.bouncycastle.openpgp\u003c/groupId\u003e\n        \u003cartifactId\u003ebouncy-gpg\u003c/artifactId\u003e\n        \u003cversion\u003e2.3.0\u003c/version\u003e\n    \u003c/dependency\u003e\n```\n \n### Install Provider\n\n```java\n    // in one of you classed install the BC provider\n    BouncyGPG.registerProvider();\n```\n\n#2 Important Classes\n-------------------\n\n\n| Class                         | Use when you want to                                                                |\n|:------------------------------|:------------------------------------------------------------------------------------|\n| [`BouncyGPG`](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/BouncyGPG.java) | Starting point for the convenient fluent en- and decryption API. |\n| [`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). |\n| [`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.  |\n| [`DefaultPGPAlgorithmSuites`](src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/algorithms/DefaultPGPAlgorithmSuites.java) |  Select from predefined algorithms suites or create your won with `PGPAlgorithmSuite`. |\n| [`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) |\n\nFAQ\n=====\n\n\u003cdl\u003e\n  \u003cdt\u003eWhy should I use this?\u003c/dt\u003e\n  \u003cdd\u003eFor common use cases this project is easier than vanilla Bouncy Castle. It also has a pretty decent unit test\n  coverage. It is free (speech \u0026 beer).\u003c/dd\u003e\n\n  \u003cdt\u003eCan I just grab a class or two for my project?\u003c/dt\u003e\n  \u003cdd\u003eSure! Just grab it and hack away! The code is placed under the \u003ca href=\"LICENSE\"\u003eApache License 2.0\u003c/a\u003e, you can't get much\n   more permissive than this.\u003c/dd\u003e\n\n   \u003cdt\u003eWhy is the test coverage so low?\u003c/dt\u003e\n   \u003cdd\u003eTest coverage for 'non-example' code is \u0026gt;85%. Most of the not tested cases are either trivial OR lines that\n   throw exceptions when the input format is broken/handled by bouncycastle directly. \u003c/dd\u003e\n\n   \u003cdt\u003eHow can I contribute?\u003c/dt\u003e\n   \u003cdd\u003ePullrequests are welcome! Please state in your PR that you put your code under the LICENSE.\u003c/dd\u003e\n\n   \u003cdt\u003eI am getting 'org.bouncycastle.openpgp.PGPException: checksum mismatch ..' exceptions\u003c/dt\u003e\n   \u003cdd\u003eThe passphrase to your private key is very likely wrong (or you did not pass a passphrase).\u003c/dd\u003e\n\n   \u003cdt\u003eI am getting 'java.security.InvalidKeyException: Illegal key size' / 'java.lang.SecurityException: Unsupported keysize or algorithm parameters'\u003c/dt\u003e\n   \u003cdd\u003eThe unrestricted policy files for the JVM are \u003ca href=\"http://www.bouncycastle.org/wiki/display/JA1/Frequently+Asked+Questions\"\u003eprobably not installed\u003c/a\u003e.\u003c/dd\u003e\n\n   \u003cdt\u003eI am getting 'java.io.EOFException: premature end of stream in PartialInputStream' while decrypting / Sender can't validate signature\u003c/dt\u003e\n   \u003cdd\u003eThis often happens when encrypting to a 'ByteArrayOutputStream' and the \u003ca href=\"https://stackoverflow.com/questions/48870074/bouncy-castle-pgp-premature-end-of-stream-in-partialinputstream/49544870#49544870\"\u003eencryption stream is not propely closed\u003c/a\u003e. The reason is that GPG writes the signature at the end of the stream. This is triggered by closing the stream.\u003c/dd\u003e\n\n   \u003cdt\u003eWhere is 'secring.pgp'?\u003c/dt\u003e\n   \u003cdd\u003e'secring.gpg' has been \u003ca href=\"https://gnupg.org/faq/whats-new-in-2.1.html#nosecring\"\u003eremoved in gpg 2.1\u003c/a\u003e. Use the other methods to read private keys.\u003c/dd\u003e\n\n   \u003cdt\u003eShould I \u003ci\u003euse\u003c/i\u003e secring.pgp?\u003c/dt\u003e\n   \u003cdd\u003eNo, you should implement your own key handling strategy. See \u003ca href=\"#using_sec_pubring\"\u003eOn using (sec|pub)ring.gpg\u003c/a\u003e below.\n\n   \u003cdt\u003eCan I generate keys?\u003c/dt\u003e\n   \u003cdd\u003eYes, RSA key generation is supported since 2.2.0. Generating ECC keys is NOT supported yet, although the code is there (\u003ca href=\"https://github.com/neuhalje/bouncy-gpg/blob/master/src/integration-test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/integration/KeyRingGenerators.java\"\u003egpg integration tests\u003c/a\u003e fail)\u003c/dd\u003e\n\n   \u003cdt\u003eIs compatibility with GnuPG tested?\u003c/dt\u003e\n   \u003cdd\u003eYes, since 2.2.0 the gradle task integrationTest  \u003ca href=\"https://github.com/neuhalje/bouncy-gpg/blob/master/src/integration-test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/integration/\"\u003etests the interoperability with gpg\u003c/a\u003e.\u003c/dd\u003e\n\u003c/dl\u003e\n\n\n## \u003ca name=\"using_sec_pubring\"\u003e\u003c/a\u003eOn using (sec|pub)ring.gpg\n\n*I strongly advise against using `secring.gpg` or `pubring.gpg` for production systems*. These files are an undocumented API of gnupg: usable, but can change or show unexpected results. E.g. with GPG 2.1 the `secring.gpg` file gets no longer updated [and will provide you with stale data](https://gnupg.org/faq/whats-new-in-2.1.html#nosecring) (emphasis by me):\n\n\u003e To ease the migration to the no-secring method, gpg detects the presence of a secring.gpg and converts the keys on-the-fly to the the key store of gpg-agent (this is the private-keys-v1.d directory below the GnuPG home directory (~/.gnupg)). **This is done only once and an existing secring.gpg is then not anymore touched by gpg.** This allows co-existence of older GnuPG versions with GnuPG 2.1. However, any change to the private keys using the new gpg will not show up when using pre-2.1 versions of GnuPG and vice versa.\n\n## Recommendation: InMemoryKeyring\n\nMost applications should manage their keys in an application specific database. Though this might seem more complex than just using the existing keyring files it has a some nice advantages:\n\n* No dependency on the `gpg` executable\n* Keys can be managed remotely (e.g. via the applications database)\n* Key management is enforced to happen via the application\n* Key management for distributed (_scale out_ / _cloud_) systems is much easier when keys are not managed by the operating system\n\n### HOWTO use InMemoryKeyring\n\nTo use the  [InMemoryKeyring](https://github.com/neuhalje/bouncy-gpg/blob/master/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/KeyringConfigs.java) you first need to export the keys. Then you put them in your  application data(base).\n\n#### Exporting the keys from gpg\n\nExport the keys  with `gpg` (`gpg --export-secret-key -a user@example.com` and `gpg --export -a user@example.com`):\n\n```text\ngpg --export -a user@example.com \u003e user@example.com.pub.gpg\ncat user@example.com.pub.gpg\n\n-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----\n\n# You need to input keys passphrase here\ngpg --export-secret-key -a user@example.com \u003e user@example.com.secret.gpg\ncat user@example.com.secret.gpg\n\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n...\n-----END PGP PRIVATE KEY BLOCK-----\n```\n\n#### Importing the keys\n\nA few examples for using the [InMemoryKeyring](https://github.com/neuhalje/bouncy-gpg/blob/master/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/keys/keyrings/KeyringConfigs.java)  can be found in the [Test code](https://github.com/neuhalje/bouncy-gpg/blob/master/src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/testtooling/Configs.java).\n\nHere is the short version:\n\n```java\n  public static KeyringConfig keyringConfigInMemoryForKeys(final String exportedPubKey, final String exportedPrivateKey, final String passphrase) throws IOException, PGPException {\n\n    final InMemoryKeyring keyring = KeyringConfigs.forGpgExportedKeys(KeyringConfigCallbacks.withPassword(passphrase);\n\n    keyring.addPublicKey(exportedPubKey.getBytes(\"US-ASCII\"));\n   // you can add many more public keys\n\n    keyring.addSecretKey(exportedPrivateKey.getBytes(\"US-ASCII\"));\n   // you can add many more privvate keys\n\n    return keyring;\n  }\n```\n\n#### Generating Keys\n\nThe most straight forward way is to call  `BouncyGPG::createSimpleKeyring()`:\n\n```java\n    final KeyringConfig rsaKeyRing = BouncyGPG.createSimpleKeyring()\n        .simpleRsaKeyRing(UID_JULIET, RsaLength.RSA_3072_BIT);\n\n```\nHere is a more complex case with dedicated subkeys for signing, encryption, and authentication:\n```java\n        final KeySpec signingSubey = KeySpecBuilder\n                .newSpec(RSAForSigningKeyType.withLength(RsaLength.RSA_2048_BIT))\n                .allowKeyToBeUsedTo(KeyFlag.SIGN_DATA)\n                .withDefaultAlgorithms();\n\n        final KeySpec authenticationSubey = KeySpecBuilder\n                .newSpec(RSAForEncryptionKeyType.withLength(RsaLength.RSA_2048_BIT))\n                .allowKeyToBeUsedTo(KeyFlag.AUTHENTICATION)\n                .withDefaultAlgorithms();\n\n        final KeySpec encryptionSubey = KeySpecBuilder\n                .newSpec(RSAForEncryptionKeyType.withLength(RsaLength.RSA_2048_BIT))\n                .allowKeyToBeUsedTo(KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)\n                .withDefaultAlgorithms();\n\n        final KeySpec masterKey = KeySpecBuilder.newSpec(\n                RSAForSigningKeyType.withLength(RsaLength.RSA_3072_BIT)\n        )\n                .allowKeyToBeUsedTo(KeyFlag.CERTIFY_OTHER)\n                .withDetailedConfiguration()\n                .withPreferredSymmetricAlgorithms(\n                        PGPSymmetricEncryptionAlgorithms.recommendedAlgorithms()\n                )\n                .withPreferredHashAlgorithms(\n                        PGPHashAlgorithms.recommendedAlgorithms()\n                )\n                .withPreferredCompressionAlgorithms(\n                        PGPCompressionAlgorithms.recommendedAlgorithms()\n                )\n                .withFeature(Feature.MODIFICATION_DETECTION)\n                .done();\n\n        final KeyringConfig complexKeyRing = BouncyGPG\n                .createKeyring()\n                .withSubKey(signingSubey)\n                .withSubKey(authenticationSubey)\n                .withSubKey(encryptionSubey)\n                .withMasterKey(masterKey)\n                .withPrimaryUserId(uid)\n                .withPassphrase(Passphrase.fromString(passphrase))\n                .build();\n\n        return complexKeyRing;\n```\n\n##### Persisting generated keys\n\nThe bouncy castle functions can be used to persist keys. [ExportGeneratedKeysTest.java](src/test/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/examples/howto/ExportGeneratedKeysTest.java) shows how to do that.\n\n#### Using the config\n\n```java\nfinal InMemoryKeyring keyring = keyringConfigInMemoryForKeys(...);\n\nfinal InputStream decryptedPlaintextStream = BouncyGPG\n        .decryptAndVerifyStream()\n        .withConfig(keyring)\n        ....\n```\n\nBuilding\n=======\n\nThe project is a basic gradle build. All the scripts use `./gradlew  installDist`\n\nThe coverage report (incl. running tests) is generated with `./gradlew check`.\n\nPublish to jcenter\n--------------------\n\n`./gradlew bintrayUpload`\n\nCAVE\n=====\n\n* Only one keyring per userid (\"sender@example.com\") supported.\n* Only one signing key per userid supported.\n* [TODOs](TODO.md)\n\n## LICENSE\n\nThis code is placed under the Apache License 2.0. Don't forget to adhere to the BouncyCastle License (http://bouncycastle.org/license.html).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuhalje%2Fbouncy-gpg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneuhalje%2Fbouncy-gpg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneuhalje%2Fbouncy-gpg/lists"}