From 8bd760aee5ac1187d7284bc5cd2975888e03283d Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Mon, 13 Aug 2018 23:46:07 +0200 Subject: [PATCH] Customize sidebar + delete code --- CODE_OF_CONDUCT.md | 40 -- LICENSE | 201 ---------- README.md | 149 -------- _config.yml | 4 +- _layouts/default.html | 78 ++++ assets/logo.png | Bin 0 -> 14740 bytes build.gradle | 254 ------------- config/checkstyle.xml | 233 ------------ config/checkstyleLicenseHeader.txt | 15 - config/suppressions.xml | 13 - docs/CNAME | 1 - docs/_config.yml | 1 - gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 0 bytes gradle/wrapper/gradle-wrapper.properties | 6 - gradlew | 172 --------- gradlew.bat | 84 ----- docs/index.md => index.md | 0 pgpainless-core/build.gradle | 13 - .../main/java/org/pgpainless/PGPainless.java | 95 ----- .../pgpainless/algorithm/AlgorithmSuite.java | 105 ------ .../algorithm/CompressionAlgorithm.java | 52 --- .../org/pgpainless/algorithm/Feature.java | 55 --- .../pgpainless/algorithm/HashAlgorithm.java | 59 --- .../org/pgpainless/algorithm/KeyFlag.java | 53 --- .../algorithm/PublicKeyAlgorithm.java | 62 ---- .../algorithm/SymmetricKeyAlgorithm.java | 66 ---- .../pgpainless/algorithm/package-info.java | 19 - .../DecryptionBuilder.java | 124 ------- .../DecryptionBuilderInterface.java | 67 ---- .../DecryptionStream.java | 50 --- .../DecryptionStreamFactory.java | 245 ------------ .../MissingPublicKeyCallback.java | 36 -- .../OpenPgpMetadata.java | 163 -------- .../SignatureVerifyingInputStream.java | 175 --------- .../decryption_verification/package-info.java | 19 - .../encryption_signing/EncryptionBuilder.java | 348 ------------------ .../EncryptionBuilderInterface.java | 99 ----- .../encryption_signing/EncryptionStream.java | 235 ------------ .../encryption_signing/package-info.java | 19 - .../exception/SecretKeyNotFoundException.java | 32 -- .../pgpainless/exception/package-info.java | 19 - .../pgpainless/key/OpenPgpV4Fingerprint.java | 147 -------- .../key/collection/KeyRingCollection.java | 105 ------ .../pgpainless/key/collection/PGPKeyRing.java | 76 ---- .../key/collection/package-info.java | 19 - .../key/generation/KeyRingBuilder.java | 241 ------------ .../generation/KeyRingBuilderInterface.java | 54 --- .../pgpainless/key/generation/KeySpec.java | 56 --- .../key/generation/KeySpecBuilder.java | 174 --------- .../generation/KeySpecBuilderInterface.java | 74 ---- .../key/generation/package-info.java | 19 - .../pgpainless/key/generation/type/ECDH.java | 51 --- .../pgpainless/key/generation/type/ECDSA.java | 43 --- .../key/generation/type/ElGamal_ENCRYPT.java | 33 -- .../key/generation/type/ElGamal_GENERAL.java | 51 --- .../key/generation/type/KeyType.java | 29 -- .../key/generation/type/RSA_ENCRYPT.java | 33 -- .../key/generation/type/RSA_GENERAL.java | 51 --- .../key/generation/type/RSA_SIGN.java | 33 -- .../generation/type/curve/EllipticCurve.java | 33 -- .../generation/type/curve/package-info.java | 19 - .../type/length/DiffieHellmanLength.java | 36 -- .../generation/type/length/ElGamalLength.java | 87 ----- .../key/generation/type/length/KeyLength.java | 21 -- .../key/generation/type/length/RsaLength.java | 38 -- .../generation/type/length/package-info.java | 19 - .../key/generation/type/package-info.java | 19 - .../java/org/pgpainless/key/package-info.java | 19 - .../pgpainless/key/parsing/KeyRingReader.java | 161 -------- .../pgpainless/key/parsing/package-info.java | 19 - .../protection/KeyRingProtectionSettings.java | 49 --- .../PassphraseMapKeyRingProtector.java | 93 ----- .../PasswordBasedSecretKeyRingProtector.java | 72 ---- .../SecretKeyPassphraseProvider.java | 36 -- .../protection/SecretKeyRingProtector.java | 45 --- .../protection/UnprotectedKeysProtector.java | 39 -- .../key/protection/package-info.java | 19 - .../selection/key/KeySelectionStrategy.java | 38 -- .../key/PublicKeySelectionStrategy.java | 55 --- .../key/SecretKeySelectionStrategy.java | 55 --- .../key/selection/key/impl/And.java | 61 --- .../impl/EncryptionKeySelectionStrategy.java | 34 -- .../key/selection/key/impl/NoRevocation.java | 55 --- .../pgpainless/key/selection/key/impl/Or.java | 61 --- .../impl/SignatureKeySelectionStrategy.java | 35 -- .../selection/key/impl/SignedByMasterKey.java | 61 --- .../key/selection/key/impl/package-info.java | 19 - .../key/selection/key/package-info.java | 19 - .../keyring/KeyRingSelectionStrategy.java | 29 -- .../PublicKeyRingSelectionStrategy.java | 49 --- .../SecretKeyRingSelectionStrategy.java | 48 --- .../key/selection/keyring/impl/Email.java | 48 --- .../selection/keyring/impl/ExactUserId.java | 50 --- .../selection/keyring/impl/PartialUserId.java | 55 --- .../key/selection/keyring/impl/Whitelist.java | 77 ---- .../key/selection/keyring/impl/Wildcard.java | 40 -- .../key/selection/keyring/impl/XMPP.java | 38 -- .../selection/keyring/impl/package-info.java | 19 - .../key/selection/keyring/package-info.java | 19 - .../java/org/pgpainless/package-info.java | 21 -- .../SymmetricEncryptorDecryptor.java | 183 --------- .../symmetric_encryption/package-info.java | 19 - .../main/java/org/pgpainless/util/BCUtil.java | 282 -------------- .../org/pgpainless/util/KeyRingSubKeyFix.java | 111 ------ .../java/org/pgpainless/util/MultiMap.java | 136 ------- .../java/org/pgpainless/util/Passphrase.java | 103 ------ .../org/pgpainless/util/package-info.java | 19 - .../pgpainless/AbstractPGPainlessTest.java | 29 -- .../test/java/org/pgpainless/BCUtilTest.java | 149 -------- .../pgpainless/BouncycastleExportSubkeys.java | 128 ------- .../org/pgpainless/EncryptDecryptTest.java | 190 ---------- .../org/pgpainless/ImportExportKeyTest.java | 63 ---- .../org/pgpainless/KeyRingSubKeyFixTest.java | 52 --- .../test/java/org/pgpainless/LengthTest.java | 128 ------- .../pgpainless/OpenPgpV4FingerprintTest.java | 78 ---- .../java/org/pgpainless/SymmetricTest.java | 63 ---- .../test/java/org/pgpainless/TestKeys.java | 267 -------------- .../java/org/pgpainless/TestKeysTest.java | 74 ---- settings.gradle | 4 - version.gradle | 9 - 120 files changed, 81 insertions(+), 8566 deletions(-) delete mode 100644 CODE_OF_CONDUCT.md delete mode 100644 LICENSE delete mode 100644 README.md create mode 100644 _layouts/default.html create mode 100644 assets/logo.png delete mode 100644 build.gradle delete mode 100644 config/checkstyle.xml delete mode 100644 config/checkstyleLicenseHeader.txt delete mode 100644 config/suppressions.xml delete mode 100644 docs/CNAME delete mode 100644 docs/_config.yml delete mode 100644 gradle/wrapper/gradle-wrapper.jar delete mode 100644 gradle/wrapper/gradle-wrapper.properties delete mode 100755 gradlew delete mode 100644 gradlew.bat rename docs/index.md => index.md (100%) delete mode 100644 pgpainless-core/build.gradle delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/PGPainless.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/AlgorithmSuite.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilder.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilderInterface.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStream.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MissingPublicKeyCallback.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/SignatureVerifyingInputStream.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/decryption_verification/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/encryption_signing/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/exception/SecretKeyNotFoundException.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/exception/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV4Fingerprint.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/collection/KeyRingCollection.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRing.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/collection/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilderInterface.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDH.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDSA.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_ENCRYPT.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_GENERAL.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_ENCRYPT.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_GENERAL.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_SIGN.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/EllipticCurve.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/DiffieHellmanLength.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/ElGamalLength.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/KeyLength.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/RsaLength.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/generation/type/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/parsing/KeyRingReader.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/parsing/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/protection/KeyRingProtectionSettings.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/protection/PassphraseMapKeyRingProtector.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyPassphraseProvider.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyRingProtector.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/protection/UnprotectedKeysProtector.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/protection/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/KeySelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/PublicKeySelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/SecretKeySelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/And.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/NoRevocation.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/Or.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignatureKeySelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignedByMasterKey.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/key/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/KeyRingSelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/PublicKeyRingSelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/SecretKeyRingSelectionStrategy.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Email.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/ExactUserId.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/PartialUserId.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Whitelist.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Wildcard.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/XMPP.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/SymmetricEncryptorDecryptor.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/package-info.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/util/BCUtil.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/util/KeyRingSubKeyFix.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/util/MultiMap.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/util/Passphrase.java delete mode 100644 pgpainless-core/src/main/java/org/pgpainless/util/package-info.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/AbstractPGPainlessTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/BCUtilTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/BouncycastleExportSubkeys.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/EncryptDecryptTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/ImportExportKeyTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/KeyRingSubKeyFixTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/LengthTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/OpenPgpV4FingerprintTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/SymmetricTest.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/TestKeys.java delete mode 100644 pgpainless-core/src/test/java/org/pgpainless/TestKeysTest.java delete mode 100644 settings.gradle delete mode 100644 version.gradle diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index f809c8b0..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,40 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/README.md b/README.md deleted file mode 100644 index 2cebcb50..00000000 --- a/README.md +++ /dev/null @@ -1,149 +0,0 @@ -PGPainless - Use OpenPGP Painlessly! -==================================== - -[![Travis (.org)](https://travis-ci.org/pgpainless/pgpainless.svg)](https://travis-ci.org/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) - -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 encryption / decrytion 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 9. - -### NOTE: PGPainless is in a *very* early state of development and should under no circumstances be used for serious production usage yet. - -## 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. - -```gradle -repositories { - mavenCentral() -} - -dependencies { - compile 'org.pgpainless:pgpainless-core:0.0.1-alpha1' -} -``` - -## 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 - PGPSecretKeyRing 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_GENERAL.withLength(RsaLength._8192)) - .withKeyFlags(KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER) - .withDefaultAlgorithms()) - .withPrimaryUserId("Juliet ") - .withPassphrase("romeo_oh_Romeo<3") - .build(); -``` - -### Encrypt / Sign Data - -Encrypting and signing data is pretty straight forward as well. -```java - EncryptionStream encryptor = PGPainless.createEncryptor() - .onOutputStream(targetOuputStream) - .toRecipients(publicKeyRings) - .usingSecureAlgorithms() - .signWith(secretKeyDecryptor, signingKeyRing) - .noArmor(); -``` - -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 - PainlessResult result = encryptor.getResult(); -``` - -That object will contain information like to which keys the message is encrypted, which keys were used for signing and so on. - -### Decrypt / Verify Encrypted Data - -To process incoming encrypted / signed data, just do the following: - -```java - DecryptionStream decryptor = PGPainless.createDecryptor() - .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 `PainlessResult`. -Again, this object will contain information about how the message was encrypted, who signed it and so on. - -```java - PainlessResult result = decryptor.getResult(); -``` - -## About -PGPainless is a by-product of my [Summer of Code 2018 project](https://vanitasvitae.github.io/GSOC2018/). -For that project I was in need of a simple to use OpenPGP library. - -Originally I was going to use [Bouncy-GPG](https://github.com/neuhalje/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 and I would definitely recommend you to -use it instead of PGPainless if you want a more mature, better tested code base. - -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: - -* [Github](https://github.com/pgpainless/pgpainless) -* [Teahub](https://teahub.io/PGPainless/pgpainless) - -Please follow the [code of conduct](CODE_OF_CONDUCT.md) if you want to be part of the project. diff --git a/_config.yml b/_config.yml index 2f7efbea..78b36e82 100644 --- a/_config.yml +++ b/_config.yml @@ -1 +1,3 @@ -theme: jekyll-theme-minimal \ No newline at end of file +logo: /assets/logo.png +show_downloads: true +theme: jekyll-theme-minimal diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 00000000..b0471b4d --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,78 @@ + + + + + + {{ site.title | default: site.github.repository_name }} by {{ +site.github.owner_name }} + + + + + + +
+
+

{{ site.title | default: site.github.repository_name }}

+ {% if site.logo %} + Logo + {% endif %} +

{{ site.description | default: site.github.project_tagline +}}

+ + Home +
+ Releases +
+ Javadoc +
+ Jacoco +
+ + + {% if site.github.is_project_page %} +

View the Project on GitHub {{ github_name }}

+ {% endif %} + + {% if site.github.is_user_page %} +

View My +GitHub Profile

+ {% endif %} + + {% if site.show_downloads %} + + {% endif %} +
+
+ + {{ content }} + +
+ +
+ + + diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6cfae8208b74a71af609b752921d128d4b60f6d4 GIT binary patch literal 14740 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 signing.signPom(deployment) } - } - repository(url: project.sonatypeStagingUrl) { - if (sonatypeCredentialsAvailable) { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - } - snapshotRepository(url: project.sonatypeSnapshotUrl) { - if (sonatypeCredentialsAvailable) { - authentication(userName: sonatypeUsername, password: sonatypePassword) - } - } - - pom.project { - name 'PGPainless' - description 'Simple to use OpenPGP API for Java based on Bouncycastle' - url 'https://github.com/pgpainless/pgpainless' - inceptionYear '2018' - - scm { - url 'https://github.com/pgpainless/pgpainless' - connection 'scm:https://github.com/pgpainless/pgpainless' - developerConnection 'scm:git://github.com/pgpainless/pgpainless.git' - } - - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'http://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' - } - } - - developers { - developer { - id 'vanitasvitae' - name 'Paul Schaub' - email 'vanitasvitae@fsfe.org' - } - } - } - } - } - } - - signing { - required { signingRequired } - sign configurations.archives - } -} - -def getAndroidRuntimeJar(androidSdkApiLevel) { - def androidHome = getAndroidHome() - def androidJar = new File("$androidHome/platforms/android-$androidSdkApiLevel/android.jar") - if (androidJar.isFile()) { - return androidJar - } else { - throw new Exception("Can't find android.jar for API level $androidSdkApiLevel at $androidHome/platforms/android-$androidSdkApiLevel/android.jar. Please install corresponding SDK platform package") - } -} - -def getAndroidHome() { - def androidHomeEnv = System.getenv("ANDROID_HOME") - if (androidHomeEnv == null) { - throw new Exception("ANDROID_HOME environment variable is not set") - } - def androidHome = new File(androidHomeEnv) - if (!androidHome.isDirectory()) throw new Exception("Environment variable ANDROID_HOME is not pointing to a directory") - return androidHome -} - -def getGitCommit() { - def dotGit = new File("$projectDir/.git") - if (!dotGit.isDirectory()) return 'non-git build' - - def cmd = 'git describe --always --tags --dirty=+' - def proc = cmd.execute() - def gitCommit = proc.text.trim() - assert !gitCommit.isEmpty() - - def srCmd = 'git symbolic-ref --short HEAD' - def srProc = srCmd.execute() - srProc.waitForOrKill(10 * 1000) - if (srProc.exitValue() == 0) { - // Only add the information if the git command was - // successful. There may be no symbolic reference for HEAD if - // e.g. in detached mode. - def symbolicReference = srProc.text.trim() - assert !symbolicReference.isEmpty() - gitCommit += "-$symbolicReference" - } - - gitCommit -} - -apply plugin: "com.github.kt3k.coveralls" -coveralls { - sourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs).files.absolutePath -} - - -task jacocoRootReport(type: JacocoReport) { - dependsOn = subprojects.jacocoTestReport - sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs) - classDirectories = files(subprojects.sourceSets.main.output) - executionData = files(subprojects.jacocoTestReport.executionData) - reports { - xml.enabled true - xml.destination file("${buildDir}/reports/jacoco/test/jacocoTestReport.xml") - } - // We could remove the following setOnlyIf line, but then - // jacocoRootReport would silently be SKIPPED if something with - // the projectsWithUnitTests is wrong (e.g. a project is missing - // in there). - setOnlyIf { true } -} - - -task javadocAll(type: Javadoc) { - source subprojects.collect {project -> - project.sourceSets.main.allJava } - destinationDir = new File(buildDir, 'javadoc') - // Might need a classpath - classpath = files(subprojects.collect {project -> - project.sourceSets.main.compileClasspath}) - options.linkSource = true - options.use = true - options.links = [ - "https://docs.oracle.com/javase/${sourceCompatibility.getMajorVersion()}/docs/api/", - ] as String[] -} diff --git a/config/checkstyle.xml b/config/checkstyle.xml deleted file mode 100644 index 14e2cbc6..00000000 --- a/config/checkstyle.xml +++ /dev/null @@ -1,233 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/checkstyleLicenseHeader.txt b/config/checkstyleLicenseHeader.txt deleted file mode 100644 index fb341cd2..00000000 --- a/config/checkstyleLicenseHeader.txt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2018 Author Authorsson. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ \ No newline at end of file diff --git a/config/suppressions.xml b/config/suppressions.xml deleted file mode 100644 index f2aba18d..00000000 --- a/config/suppressions.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - diff --git a/docs/CNAME b/docs/CNAME deleted file mode 100644 index b985fe9f..00000000 --- a/docs/CNAME +++ /dev/null @@ -1 +0,0 @@ -www.pgpainless.org \ No newline at end of file diff --git a/docs/_config.yml b/docs/_config.yml deleted file mode 100644 index c7418817..00000000 --- a/docs/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 01b8bf6b1f99cad9213fc495b33ad5bbab8efd20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 54329 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

<5G2M1WZP5 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi -done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null - -APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" - -warn () { - echo "$*" -} - -die () { - echo - echo "$*" - echo - exit 1 -} - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD="java" - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." -fi - -# Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi -fi - -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi - -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi - # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" - fi - i=$((i+1)) - done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac -fi - -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - -exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat deleted file mode 100644 index e95643d6..00000000 --- a/gradlew.bat +++ /dev/null @@ -1,84 +0,0 @@ -@if "%DEBUG%" == "" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto init - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% - -:end -@rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/docs/index.md b/index.md similarity index 100% rename from docs/index.md rename to index.md diff --git a/pgpainless-core/build.gradle b/pgpainless-core/build.gradle deleted file mode 100644 index f343d4c4..00000000 --- a/pgpainless-core/build.gradle +++ /dev/null @@ -1,13 +0,0 @@ - -dependencies { - testCompile group: 'junit', name: 'junit', version: '4.12' - /* - compile 'org.bouncycastle:bcprov-debug-jdk15on:1.60' - /*/ - compile 'org.bouncycastle:bcprov-jdk15on:1.60' - //*/ - compile 'org.bouncycastle:bcpg-jdk15on:1.60' - - // https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305 - compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2' -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/PGPainless.java b/pgpainless-core/src/main/java/org/pgpainless/PGPainless.java deleted file mode 100644 index a3c4d24c..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/PGPainless.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import javax.annotation.Nonnull; -import java.io.IOException; - -import org.bouncycastle.openpgp.PGPException; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.decryption_verification.DecryptionBuilder; -import org.pgpainless.decryption_verification.DecryptionStream; -import org.pgpainless.encryption_signing.EncryptionBuilder; -import org.pgpainless.encryption_signing.EncryptionStream; -import org.pgpainless.key.generation.KeyRingBuilder; -import org.pgpainless.key.parsing.KeyRingReader; -import org.pgpainless.symmetric_encryption.SymmetricEncryptorDecryptor; -import org.pgpainless.util.Passphrase; - -public class PGPainless { - - /** - * Generate a new OpenPGP key ring. - * @return builder - */ - public static KeyRingBuilder generateKeyRing() { - return new KeyRingBuilder(); - } - - /** - * Read an existing OpenPGP key ring. - * @return builder - */ - public static KeyRingReader readKeyRing() { - return new KeyRingReader(); - } - - /** - * Create an {@link EncryptionStream}, which can be used to encrypt and/or sign data using OpenPGP. - * @return builder - */ - public static EncryptionBuilder createEncryptor() { - return new EncryptionBuilder(); - } - - /** - * Create a {@link DecryptionStream}, which can be used to decrypt and/or verify data using OpenPGP. - * @return builder - */ - public static DecryptionBuilder createDecryptor() { - return new DecryptionBuilder(); - } - - /** - * Encrypt some data symmetrically using OpenPGP and a password. - * The resulting data will be uncompressed and integrity protected. - * - * @param data input data. - * @param password password. - * @return symmetrically OpenPGP encrypted data. - * @throws IOException IO is dangerous. - * @throws PGPException PGP is brittle. - */ - public static byte[] encryptWithPassword(@Nonnull byte[] data, @Nonnull Passphrase password, @Nonnull SymmetricKeyAlgorithm algorithm) throws IOException, PGPException { - return SymmetricEncryptorDecryptor.symmetricallyEncrypt(data, password, - algorithm, CompressionAlgorithm.UNCOMPRESSED); - } - - /** - * Decrypt some symmetrically encrypted data using a password. - * The data is suspected to be integrity protected. - * - * @param data symmetrically OpenPGP encrypted data. - * @param password password. - * @return decrypted data. - * @throws IOException IO is dangerous. - * @throws PGPException PGP is brittle. - */ - public static byte[] decryptWithPassword(@Nonnull byte[] data, @Nonnull Passphrase password) throws IOException, PGPException { - return SymmetricEncryptorDecryptor.symmetricallyDecrypt(data, password); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/AlgorithmSuite.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/AlgorithmSuite.java deleted file mode 100644 index 3cce51f3..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/AlgorithmSuite.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.algorithm; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public class AlgorithmSuite { - - private static AlgorithmSuite defaultAlgorithmSuite = new AlgorithmSuite( - Arrays.asList( - SymmetricKeyAlgorithm.AES_256, - SymmetricKeyAlgorithm.AES_192, - SymmetricKeyAlgorithm.AES_128), - Arrays.asList( - HashAlgorithm.SHA512, - HashAlgorithm.SHA384, - HashAlgorithm.SHA256, - HashAlgorithm.SHA224), - Arrays.asList( - CompressionAlgorithm.ZLIB, - CompressionAlgorithm.BZIP2, - CompressionAlgorithm.ZIP, - CompressionAlgorithm.UNCOMPRESSED) - ); - - private List symmetricKeyAlgorithms; - private List hashAlgorithms; - private List compressionAlgorithms; - - public AlgorithmSuite(List symmetricKeyAlgorithms, - List hashAlgorithms, - List compressionAlgorithms) { - this.symmetricKeyAlgorithms = Collections.unmodifiableList(symmetricKeyAlgorithms); - this.hashAlgorithms = Collections.unmodifiableList(hashAlgorithms); - this.compressionAlgorithms = Collections.unmodifiableList(compressionAlgorithms); - } - - public void setSymmetricKeyAlgorithms(List symmetricKeyAlgorithms) { - this.symmetricKeyAlgorithms = symmetricKeyAlgorithms; - } - - public List getSymmetricKeyAlgorithms() { - return new ArrayList<>(symmetricKeyAlgorithms); - } - - public int[] getSymmetricKeyAlgorithmIds() { - int[] array = new int[symmetricKeyAlgorithms.size()]; - for (int i = 0; i < array.length; i++) { - array[i] = symmetricKeyAlgorithms.get(i).getAlgorithmId(); - } - return array; - } - - public void setHashAlgorithms(List hashAlgorithms) { - this.hashAlgorithms = hashAlgorithms; - } - - public List getHashAlgorithms() { - return hashAlgorithms; - } - - public int[] getHashAlgorithmIds() { - int[] array = new int[hashAlgorithms.size()]; - for (int i = 0; i < array.length; i++) { - array[i] = hashAlgorithms.get(i).getAlgorithmId(); - } - return array; - } - - public void setCompressionAlgorithms(List compressionAlgorithms) { - this.compressionAlgorithms = compressionAlgorithms; - } - - public List getCompressionAlgorithms() { - return compressionAlgorithms; - } - - public int[] getCompressionAlgorithmIds() { - int[] array = new int[compressionAlgorithms.size()]; - for (int i = 0; i < array.length; i++) { - array[i] = compressionAlgorithms.get(i).getAlgorithmId(); - } - return array; - } - - public static AlgorithmSuite getDefaultAlgorithmSuite() { - return defaultAlgorithmSuite; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java deleted file mode 100644 index 5c2be73f..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/CompressionAlgorithm.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.algorithm; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.bcpg.CompressionAlgorithmTags; - -public enum CompressionAlgorithm { - - UNCOMPRESSED (CompressionAlgorithmTags.UNCOMPRESSED), - ZIP (CompressionAlgorithmTags.ZIP), - ZLIB (CompressionAlgorithmTags.ZLIB), - BZIP2 (CompressionAlgorithmTags.BZIP2), - ; - - private static final Map MAP = new HashMap<>(); - - static { - for (CompressionAlgorithm c : CompressionAlgorithm.values()) { - MAP.put(c.algorithmId, c); - } - } - - public static CompressionAlgorithm fromId(int id) { - return MAP.get(id); - } - - private final int algorithmId; - - CompressionAlgorithm(int id) { - this.algorithmId = id; - } - - public int getAlgorithmId() { - return algorithmId; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java deleted file mode 100644 index d3fa5293..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/Feature.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.algorithm; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.bcpg.sig.Features; - -public enum Feature { - - /** - * Add modification detection package. - * - * @see - * RFC-4880 §5.14: Modification Detection Code Packet - */ - MODIFICATION_DETECTION(Features.FEATURE_MODIFICATION_DETECTION), - ; - - private static final Map MAP = new HashMap<>(); - - static { - for (Feature f : Feature.values()) { - MAP.put(f.featureId, f); - } - } - - public static Feature fromId(byte id) { - return MAP.get(id); - } - - private final byte featureId; - - Feature(byte featureId) { - this.featureId = featureId; - } - - public byte getFeatureId() { - return featureId; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java deleted file mode 100644 index 896acdde..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/HashAlgorithm.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.algorithm; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.bcpg.HashAlgorithmTags; - -public enum HashAlgorithm { - - MD5 (HashAlgorithmTags.MD5), - SHA1 (HashAlgorithmTags.SHA1), - RIPEMD160 (HashAlgorithmTags.RIPEMD160), - DOUBLE_SHA (HashAlgorithmTags.DOUBLE_SHA), - MD2 (HashAlgorithmTags.MD2), - TIGER_192 (HashAlgorithmTags.TIGER_192), - HAVAL_5_160(HashAlgorithmTags.HAVAL_5_160), - SHA256 (HashAlgorithmTags.SHA256), - SHA384 (HashAlgorithmTags.SHA384), - SHA512 (HashAlgorithmTags.SHA512), - SHA224 (HashAlgorithmTags.SHA224), - ; - // Coincidence? I don't this so... - private static final Map MAP = new HashMap<>(); - - static { - for (HashAlgorithm h : HashAlgorithm.values()) { - MAP.put(h.algorithmId, h); - } - } - - public static HashAlgorithm fromId(int id) { - return MAP.get(id); - } - - private final int algorithmId; - - HashAlgorithm(int id) { - this.algorithmId = id; - } - - public int getAlgorithmId() { - return algorithmId; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java deleted file mode 100644 index 82e7fe5c..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/KeyFlag.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.algorithm; - -import java.util.ArrayList; -import java.util.List; - -import org.bouncycastle.bcpg.sig.KeyFlags; - -public enum KeyFlag { - - CERTIFY_OTHER (KeyFlags.CERTIFY_OTHER), - SIGN_DATA (KeyFlags.SIGN_DATA), - ENCRYPT_COMMS (KeyFlags.ENCRYPT_COMMS), - ENCRYPT_STORAGE(KeyFlags.ENCRYPT_STORAGE), - SPLIT (KeyFlags.SPLIT), - AUTHENTICATION (KeyFlags.AUTHENTICATION), - SHARED (KeyFlags.SHARED), - ; - - private final int flag; - - KeyFlag(int flag) { - this.flag = flag; - } - - public int getFlag() { - return flag; - } - - public static List fromInteger(int bitmask) { - List flags = new ArrayList<>(); - for (KeyFlag f : KeyFlag.values()) { - if ((bitmask & f.flag) != 0) { - flags.add(f); - } - } - return flags; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java deleted file mode 100644 index b598b125..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/PublicKeyAlgorithm.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.algorithm; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; - -public enum PublicKeyAlgorithm { - - RSA_GENERAL (PublicKeyAlgorithmTags.RSA_GENERAL), - RSA_ENCRYPT (PublicKeyAlgorithmTags.RSA_ENCRYPT), - RSA_SIGN (PublicKeyAlgorithmTags.RSA_SIGN), - ELGAMAL_ENCRYPT (PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT), - DSA (PublicKeyAlgorithmTags.DSA), - /** - * EC is deprecated. - * @deprecated use {@link #ECDH} instead. - */ - EC (PublicKeyAlgorithmTags.EC), - ECDH (PublicKeyAlgorithmTags.ECDH), - ECDSA (PublicKeyAlgorithmTags.ECDSA), - ELGAMAL_GENERAL (PublicKeyAlgorithmTags.ELGAMAL_GENERAL), - DIFFIE_HELLMAN (PublicKeyAlgorithmTags.DIFFIE_HELLMAN), - ; - - private static final Map MAP = new HashMap<>(); - - static { - for (PublicKeyAlgorithm p : PublicKeyAlgorithm.values()) { - MAP.put(p.algorithmId, p); - } - } - - public static PublicKeyAlgorithm fromId(int id) { - return MAP.get(id); - } - - private final int algorithmId; - - PublicKeyAlgorithm(int algorithmId) { - this.algorithmId = algorithmId; - } - - public int getAlgorithmId() { - return algorithmId; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java deleted file mode 100644 index 36a28651..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/SymmetricKeyAlgorithm.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.algorithm; - -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; - -public enum SymmetricKeyAlgorithm { - - NULL (SymmetricKeyAlgorithmTags.NULL), - /** - * IDEA is deprecated. - * @deprecated use a different algorithm. - */ - IDEA (SymmetricKeyAlgorithmTags.IDEA), - TRIPLE_DES (SymmetricKeyAlgorithmTags.TRIPLE_DES), - CAST5 (SymmetricKeyAlgorithmTags.CAST5), - BLOWFISH (SymmetricKeyAlgorithmTags.BLOWFISH), - SAFER (SymmetricKeyAlgorithmTags.SAFER), - DES (SymmetricKeyAlgorithmTags.DES), - AES_128 (SymmetricKeyAlgorithmTags.AES_128), - AES_192 (SymmetricKeyAlgorithmTags.AES_192), - AES_256 (SymmetricKeyAlgorithmTags.AES_256), - TWOFISH (SymmetricKeyAlgorithmTags.TWOFISH), - CAMELLIA_128 (SymmetricKeyAlgorithmTags.CAMELLIA_128), - CAMELLIA_192 (SymmetricKeyAlgorithmTags.CAMELLIA_192), - CAMELLIA_256 (SymmetricKeyAlgorithmTags.CAMELLIA_256), - ; - - private static final Map MAP = new HashMap<>(); - - static { - for (SymmetricKeyAlgorithm s : SymmetricKeyAlgorithm.values()) { - MAP.put(s.algorithmId, s); - } - } - - public static SymmetricKeyAlgorithm fromId(int id) { - return MAP.get(id); - } - - private final int algorithmId; - - SymmetricKeyAlgorithm(int algorithmId) { - this.algorithmId = algorithmId; - } - - public int getAlgorithmId() { - return algorithmId; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java deleted file mode 100644 index 5a1d3643..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/algorithm/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Enums which map to OpenPGP's algorithm IDs. - */ -package org.pgpainless.algorithm; diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilder.java deleted file mode 100644 index 5e9cf9ea..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilder.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.decryption_verification; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.pgpainless.key.OpenPgpV4Fingerprint; -import org.pgpainless.key.protection.SecretKeyRingProtector; - -public class DecryptionBuilder implements DecryptionBuilderInterface { - - private InputStream inputStream; - private PGPSecretKeyRingCollection decryptionKeys; - private SecretKeyRingProtector decryptionKeyDecryptor; - private Set verificationKeys = new HashSet<>(); - private MissingPublicKeyCallback missingPublicKeyCallback = null; - - @Override - public DecryptWith onInputStream(InputStream inputStream) { - this.inputStream = inputStream; - return new DecryptWithImpl(); - } - - class DecryptWithImpl implements DecryptWith { - - @Override - public VerifyWith decryptWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRingCollection secretKeyRings) { - DecryptionBuilder.this.decryptionKeys = secretKeyRings; - DecryptionBuilder.this.decryptionKeyDecryptor = decryptor; - return new VerifyWithImpl(); - } - - @Override - public VerifyWith doNotDecrypt() { - DecryptionBuilder.this.decryptionKeys = null; - DecryptionBuilder.this.decryptionKeyDecryptor = null; - return new VerifyWithImpl(); - } - } - - class VerifyWithImpl implements VerifyWith { - - @Override - public HandleMissingPublicKeys verifyWith(@Nonnull PGPPublicKeyRingCollection publicKeyRingCollection) { - Set publicKeyRings = new HashSet<>(); - for (Iterator i = publicKeyRingCollection.getKeyRings(); i.hasNext(); ) { - publicKeyRings.add(i.next()); - } - return verifyWith(publicKeyRings); - } - - @Override - public HandleMissingPublicKeys verifyWith(@Nonnull Set trustedKeyIds, - @Nonnull PGPPublicKeyRingCollection publicKeyRingCollection) { - Set publicKeyRings = new HashSet<>(); - for (Iterator i = publicKeyRingCollection.getKeyRings(); i.hasNext(); ) { - PGPPublicKeyRing p = i.next(); - OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(p); - if (trustedKeyIds.contains(fingerprint)) { - publicKeyRings.add(p); - } - } - return verifyWith(publicKeyRings); - } - - @Override - public HandleMissingPublicKeys verifyWith(@Nonnull Set publicKeyRings) { - DecryptionBuilder.this.verificationKeys = publicKeyRings; - return new HandleMissingPublicKeysImpl(); - } - - @Override - public Build doNotVerify() { - DecryptionBuilder.this.verificationKeys = null; - return new BuildImpl(); - } - } - - class HandleMissingPublicKeysImpl implements HandleMissingPublicKeys { - - @Override - public Build handleMissingPublicKeysWith(@Nonnull MissingPublicKeyCallback callback) { - DecryptionBuilder.this.missingPublicKeyCallback = callback; - return new BuildImpl(); - } - - @Override - public Build ignoreMissingPublicKeys() { - DecryptionBuilder.this.missingPublicKeyCallback = null; - return new BuildImpl(); - } - } - - class BuildImpl implements Build { - - @Override - public DecryptionStream build() throws IOException, PGPException { - return DecryptionStreamFactory.create(inputStream, - decryptionKeys, decryptionKeyDecryptor, verificationKeys, missingPublicKeyCallback); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilderInterface.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilderInterface.java deleted file mode 100644 index 0cd096be..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionBuilderInterface.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.decryption_verification; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.io.InputStream; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.pgpainless.key.OpenPgpV4Fingerprint; -import org.pgpainless.key.protection.SecretKeyRingProtector; - -public interface DecryptionBuilderInterface { - - DecryptWith onInputStream(InputStream inputStream); - - interface DecryptWith { - - VerifyWith decryptWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRingCollection secretKeyRings); - - VerifyWith doNotDecrypt(); - - } - - interface VerifyWith { - - HandleMissingPublicKeys verifyWith(@Nonnull PGPPublicKeyRingCollection publicKeyRings); - - HandleMissingPublicKeys verifyWith(@Nonnull Set trustedFingerprints, @Nonnull PGPPublicKeyRingCollection publicKeyRings); - - HandleMissingPublicKeys verifyWith(@Nonnull Set publicKeyRings); - - Build doNotVerify(); - - } - - interface HandleMissingPublicKeys { - - Build handleMissingPublicKeysWith(@Nonnull MissingPublicKeyCallback callback); - - Build ignoreMissingPublicKeys(); - } - - interface Build { - - DecryptionStream build() throws IOException, PGPException; - - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStream.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStream.java deleted file mode 100644 index 2bad3724..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStream.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.decryption_verification; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.io.InputStream; - -public class DecryptionStream extends InputStream { - - private final InputStream inputStream; - private final OpenPgpMetadata.Builder resultBuilder; - private boolean isClosed = false; - - DecryptionStream(@Nonnull InputStream wrapped, @Nonnull OpenPgpMetadata.Builder resultBuilder) { - this.inputStream = wrapped; - this.resultBuilder = resultBuilder; - } - - @Override - public int read() throws IOException { - return inputStream.read(); - } - - @Override - public void close() throws IOException { - inputStream.close(); - this.isClosed = true; - } - - public OpenPgpMetadata getResult() { - if (!isClosed) { - throw new IllegalStateException("DecryptionStream MUST be closed before the result can be accessed."); - } - return resultBuilder.build(); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java deleted file mode 100644 index 3c439a43..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/DecryptionStreamFactory.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.decryption_verification; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPCompressedData; -import org.bouncycastle.openpgp.PGPEncryptedDataList; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPLiteralData; -import org.bouncycastle.openpgp.PGPObjectFactory; -import org.bouncycastle.openpgp.PGPOnePassSignature; -import org.bouncycastle.openpgp.PGPOnePassSignatureList; -import org.bouncycastle.openpgp.PGPPrivateKey; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; -import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider; -import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; -import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; -import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.key.OpenPgpV4Fingerprint; -import org.pgpainless.key.protection.SecretKeyRingProtector; - -public final class DecryptionStreamFactory { - - private static final Logger LOGGER = Logger.getLogger(DecryptionStreamFactory.class.getName()); - private static final Level LEVEL = Level.FINE; - - private final PGPSecretKeyRingCollection decryptionKeys; - private final SecretKeyRingProtector decryptionKeyDecryptor; - private final Set verificationKeys = new HashSet<>(); - private final MissingPublicKeyCallback missingPublicKeyCallback; - - private final OpenPgpMetadata.Builder resultBuilder = OpenPgpMetadata.getBuilder(); - private final PGPContentVerifierBuilderProvider verifierBuilderProvider = new BcPGPContentVerifierBuilderProvider(); - private final KeyFingerPrintCalculator fingerCalc = new BcKeyFingerprintCalculator(); - private final Map verifiableOnePassSignatures = new HashMap<>(); - - private DecryptionStreamFactory(@Nullable PGPSecretKeyRingCollection decryptionKeys, - @Nullable SecretKeyRingProtector decryptor, - @Nullable Set verificationKeys, - @Nullable MissingPublicKeyCallback missingPublicKeyCallback) { - this.decryptionKeys = decryptionKeys; - this.decryptionKeyDecryptor = decryptor; - this.verificationKeys.addAll(verificationKeys != null ? verificationKeys : Collections.emptyList()); - this.missingPublicKeyCallback = missingPublicKeyCallback; - } - - public static DecryptionStream create(@Nonnull InputStream inputStream, - @Nullable PGPSecretKeyRingCollection decryptionKeys, - @Nullable SecretKeyRingProtector decryptor, - @Nullable Set verificationKeys, - @Nullable MissingPublicKeyCallback missingPublicKeyCallback) - throws IOException, PGPException { - - DecryptionStreamFactory factory = new DecryptionStreamFactory(decryptionKeys, - decryptor, - verificationKeys, - missingPublicKeyCallback); - - PGPObjectFactory objectFactory = new PGPObjectFactory( - PGPUtil.getDecoderStream(inputStream), new BcKeyFingerprintCalculator()); - - return new DecryptionStream(factory.wrap(objectFactory), factory.resultBuilder); - } - - private InputStream wrap(@Nonnull PGPObjectFactory objectFactory) throws IOException, PGPException { - - Object pgpObj; - while ((pgpObj = objectFactory.nextObject()) != null) { - - if (pgpObj instanceof PGPEncryptedDataList) { - LOGGER.log(LEVEL, "Encountered PGPEncryptedDataList"); - PGPEncryptedDataList encDataList = (PGPEncryptedDataList) pgpObj; - InputStream nextStream = decrypt(encDataList); - objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(nextStream), fingerCalc); - return wrap(objectFactory); - } - - if (pgpObj instanceof PGPCompressedData) { - PGPCompressedData compressedData = (PGPCompressedData) pgpObj; - InputStream nextStream = compressedData.getDataStream(); - resultBuilder.setCompressionAlgorithm(CompressionAlgorithm.fromId(compressedData.getAlgorithm())); - objectFactory = new PGPObjectFactory(PGPUtil.getDecoderStream(nextStream), fingerCalc); - LOGGER.log(LEVEL, "Encountered PGPCompressedData: " + - CompressionAlgorithm.fromId(compressedData.getAlgorithm())); - return wrap(objectFactory); - } - - if (pgpObj instanceof PGPOnePassSignatureList) { - PGPOnePassSignatureList onePassSignatures = (PGPOnePassSignatureList) pgpObj; - LOGGER.log(LEVEL, "Encountered PGPOnePassSignatureList of size " + onePassSignatures.size()); - initOnePassSignatures(onePassSignatures); - return wrap(objectFactory); - } - - if (pgpObj instanceof PGPLiteralData) { - LOGGER.log(LEVEL, "Found PGPLiteralData"); - PGPLiteralData literalData = (PGPLiteralData) pgpObj; - InputStream literalDataInputStream = literalData.getInputStream(); - - if (verifiableOnePassSignatures.isEmpty()) { - LOGGER.log(LEVEL, "No OnePassSignatures found -> We are done"); - return literalDataInputStream; - } - - return new SignatureVerifyingInputStream(literalDataInputStream, - objectFactory, verifiableOnePassSignatures, resultBuilder); - } - } - - throw new PGPException("No Literal Data Packet found"); - } - - private InputStream decrypt(@Nonnull PGPEncryptedDataList encryptedDataList) - throws PGPException { - Iterator iterator = encryptedDataList.getEncryptedDataObjects(); - if (!iterator.hasNext()) { - throw new PGPException("Decryption failed - EncryptedDataList has no items"); - } - - PGPPrivateKey decryptionKey = null; - PGPPublicKeyEncryptedData encryptedSessionKey = null; - while (iterator.hasNext()) { - PGPPublicKeyEncryptedData encryptedData = (PGPPublicKeyEncryptedData) iterator.next(); - long keyId = encryptedData.getKeyID(); - - resultBuilder.addRecipientKeyId(keyId); - LOGGER.log(LEVEL, "PGPEncryptedData is encrypted for key " + Long.toHexString(keyId)); - - PGPSecretKey secretKey = decryptionKeys.getSecretKey(keyId); - if (secretKey != null) { - LOGGER.log(LEVEL, "Found respective secret key " + Long.toHexString(keyId)); - encryptedSessionKey = encryptedData; - decryptionKey = secretKey.extractPrivateKey(decryptionKeyDecryptor.getDecryptor(keyId)); - resultBuilder.setDecryptionFingerprint(new OpenPgpV4Fingerprint(secretKey)); - } - } - - if (decryptionKey == null) { - throw new PGPException("Decryption failed - No suitable decryption key found"); - } - - PublicKeyDataDecryptorFactory keyDecryptor = new BcPublicKeyDataDecryptorFactory(decryptionKey); - SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm - .fromId(encryptedSessionKey.getSymmetricAlgorithm(keyDecryptor)); - - LOGGER.log(LEVEL, "Message is encrypted using " + symmetricKeyAlgorithm); - resultBuilder.setSymmetricKeyAlgorithm(symmetricKeyAlgorithm); - - if (encryptedSessionKey.isIntegrityProtected()) { - LOGGER.log(LEVEL, "Message is integrity protected"); - resultBuilder.setIntegrityProtected(true); - } else { - LOGGER.log(LEVEL, "Message is not integrity protected"); - resultBuilder.setIntegrityProtected(false); - } - InputStream decryptionStream = encryptedSessionKey.getDataStream(keyDecryptor); - - return decryptionStream; - } - - private void initOnePassSignatures(@Nonnull PGPOnePassSignatureList onePassSignatureList) throws PGPException { - Iterator iterator = onePassSignatureList.iterator(); - if (!iterator.hasNext()) { - throw new PGPException("Verification failed - No OnePassSignatures found"); - } - - while (iterator.hasNext()) { - PGPOnePassSignature signature = iterator.next(); - final long keyId = signature.getKeyID(); - resultBuilder.addUnverifiedSignatureKeyId(keyId); - - LOGGER.log(LEVEL, "Message contains OnePassSignature from " + Long.toHexString(keyId)); - - // Find public key - PGPPublicKey verificationKey = null; - for (PGPPublicKeyRing publicKeyRing : verificationKeys) { - verificationKey = publicKeyRing.getPublicKey(keyId); - if (verificationKey != null) { - LOGGER.log(LEVEL, "Found respective public key " + Long.toHexString(keyId)); - break; - } - } - - if (verificationKey == null) { - LOGGER.log(Level.INFO, "No public key for signature of " + Long.toHexString(keyId) + " found."); - - if (missingPublicKeyCallback == null) { - LOGGER.log(Level.INFO, "Skip signature of " + Long.toHexString(keyId)); - continue; - } - - PGPPublicKey missingPublicKey = missingPublicKeyCallback.onMissingPublicKeyEncountered(keyId); - if (missingPublicKey == null) { - LOGGER.log(Level.INFO, "Skip signature of " + Long.toHexString(keyId)); - continue; - } - - if (missingPublicKey.getKeyID() != keyId) { - throw new IllegalArgumentException("KeyID of the provided public key differs from the signatures keyId. " + - "The signature was created from " + Long.toHexString(keyId) + " while the provided key has ID " + - Long.toHexString(missingPublicKey.getKeyID())); - } - - verificationKey = missingPublicKey; - } - - signature.init(verifierBuilderProvider, verificationKey); - verifiableOnePassSignatures.put(new OpenPgpV4Fingerprint(verificationKey), signature); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MissingPublicKeyCallback.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MissingPublicKeyCallback.java deleted file mode 100644 index 9ca3bfa3..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/MissingPublicKeyCallback.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.decryption_verification; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPPublicKey; - -public interface MissingPublicKeyCallback { - - /** - * This method gets called if we encounter a signature of an unknown key. - * - * Note: It would be super cool to provide the OpenPgp fingerprint here, but unfortunately signatures only contain - * the key id (see https://tools.ietf.org/html/rfc4880#section-5.2.3.5) - * - * @param keyId ID of the missing key - * - * @return the key or null - */ - PGPPublicKey onMissingPublicKeyEncountered(@Nonnull Long keyId); - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java deleted file mode 100644 index 5ae994fe..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpMetadata.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.decryption_verification; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.key.OpenPgpV4Fingerprint; - -public class OpenPgpMetadata { - - private final Set recipientKeyIds; - private final OpenPgpV4Fingerprint decryptionFingerprint; - private final Set unverifiedSignatureKeyIds; - private final Set verifiedSignaturesFingerprints; - - private final SymmetricKeyAlgorithm symmetricKeyAlgorithm; - private final CompressionAlgorithm compressionAlgorithm; - private final boolean integrityProtected; - - public OpenPgpMetadata(Set recipientKeyIds, - OpenPgpV4Fingerprint decryptionFingerprint, - SymmetricKeyAlgorithm symmetricKeyAlgorithm, - CompressionAlgorithm algorithm, - boolean integrityProtected, - Set unverifiedSignatureKeyIds, - Set verifiedSignaturesFingerprints) { - - this.recipientKeyIds = Collections.unmodifiableSet(recipientKeyIds); - this.decryptionFingerprint = decryptionFingerprint; - this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; - this.compressionAlgorithm = algorithm; - this.integrityProtected = integrityProtected; - this.unverifiedSignatureKeyIds = Collections.unmodifiableSet(unverifiedSignatureKeyIds); - this.verifiedSignaturesFingerprints = Collections.unmodifiableSet(verifiedSignaturesFingerprints); - } - - public Set getRecipientKeyIds() { - return recipientKeyIds; - } - - public boolean isEncrypted() { - return !getRecipientKeyIds().isEmpty(); - } - - public OpenPgpV4Fingerprint getDecryptionFingerprint() { - return decryptionFingerprint; - } - - public SymmetricKeyAlgorithm getSymmetricKeyAlgorithm() { - return symmetricKeyAlgorithm; - } - - public CompressionAlgorithm getCompressionAlgorithm() { - return compressionAlgorithm; - } - - public boolean isIntegrityProtected() { - return integrityProtected; - } - - public Set getAllSignatureKeyFingerprints() { - return unverifiedSignatureKeyIds; - } - - public boolean isSigned() { - return !unverifiedSignatureKeyIds.isEmpty(); - } - - public Set getVerifiedSignaturesFingerprints() { - return verifiedSignaturesFingerprints; - } - - public boolean isVerified() { - return !verifiedSignaturesFingerprints.isEmpty(); - } - - public boolean containsVerifiedSignatureFrom(PGPPublicKeyRing publicKeys) { - for (PGPPublicKey key : publicKeys) { - OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(key); - if (containsVerifiedSignatureFrom(fingerprint)) { - return true; - } - } - return false; - } - - public boolean containsVerifiedSignatureFrom(OpenPgpV4Fingerprint fingerprint) { - return verifiedSignaturesFingerprints.contains(fingerprint); - } - - static Builder getBuilder() { - return new Builder(); - } - - static class Builder { - - private final Set recipientFingerprints = new HashSet<>(); - private OpenPgpV4Fingerprint decryptionFingerprint; - private final Set unverifiedSignatureKeyIds = new HashSet<>(); - private final Set verifiedSignatureFingerprints = new HashSet<>(); - private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.NULL; - private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED; - private boolean integrityProtected = false; - - public Builder addRecipientKeyId(Long keyId) { - this.recipientFingerprints.add(keyId); - return this; - } - - public Builder setDecryptionFingerprint(OpenPgpV4Fingerprint fingerprint) { - this.decryptionFingerprint = fingerprint; - return this; - } - - public Builder setCompressionAlgorithm(CompressionAlgorithm algorithm) { - this.compressionAlgorithm = algorithm; - return this; - } - - public Builder addUnverifiedSignatureKeyId(Long keyId) { - this.unverifiedSignatureKeyIds.add(keyId); - return this; - } - - public Builder addVerifiedSignatureFingerprint(OpenPgpV4Fingerprint fingerprint) { - this.verifiedSignatureFingerprints.add(fingerprint); - return this; - } - - public Builder setSymmetricKeyAlgorithm(SymmetricKeyAlgorithm symmetricKeyAlgorithm) { - this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; - return this; - } - - public Builder setIntegrityProtected(boolean integrityProtected) { - this.integrityProtected = integrityProtected; - return this; - } - - public OpenPgpMetadata build() { - return new OpenPgpMetadata(recipientFingerprints, decryptionFingerprint, symmetricKeyAlgorithm, compressionAlgorithm, integrityProtected, unverifiedSignatureKeyIds, verifiedSignatureFingerprints); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/SignatureVerifyingInputStream.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/SignatureVerifyingInputStream.java deleted file mode 100644 index 312d92fa..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/SignatureVerifyingInputStream.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.decryption_verification; - -import javax.annotation.Nonnull; -import java.io.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.security.SignatureException; -import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPObjectFactory; -import org.bouncycastle.openpgp.PGPOnePassSignature; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureList; -import org.pgpainless.key.OpenPgpV4Fingerprint; - -public class SignatureVerifyingInputStream extends FilterInputStream { - - private static final Logger LOGGER = Logger.getLogger(SignatureVerifyingInputStream.class.getName()); - private static final Level LEVEL = Level.INFO; - - private final PGPObjectFactory objectFactory; - private final Map onePassSignatures; - private final OpenPgpMetadata.Builder resultBuilder; - - private boolean validated = false; - - protected SignatureVerifyingInputStream(@Nonnull InputStream inputStream, - @Nonnull PGPObjectFactory objectFactory, - @Nonnull Map onePassSignatures, - @Nonnull OpenPgpMetadata.Builder resultBuilder) { - super(inputStream); - this.objectFactory = objectFactory; - this.resultBuilder = resultBuilder; - this.onePassSignatures = onePassSignatures; - - LOGGER.log(LEVEL, "Begin verifying OnePassSignatures"); - } - - private void updateOnePassSignatures(byte data) { - for (PGPOnePassSignature signature : onePassSignatures.values()) { - signature.update(data); - } - } - - private void updateOnePassSignatures(byte[] b, int off, int len) { - for (PGPOnePassSignature signature : onePassSignatures.values()) { - signature.update(b, off, len); - } - } - - private void validateOnePassSignatures() throws IOException { - - if (validated) { - LOGGER.log(LEVEL, "Validated signatures already. Skip"); - return; - } - - validated = true; - - if (onePassSignatures.isEmpty()) { - LOGGER.log(LEVEL, "No One-Pass-Signatures found -> No validation"); - return; - } - - try { - PGPSignatureList signatureList = null; - Object obj = objectFactory.nextObject(); - while (obj != null && signatureList == null) { - if (obj instanceof PGPSignatureList) { - signatureList = (PGPSignatureList) obj; - } else { - obj = objectFactory.nextObject(); - } - } - - if (signatureList == null || signatureList.isEmpty()) { - throw new IOException("Verification failed - No Signatures found"); - } - - for (PGPSignature signature : signatureList) { - OpenPgpV4Fingerprint fingerprint = null; - for (OpenPgpV4Fingerprint f : onePassSignatures.keySet()) { - if (f.getKeyId() == signature.getKeyID()) { - fingerprint = f; - break; - } - } - - PGPOnePassSignature onePassSignature; - if (fingerprint == null || (onePassSignature = onePassSignatures.get(fingerprint)) == null) { - LOGGER.log(LEVEL, "Found Signature without respective OnePassSignature packet -> skip"); - continue; - } - - if (!onePassSignature.verify(signature)) { - throw new SignatureException("Bad Signature of key " + signature.getKeyID()); - } else { - LOGGER.log(LEVEL, "Verified signature of key " + Long.toHexString(signature.getKeyID())); - resultBuilder.addVerifiedSignatureFingerprint(fingerprint); - } - } - } catch (PGPException | SignatureException e) { - throw new IOException(e.getMessage(), e); - } - - } - - @Override - public int read() throws IOException { - final int data = super.read(); - final boolean endOfStream = data == -1; - if (endOfStream) { - validateOnePassSignatures(); - } else { - updateOnePassSignatures((byte) data); - } - return data; - } - - @Override - public int read(byte[] b) throws IOException { - return read(b, 0, b.length); - } - - @Override - public int read(byte[] b, int off, int len) throws IOException { - int read = super.read(b, off, len); - - final boolean endOfStream = read == -1; - if (endOfStream) { - validateOnePassSignatures(); - } else { - updateOnePassSignatures(b, off, read); - } - return read; - } - - @Override - public long skip(long n) { - throw new UnsupportedOperationException("skip() is not supported"); - } - - @Override - public synchronized void mark(int readlimit) { - throw new UnsupportedOperationException("mark() not supported"); - } - - @Override - public synchronized void reset() { - throw new UnsupportedOperationException("reset() is not supported"); - } - - @Override - public boolean markSupported() { - return false; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/package-info.java deleted file mode 100644 index 37376629..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes used to decryption and verification of OpenPGP encrypted / signed data. - */ -package org.pgpainless.decryption_verification; diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java deleted file mode 100644 index ae5665c0..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilder.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.encryption_signing; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPrivateKey; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.key.protection.SecretKeyRingProtector; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; -import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; -import org.pgpainless.key.selection.key.impl.And; -import org.pgpainless.key.selection.key.impl.EncryptionKeySelectionStrategy; -import org.pgpainless.key.selection.key.impl.NoRevocation; -import org.pgpainless.key.selection.key.impl.SignatureKeySelectionStrategy; -import org.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy; -import org.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy; -import org.pgpainless.util.MultiMap; - -public class EncryptionBuilder implements EncryptionBuilderInterface { - - private OutputStream outputStream; - private final Set encryptionKeys = new HashSet<>(); - private final Set signingKeys = new HashSet<>(); - private SecretKeyRingProtector signingKeysDecryptor; - private SymmetricKeyAlgorithm symmetricKeyAlgorithm = SymmetricKeyAlgorithm.AES_128; - private HashAlgorithm hashAlgorithm = HashAlgorithm.SHA256; - private CompressionAlgorithm compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED; - private boolean asciiArmor = false; - - @Override - public ToRecipients onOutputStream(@Nonnull OutputStream outputStream) { - this.outputStream = outputStream; - return new ToRecipientsImpl(); - } - - class ToRecipientsImpl implements ToRecipients { - - @Override - public WithAlgorithms toRecipients(@Nonnull PGPPublicKey... keys) { - for (PGPPublicKey k : keys) { - if (encryptionKeySelector().accept(null, k)) { - EncryptionBuilder.this.encryptionKeys.add(k); - } else { - throw new IllegalArgumentException("Key " + k.getKeyID() + " is not a valid encryption key."); - } - } - - if (EncryptionBuilder.this.encryptionKeys.isEmpty()) { - throw new IllegalStateException("No valid encryption keys found!"); - } - - return new WithAlgorithmsImpl(); - } - - @Override - public WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRing... keys) { - for (PGPPublicKeyRing ring : keys) { - for (PGPPublicKey k : ring) { - if (encryptionKeySelector().accept(null, k)) { - EncryptionBuilder.this.encryptionKeys.add(k); - } - } - } - - if (EncryptionBuilder.this.encryptionKeys.isEmpty()) { - throw new IllegalStateException("No valid encryption keys found!"); - } - - return new WithAlgorithmsImpl(); - } - - @Override - public WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRingCollection... keys) { - for (PGPPublicKeyRingCollection collection : keys) { - for (PGPPublicKeyRing ring : collection) { - for (PGPPublicKey k : ring) { - if (encryptionKeySelector().accept(null, k)) { - EncryptionBuilder.this.encryptionKeys.add(k); - } - } - } - } - - if (EncryptionBuilder.this.encryptionKeys.isEmpty()) { - throw new IllegalStateException("No valid encryption keys found!"); - } - - return new WithAlgorithmsImpl(); - } - - @Override - public WithAlgorithms toRecipients(@Nonnull PublicKeyRingSelectionStrategy ringSelectionStrategy, - @Nonnull MultiMap keys) { - if (keys.isEmpty()) { - throw new IllegalArgumentException("Recipient map MUST NOT be empty."); - } - MultiMap acceptedKeyRings = ringSelectionStrategy.selectKeyRingsFromCollections(keys); - for (O identifier : acceptedKeyRings.keySet()) { - Set acceptedSet = acceptedKeyRings.get(identifier); - for (PGPPublicKeyRing ring : acceptedSet) { - for (PGPPublicKey k : ring) { - if (encryptionKeySelector().accept(null, k)) { - EncryptionBuilder.this.encryptionKeys.add(k); - } - } - } - } - - if (EncryptionBuilder.this.encryptionKeys.isEmpty()) { - throw new IllegalStateException("No valid encryption keys found!"); - } - - return new WithAlgorithmsImpl(); - } - - @Override - public SignWith doNotEncrypt() { - return new SignWithImpl(); - } - } - - class WithAlgorithmsImpl implements WithAlgorithms { - - @Override - public WithAlgorithms andToSelf(@Nonnull PGPPublicKey... keys) { - if (keys.length == 0) { - throw new IllegalArgumentException("Recipient list MUST NOT be empty."); - } - for (PGPPublicKey k : keys) { - if (encryptionKeySelector().accept(null, k)) { - EncryptionBuilder.this.encryptionKeys.add(k); - } else { - throw new IllegalArgumentException("Key " + k.getKeyID() + " is not a valid encryption key."); - } - } - return this; - } - - @Override - public WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRing... keys) { - if (keys.length == 0) { - throw new IllegalArgumentException("Recipient list MUST NOT be empty."); - } - for (PGPPublicKeyRing ring : keys) { - for (Iterator i = ring.getPublicKeys(); i.hasNext(); ) { - PGPPublicKey key = i.next(); - if (encryptionKeySelector().accept(null, key)) { - EncryptionBuilder.this.encryptionKeys.add(key); - } - } - } - return this; - } - - @Override - public WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRingCollection keys) { - for (PGPPublicKeyRing ring : keys) { - for (Iterator i = ring.getPublicKeys(); i.hasNext(); ) { - PGPPublicKey key = i.next(); - if (encryptionKeySelector().accept(null, key)) { - EncryptionBuilder.this.encryptionKeys.add(key); - } - } - } - return this; - } - - public WithAlgorithms andToSelf(@Nonnull PublicKeyRingSelectionStrategy ringSelectionStrategy, - @Nonnull MultiMap keys) { - if (keys.isEmpty()) { - throw new IllegalArgumentException("Recipient list MUST NOT be empty."); - } - MultiMap acceptedKeyRings = - ringSelectionStrategy.selectKeyRingsFromCollections(keys); - for (O identifier : acceptedKeyRings.keySet()) { - Set acceptedSet = acceptedKeyRings.get(identifier); - for (PGPPublicKeyRing k : acceptedSet) { - for (Iterator i = k.getPublicKeys(); i.hasNext(); ) { - PGPPublicKey key = i.next(); - if (encryptionKeySelector().accept(null, key)) { - EncryptionBuilder.this.encryptionKeys.add(key); - } - } - } - } - return this; - } - - @Override - public SignWith usingAlgorithms(@Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm, - @Nonnull HashAlgorithm hashAlgorithm, - @Nonnull CompressionAlgorithm compressionAlgorithm) { - - EncryptionBuilder.this.symmetricKeyAlgorithm = symmetricKeyAlgorithm; - EncryptionBuilder.this.hashAlgorithm = hashAlgorithm; - EncryptionBuilder.this.compressionAlgorithm = compressionAlgorithm; - - return new SignWithImpl(); - } - - @Override - public SignWith usingSecureAlgorithms() { - EncryptionBuilder.this.symmetricKeyAlgorithm = SymmetricKeyAlgorithm.AES_256; - EncryptionBuilder.this.hashAlgorithm = HashAlgorithm.SHA512; - EncryptionBuilder.this.compressionAlgorithm = CompressionAlgorithm.UNCOMPRESSED; - - return new SignWithImpl(); - } - } - - class SignWithImpl implements SignWith { - - @Override - public Armor signWith(@Nonnull SecretKeyRingProtector decryptor, - @Nonnull PGPSecretKey... keys) { - if (keys.length == 0) { - throw new IllegalArgumentException("Recipient list MUST NOT be empty."); - } - for (PGPSecretKey s : keys) { - if (EncryptionBuilder.this.signingKeySelector().accept(null, s)) { - signingKeys.add(s); - } else { - throw new IllegalArgumentException("Key " + s.getKeyID() + " is not a valid signing key."); - } - } - EncryptionBuilder.this.signingKeysDecryptor = decryptor; - return new ArmorImpl(); - } - - @Override - public Armor signWith(@Nonnull SecretKeyRingProtector decryptor, - @Nonnull PGPSecretKeyRing... keys) { - if (keys.length == 0) { - throw new IllegalArgumentException("Recipient list MUST NOT be empty."); - } - for (PGPSecretKeyRing key : keys) { - for (Iterator i = key.getSecretKeys(); i.hasNext(); ) { - PGPSecretKey s = i.next(); - if (EncryptionBuilder.this.signingKeySelector().accept(null, s)) { - EncryptionBuilder.this.signingKeys.add(s); - } - } - } - EncryptionBuilder.this.signingKeysDecryptor = decryptor; - return new ArmorImpl(); - } - - @Override - public Armor signWith(@Nonnull SecretKeyRingSelectionStrategy ringSelectionStrategy, - @Nonnull SecretKeyRingProtector decryptor, - @Nonnull MultiMap keys) { - if (keys.isEmpty()) { - throw new IllegalArgumentException("Recipient list MUST NOT be empty."); - } - MultiMap acceptedKeyRings = - ringSelectionStrategy.selectKeyRingsFromCollections(keys); - for (O identifier : acceptedKeyRings.keySet()) { - Set acceptedSet = acceptedKeyRings.get(identifier); - for (PGPSecretKeyRing k : acceptedSet) { - for (Iterator i = k.getSecretKeys(); i.hasNext(); ) { - PGPSecretKey s = i.next(); - if (EncryptionBuilder.this.signingKeySelector().accept(null, s)) { - EncryptionBuilder.this.signingKeys.add(s); - } - } - } - } - return new ArmorImpl(); - } - - @Override - public Armor doNotSign() { - return new ArmorImpl(); - } - } - - class ArmorImpl implements Armor { - - @Override - public EncryptionStream asciiArmor() throws IOException, PGPException { - EncryptionBuilder.this.asciiArmor = true; - return build(); - } - - @Override - public EncryptionStream noArmor() throws IOException, PGPException { - EncryptionBuilder.this.asciiArmor = false; - return build(); - } - - private EncryptionStream build() throws IOException, PGPException { - - Set privateKeys = new HashSet<>(); - for (PGPSecretKey secretKey : signingKeys) { - privateKeys.add(secretKey.extractPrivateKey(signingKeysDecryptor.getDecryptor(secretKey.getKeyID()))); - } - - return new EncryptionStream( - EncryptionBuilder.this.outputStream, - EncryptionBuilder.this.encryptionKeys, - privateKeys, - EncryptionBuilder.this.symmetricKeyAlgorithm, - EncryptionBuilder.this.hashAlgorithm, - EncryptionBuilder.this.compressionAlgorithm, - EncryptionBuilder.this.asciiArmor); - } - } - - PublicKeySelectionStrategy encryptionKeySelector() { - return new And.PubKeySelectionStrategy<>( - new NoRevocation.PubKeySelectionStrategy<>(), - new EncryptionKeySelectionStrategy<>()); - } - - SecretKeySelectionStrategy signingKeySelector() { - return new And.SecKeySelectionStrategy<>( - new NoRevocation.SecKeySelectionStrategy<>(), - new SignatureKeySelectionStrategy<>()); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java deleted file mode 100644 index e0f79a36..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionBuilderInterface.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.encryption_signing; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.io.OutputStream; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.exception.SecretKeyNotFoundException; -import org.pgpainless.key.protection.SecretKeyRingProtector; -import org.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy; -import org.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy; -import org.pgpainless.util.MultiMap; - -public interface EncryptionBuilderInterface { - - ToRecipients onOutputStream(@Nonnull OutputStream outputStream); - - interface ToRecipients { - - WithAlgorithms toRecipients(@Nonnull PGPPublicKey... keys); - - WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRing... keys); - - WithAlgorithms toRecipients(@Nonnull PGPPublicKeyRingCollection... keys); - - WithAlgorithms toRecipients(@Nonnull PublicKeyRingSelectionStrategy selectionStrategy, - @Nonnull MultiMap keys); - - SignWith doNotEncrypt(); - - } - - interface WithAlgorithms { - - WithAlgorithms andToSelf(@Nonnull PGPPublicKey... keys); - - WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRing... keys); - - WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRingCollection keys); - - WithAlgorithms andToSelf(@Nonnull PublicKeyRingSelectionStrategy selectionStrategy, - @Nonnull MultiMap keys); - - SignWith usingAlgorithms(@Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm, - @Nonnull HashAlgorithm hashAlgorithm, - @Nonnull CompressionAlgorithm compressionAlgorithm); - - SignWith usingSecureAlgorithms(); - - } - - interface SignWith { - - Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys); - - Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings); - - Armor signWith(@Nonnull SecretKeyRingSelectionStrategy selectionStrategy, - @Nonnull SecretKeyRingProtector decryptor, - @Nonnull MultiMap keys) - throws SecretKeyNotFoundException; - - Armor doNotSign(); - - } - - interface Armor { - - EncryptionStream asciiArmor() throws IOException, PGPException; - - EncryptionStream noArmor() throws IOException, PGPException; - - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java deleted file mode 100644 index d2c7b1d1..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/EncryptionStream.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.encryption_signing; - -import javax.annotation.Nonnull; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.bcpg.ArmoredOutputStream; -import org.bouncycastle.bcpg.BCPGOutputStream; -import org.bouncycastle.openpgp.PGPCompressedDataGenerator; -import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPLiteralData; -import org.bouncycastle.openpgp.PGPLiteralDataGenerator; -import org.bouncycastle.openpgp.PGPPrivateKey; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureGenerator; -import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPublicKeyKeyEncryptionMethodGenerator; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.decryption_verification.OpenPgpMetadata; - -/** - * This class is based upon Jens Neuhalfen's Bouncy-GPG PGPEncryptingStream. - * @see Source - */ -public final class EncryptionStream extends OutputStream { - - private static final Logger LOGGER = Logger.getLogger(EncryptionStream.class.getName()); - private static final Level LEVEL = Level.FINE; - - private static final int BUFFER_SIZE = 1 << 8; - - private final OpenPgpMetadata result; - - private List signatureGenerators = new ArrayList<>(); - private boolean closed = false; - - // ASCII Armor - private ArmoredOutputStream armorOutputStream = null; - - // Public Key Encryption of Symmetric Session Key - private OutputStream publicKeyEncryptedStream = null; - - // Data Compression - private PGPCompressedDataGenerator compressedDataGenerator; - private BCPGOutputStream basicCompressionStream; - - // Literal Data - private PGPLiteralDataGenerator literalDataGenerator; - private OutputStream literalDataStream; - - EncryptionStream(@Nonnull OutputStream targetOutputStream, - @Nonnull Set encryptionKeys, - @Nonnull Set signingKeys, - @Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm, - @Nonnull HashAlgorithm hashAlgorithm, - @Nonnull CompressionAlgorithm compressionAlgorithm, - boolean asciiArmor) - throws IOException, PGPException { - - // Currently outermost Stream - OutputStream outerMostStream; - if (asciiArmor) { - LOGGER.log(LEVEL, "Wrap encryption output in ASCII armor"); - armorOutputStream = new ArmoredOutputStream(targetOutputStream); - outerMostStream = armorOutputStream; - } else { - LOGGER.log(LEVEL, "Encryption output will be binary"); - outerMostStream = targetOutputStream; - } - - // If we want to encrypt - if (!encryptionKeys.isEmpty()) { - LOGGER.log(LEVEL, "At least one encryption key is available -> encrypt using " + symmetricKeyAlgorithm); - BcPGPDataEncryptorBuilder dataEncryptorBuilder = - new BcPGPDataEncryptorBuilder(symmetricKeyAlgorithm.getAlgorithmId()); - - LOGGER.log(LEVEL, "Integrity protection enabled"); - dataEncryptorBuilder.setWithIntegrityPacket(true); - - PGPEncryptedDataGenerator encryptedDataGenerator = - new PGPEncryptedDataGenerator(dataEncryptorBuilder); - - for (PGPPublicKey key : encryptionKeys) { - LOGGER.log(LEVEL, "Encrypt for key " + Long.toHexString(key.getKeyID())); - encryptedDataGenerator.addMethod(new BcPublicKeyKeyEncryptionMethodGenerator(key)); - } - - publicKeyEncryptedStream = encryptedDataGenerator.open(outerMostStream, new byte[BUFFER_SIZE]); - outerMostStream = publicKeyEncryptedStream; - } - - // If we want to sign, prepare for signing - if (!signingKeys.isEmpty()) { - LOGGER.log(LEVEL, "At least one signing key is available -> sign " + hashAlgorithm + " hash of message"); - for (PGPPrivateKey privateKey : signingKeys) { - LOGGER.log(LEVEL, "Sign using key " + Long.toHexString(privateKey.getKeyID())); - BcPGPContentSignerBuilder contentSignerBuilder = new BcPGPContentSignerBuilder( - privateKey.getPublicKeyPacket().getAlgorithm(), hashAlgorithm.getAlgorithmId()); - - PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder); - signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); - signatureGenerators.add(signatureGenerator); - } - } - - LOGGER.log(LEVEL, "Compress using " + compressionAlgorithm); - // Compression - compressedDataGenerator = new PGPCompressedDataGenerator( - compressionAlgorithm.getAlgorithmId()); - basicCompressionStream = new BCPGOutputStream(compressedDataGenerator.open(outerMostStream)); - - // If we want to sign, sign! - for (PGPSignatureGenerator signatureGenerator : signatureGenerators) { - signatureGenerator.generateOnePassVersion(false).encode(basicCompressionStream); - } - - literalDataGenerator = new PGPLiteralDataGenerator(); - literalDataStream = literalDataGenerator.open(basicCompressionStream, - PGPLiteralData.BINARY, PGPLiteralData.CONSOLE, new Date(), new byte[BUFFER_SIZE]); - - // Prepare result - Set recipientKeyIds = new HashSet<>(); - for (PGPPublicKey recipient : encryptionKeys) { - recipientKeyIds.add(recipient.getKeyID()); - } - - Set signingKeyIds = new HashSet<>(); - for (PGPPrivateKey signer : signingKeys) { - signingKeyIds.add(signer.getKeyID()); - } - - - this.result = new OpenPgpMetadata(recipientKeyIds, - null, symmetricKeyAlgorithm, - compressionAlgorithm, true, - signingKeyIds, Collections.emptySet()); - } - - @Override - public void write(int data) throws IOException { - literalDataStream.write(data); - - for (PGPSignatureGenerator signatureGenerator : signatureGenerators) { - byte asByte = (byte) (data & 0xff); - signatureGenerator.update(asByte); - } - } - - @Override - public void write(byte[] buffer) throws IOException { - write(buffer, 0, buffer.length); - } - - - @Override - public void write(byte[] buffer, int off, int len) throws IOException { - literalDataStream.write(buffer, 0, len); - for (PGPSignatureGenerator signatureGenerator : signatureGenerators) { - signatureGenerator.update(buffer, 0, len); - } - } - - @Override - public void flush() throws IOException { - literalDataStream.flush(); - } - - @Override - public void close() throws IOException { - if (!closed) { - - // Literal Data - literalDataStream.flush(); - literalDataStream.close(); - literalDataGenerator.close(); - - // Signing - for (PGPSignatureGenerator signatureGenerator : signatureGenerators) { - try { - signatureGenerator.generate().encode(basicCompressionStream); - } catch (PGPException e) { - throw new IOException(e); - } - } - - // Compressed Data - compressedDataGenerator.close(); - - // Public Key Encryption - if (publicKeyEncryptedStream != null) { - publicKeyEncryptedStream.flush(); - publicKeyEncryptedStream.close(); - } - - // Armor - if (armorOutputStream != null) { - armorOutputStream.flush(); - armorOutputStream.close(); - } - closed = true; - } - } - - public OpenPgpMetadata getResult() { - return result; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/package-info.java deleted file mode 100644 index c7e05044..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/encryption_signing/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes used to encrypt or sign data using OpenPGP. - */ -package org.pgpainless.encryption_signing; diff --git a/pgpainless-core/src/main/java/org/pgpainless/exception/SecretKeyNotFoundException.java b/pgpainless-core/src/main/java/org/pgpainless/exception/SecretKeyNotFoundException.java deleted file mode 100644 index 61966203..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/exception/SecretKeyNotFoundException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.exception; - -public class SecretKeyNotFoundException extends Exception { - - private static final long serialVersionUID = 1L; - - private long keyId; - - public SecretKeyNotFoundException(long keyId) { - super("No PGPSecretKey with id " + Long.toHexString(keyId) + " (" + keyId + ") found."); - this.keyId = keyId; - } - - public long getKeyId() { - return keyId; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/exception/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/exception/package-info.java deleted file mode 100644 index 1d5adbd2..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/exception/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Exceptions. - */ -package org.pgpainless.exception; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV4Fingerprint.java b/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV4Fingerprint.java deleted file mode 100644 index f051d086..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/OpenPgpV4Fingerprint.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key; - -import javax.annotation.Nonnull; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Arrays; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.util.encoders.Hex; - -/** - * This class represents an hex encoded, uppercase OpenPGP v4 fingerprint. - */ -public class OpenPgpV4Fingerprint implements CharSequence, Comparable { - - private final String fingerprint; - - /** - * Create an {@link OpenPgpV4Fingerprint}. - * @see - * XEP-0373 §4.1: The OpenPGP Public-Key Data Node about how to obtain the fingerprint - * @param fingerprint hexadecimal representation of the fingerprint. - */ - public OpenPgpV4Fingerprint(@Nonnull String fingerprint) { - String fp = fingerprint.trim().toUpperCase(); - if (!isValid(fp)) { - throw new IllegalArgumentException("Fingerprint " + fingerprint + - " does not appear to be a valid OpenPGP v4 fingerprint."); - } - this.fingerprint = fp; - } - - public OpenPgpV4Fingerprint(@Nonnull byte[] bytes) { - this(new String(bytes, Charset.forName("UTF-8"))); - } - - public OpenPgpV4Fingerprint(@Nonnull PGPPublicKey key) { - this(Hex.encode(key.getFingerprint())); - if (key.getVersion() != 4) { - throw new IllegalArgumentException("Key is not a v4 OpenPgp key."); - } - } - - public OpenPgpV4Fingerprint(@Nonnull PGPSecretKey key) { - this(key.getPublicKey()); - } - - public OpenPgpV4Fingerprint(@Nonnull PGPPublicKeyRing ring) { - this(ring.getPublicKey()); - } - - public OpenPgpV4Fingerprint(@Nonnull PGPSecretKeyRing ring) { - this(ring.getPublicKey()); - } - - /** - * Check, whether the fingerprint consists of 40 valid hexadecimal characters. - * @param fp fingerprint to check. - * @return true if fingerprint is valid. - */ - private static boolean isValid(@Nonnull String fp) { - return fp.matches("[0-9A-F]{40}"); - } - - /** - * Return the key id of the OpenPGP public key this {@link OpenPgpV4Fingerprint} belongs to. - * - * @see - * RFC-4880 §12.2: Key IDs and Fingerprints - * @return key id - */ - public long getKeyId() { - - byte[] bytes = new BigInteger(toString(), 16).toByteArray(); - if (bytes.length != toString().length() / 2) { - bytes = Arrays.copyOfRange(bytes, 1, bytes.length); - } - - byte[] lower8Bytes = Arrays.copyOfRange(bytes, 12, 20); - ByteBuffer byteBuffer = ByteBuffer.allocate(8); - byteBuffer.put(lower8Bytes); - byteBuffer.flip(); - return byteBuffer.getLong(); - } - - @Override - public boolean equals(Object other) { - if (other == null) { - return false; - } - - if (!(other instanceof CharSequence)) { - return false; - } - - return this.toString().equals(other.toString()); - } - - @Override - public int hashCode() { - return fingerprint.hashCode(); - } - - @Override - public int length() { - return fingerprint.length(); - } - - @Override - public char charAt(int i) { - return fingerprint.charAt(i); - } - - @Override - public CharSequence subSequence(int i, int i1) { - return fingerprint.subSequence(i, i1); - } - - @Override - public String toString() { - return fingerprint; - } - - @Override - public int compareTo(@Nonnull OpenPgpV4Fingerprint openPgpV4Fingerprint) { - return fingerprint.compareTo(openPgpV4Fingerprint.fingerprint); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/collection/KeyRingCollection.java b/pgpainless-core/src/main/java/org/pgpainless/key/collection/KeyRingCollection.java deleted file mode 100644 index aae9f814..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/collection/KeyRingCollection.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.collection; - -import javax.annotation.Nonnull; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.pgpainless.PGPainless; - -public class KeyRingCollection { - - private static final Logger LOGGER = Logger.getLogger(KeyRingCollection.class.getName()); - - private PGPPublicKeyRingCollection publicKeys; - private PGPSecretKeyRingCollection secretKeys; - - public KeyRingCollection(@Nonnull PGPPublicKeyRingCollection publicKeyRings, @Nonnull PGPSecretKeyRingCollection secretKeyRings) { - this.publicKeys = publicKeyRings; - this.secretKeys = secretKeyRings; - } - - public KeyRingCollection(File pubRingFile, File secRingFile) throws IOException, PGPException { - - if (pubRingFile == null && secRingFile == null) { - throw new NullPointerException("pubRingFile and secRingFile cannot BOTH be null."); - } - - if (pubRingFile != null) { - InputStream pubRingIn = new FileInputStream(pubRingFile); - this.publicKeys = PGPainless.readKeyRing().publicKeyRingCollection(pubRingIn); - pubRingIn.close(); - } - - if (secRingFile != null) { - InputStream secRingIn = new FileInputStream(secRingFile); - this.secretKeys = PGPainless.readKeyRing().secretKeyRingCollection(secRingIn); - secRingIn.close(); - } - } - - public KeyRingCollection(@Nonnull PGPPublicKeyRingCollection publicKeyRings) { - this.publicKeys = publicKeyRings; - } - - public KeyRingCollection(@Nonnull PGPSecretKeyRingCollection secretKeyRings) { - this.secretKeys = secretKeyRings; - } - - public void importPublicKeys(@Nonnull PGPPublicKeyRingCollection publicKeyRings) { - if (this.publicKeys == null) { - this.publicKeys = publicKeyRings; - return; - } - - for (PGPPublicKeyRing keyRing : publicKeyRings) { - try { - this.publicKeys = PGPPublicKeyRingCollection.addPublicKeyRing(this.publicKeys, keyRing); - } catch (IllegalArgumentException e) { - // TODO: merge key rings. - LOGGER.log(Level.FINE, "Keyring " + Long.toHexString(keyRing.getPublicKey().getKeyID()) + - " is already included in the collection. Skip!"); - } - } - } - - public void importSecretKeys(@Nonnull PGPSecretKeyRingCollection secretKeyRings) { - if (this.secretKeys == null) { - this.secretKeys = secretKeyRings; - return; - } - - for (PGPSecretKeyRing keyRing : secretKeyRings) { - try { - this.secretKeys = PGPSecretKeyRingCollection.addSecretKeyRing(this.secretKeys, keyRing); - } catch (IllegalArgumentException e) { - // TODO: merge key rings. - LOGGER.log(Level.FINE, "Keyring " + Long.toHexString(keyRing.getPublicKey().getKeyID()) + - " is already included in the collection. Skip!"); - } - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRing.java b/pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRing.java deleted file mode 100644 index 429733aa..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/collection/PGPKeyRing.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.collection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.pgpainless.key.OpenPgpV4Fingerprint; - -public class PGPKeyRing { - - private PGPPublicKeyRing publicKeys; - private PGPSecretKeyRing secretKeys; - - public PGPKeyRing(@Nonnull PGPPublicKeyRing publicKeys, @Nonnull PGPSecretKeyRing secretKeys) { - - if (publicKeys.getPublicKey().getKeyID() != secretKeys.getPublicKey().getKeyID()) { - throw new IllegalArgumentException("publicKeys and secretKeys must have the same master key."); - } - - this.publicKeys = publicKeys; - this.secretKeys = secretKeys; - } - - public PGPKeyRing(@Nonnull PGPPublicKeyRing publicKeys) { - this.publicKeys = publicKeys; - } - - public PGPKeyRing(@Nonnull PGPSecretKeyRing secretKeys) { - this.secretKeys = secretKeys; - } - - public long getKeyId() { - return getMasterKey().getKeyID(); - } - - public @Nonnull PGPPublicKey getMasterKey() { - PGPPublicKey publicKey = hasSecretKeys() ? secretKeys.getPublicKey() : publicKeys.getPublicKey(); - if (!publicKey.isMasterKey()) { - throw new IllegalStateException("Expected master key is not a master key"); - } - return publicKey; - } - - public @Nonnull OpenPgpV4Fingerprint getV4Fingerprint() { - return new OpenPgpV4Fingerprint(getMasterKey()); - } - - public boolean hasSecretKeys() { - return secretKeys != null; - } - - public @Nullable PGPPublicKeyRing getPublicKeys() { - return publicKeys; - } - - public @Nullable PGPSecretKeyRing getSecretKeys() { - return secretKeys; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/collection/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/collection/package-info.java deleted file mode 100644 index 30920119..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/collection/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * OpenPGP key collections. - */ -package org.pgpainless.key.collection; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java deleted file mode 100644 index 81cb725a..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilder.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation; - - -import javax.annotation.Nonnull; -import java.nio.charset.Charset; -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import org.bouncycastle.bcpg.sig.KeyFlags; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openpgp.PGPEncryptedData; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPKeyPair; -import org.bouncycastle.openpgp.PGPKeyRingGenerator; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; -import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; -import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.key.collection.PGPKeyRing; -import org.pgpainless.key.generation.type.ECDH; -import org.pgpainless.key.generation.type.ECDSA; -import org.pgpainless.key.generation.type.KeyType; -import org.pgpainless.key.generation.type.RSA_GENERAL; -import org.pgpainless.key.generation.type.curve.EllipticCurve; -import org.pgpainless.key.generation.type.length.RsaLength; -import org.pgpainless.util.KeyRingSubKeyFix; -import org.pgpainless.util.Passphrase; - -public class KeyRingBuilder implements KeyRingBuilderInterface { - - private final Charset UTF8 = Charset.forName("UTF-8"); - - private List keySpecs = new ArrayList<>(); - private String userId; - private Passphrase passphrase; - - /** - * Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. - * The KeyPair consists of a single RSA master key which is used for signing, encryption and certification. - * - * @param userId user id. - * @param length length in bits. - * @return {@link PGPSecretKeyRing} containing the KeyPair. - * @throws PGPException - * @throws NoSuchAlgorithmException - * @throws NoSuchProviderException - * @throws InvalidAlgorithmParameterException - */ - public PGPKeyRing simpleRsaKeyRing(@Nonnull String userId, @Nonnull RsaLength length) - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { - return withMasterKey( - KeySpec.getBuilder(RSA_GENERAL.withLength(length)) - .withDefaultKeyFlags() - .withDefaultAlgorithms()) - .withPrimaryUserId(userId) - .withoutPassphrase() - .build(); - } - - /** - * Creates a key ring consisting of an ECDSA master key and an ECDH sub-key. - * The ECDSA master key is used for signing messages and certifying the sub key. - * The ECDH sub-key is used for encryption of messages. - * - * @param userId user-id - * @return {@link PGPSecretKeyRing} containing the key pairs. - * @throws PGPException - * @throws NoSuchAlgorithmException - * @throws NoSuchProviderException - * @throws InvalidAlgorithmParameterException - */ - public PGPKeyRing simpleEcKeyRing(@Nonnull String userId) - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { - return withSubKey( - KeySpec.getBuilder(ECDH.fromCurve(EllipticCurve._P256)) - .withKeyFlags(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS) - .withDefaultAlgorithms()) - .withMasterKey( - KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256)) - .withKeyFlags(KeyFlag.AUTHENTICATION, KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA) - .withDefaultAlgorithms()) - .withPrimaryUserId(userId) - .withoutPassphrase() - .build(); - } - - @Override - public KeyRingBuilderInterface withSubKey(@Nonnull KeySpec type) { - KeyRingBuilder.this.keySpecs.add(type); - return this; - } - - @Override - public WithPrimaryUserId withMasterKey(@Nonnull KeySpec spec) { - if ((spec.getSubpackets().getKeyFlags() & KeyFlags.CERTIFY_OTHER) == 0) { - throw new IllegalArgumentException("Certification Key MUST have KeyFlag CERTIFY_OTHER"); - } - KeyRingBuilder.this.keySpecs.add(0, spec); - return new WithPrimaryUserIdImpl(); - } - - class WithPrimaryUserIdImpl implements WithPrimaryUserId { - - @Override - public WithPassphrase withPrimaryUserId(@Nonnull String userId) { - KeyRingBuilder.this.userId = userId; - return new WithPassphraseImpl(); - } - - @Override - public WithPassphrase withPrimaryUserId(@Nonnull byte[] userId) { - return withPrimaryUserId(new String(userId, UTF8)); - } - } - - class WithPassphraseImpl implements WithPassphrase { - - @Override - public Build withPassphrase(@Nonnull Passphrase passphrase) { - KeyRingBuilder.this.passphrase = passphrase; - return new BuildImpl(); - } - - @Override - public Build withoutPassphrase() { - KeyRingBuilder.this.passphrase = null; - return new BuildImpl(); - } - - class BuildImpl implements Build { - - @Override - public PGPKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, - InvalidAlgorithmParameterException { - - // Hash Calculator - PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(BouncyCastleProvider.PROVIDER_NAME) - .build() - .get(HashAlgorithm.SHA1.getAlgorithmId()); - - // Encryptor for encrypting secret keys - PBESecretKeyEncryptor encryptor = passphrase == null ? - null : // unencrypted key pair, otherwise AES-256 encrypted - new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, calculator) - .setProvider(BouncyCastleProvider.PROVIDER_NAME) - .build(passphrase != null ? passphrase.getChars() : null); - - if (passphrase != null) { - passphrase.clear(); - } - - // First key is the Master Key - KeySpec certKeySpec = keySpecs.get(0); - // Remove master key, so that we later only add sub keys. - keySpecs.remove(0); - - // Generate Master Key - PGPKeyPair certKey = generateKeyPair(certKeySpec); - - // Signer for creating self-signature - PGPContentSignerBuilder signer = new JcaPGPContentSignerBuilder( - certKey.getPublicKey().getAlgorithm(), HashAlgorithm.SHA512.getAlgorithmId()) - .setProvider(BouncyCastleProvider.PROVIDER_NAME); - - PGPSignatureSubpacketVector hashedSubPackets = certKeySpec.getSubpackets(); - - // Generator which the user can get the key pair from - PGPKeyRingGenerator ringGenerator = new PGPKeyRingGenerator( - PGPSignature.POSITIVE_CERTIFICATION, certKey, - userId, calculator, - hashedSubPackets, null, signer, encryptor); - - for (KeySpec subKeySpec : keySpecs) { - PGPKeyPair subKey = generateKeyPair(subKeySpec); - if (subKeySpec.isInheritedSubPackets()) { - ringGenerator.addSubKey(subKey); - } else { - ringGenerator.addSubKey(subKey, subKeySpec.getSubpackets(), null); - } - } - - PGPPublicKeyRing publicKeys = ringGenerator.generatePublicKeyRing(); - PGPSecretKeyRing secretKeys = ringGenerator.generateSecretKeyRing(); - - // TODO: Remove once BC 1.61 is released - secretKeys = KeyRingSubKeyFix.repairSubkeyPackets(secretKeys, null, null); - - return new PGPKeyRing(publicKeys, secretKeys); - } - - private PGPKeyPair generateKeyPair(KeySpec spec) - throws NoSuchProviderException, NoSuchAlgorithmException, PGPException, - InvalidAlgorithmParameterException { - KeyType type = spec.getKeyType(); - KeyPairGenerator certKeyGenerator = KeyPairGenerator.getInstance( - type.getName(), BouncyCastleProvider.PROVIDER_NAME); - certKeyGenerator.initialize(type.getAlgorithmSpec()); - - // Create raw Key Pair - KeyPair keyPair = certKeyGenerator.generateKeyPair(); - - // Form PGP key pair - PGPKeyPair pgpKeyPair = new JcaPGPKeyPair(type.getAlgorithm().getAlgorithmId(), - keyPair, new Date()); - - return pgpKeyPair; - } - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java deleted file mode 100644 index 7d214fc8..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeyRingBuilderInterface.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation; - -import javax.annotation.Nonnull; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; - -import org.bouncycastle.openpgp.PGPException; -import org.pgpainless.key.collection.PGPKeyRing; -import org.pgpainless.util.Passphrase; - -public interface KeyRingBuilderInterface { - - KeyRingBuilderInterface withSubKey(@Nonnull KeySpec keySpec); - - WithPrimaryUserId withMasterKey(@Nonnull KeySpec keySpec); - - interface WithPrimaryUserId { - - WithPassphrase withPrimaryUserId(@Nonnull String userId); - - WithPassphrase withPrimaryUserId(@Nonnull byte[] userId); - - } - - interface WithPassphrase { - - Build withPassphrase(@Nonnull Passphrase passphrase); - - Build withoutPassphrase(); - } - - interface Build { - - PGPKeyRing build() throws NoSuchAlgorithmException, PGPException, NoSuchProviderException, - InvalidAlgorithmParameterException; - - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java deleted file mode 100644 index 9fd8c2cc..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpec.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; -import org.pgpainless.key.generation.type.KeyType; - -public class KeySpec { - - private final KeyType keyType; - private final PGPSignatureSubpacketGenerator subpacketGenerator; - private final boolean inheritedSubPackets; - - KeySpec(@Nonnull KeyType type, - @Nullable PGPSignatureSubpacketGenerator subpacketGenerator, - boolean inheritedSubPackets) { - this.keyType = type; - this.subpacketGenerator = subpacketGenerator; - this.inheritedSubPackets = inheritedSubPackets; - } - - @Nonnull - KeyType getKeyType() { - return keyType; - } - - @Nullable - PGPSignatureSubpacketVector getSubpackets() { - return subpacketGenerator != null ? subpacketGenerator.generate() : null; - } - - boolean isInheritedSubPackets() { - return inheritedSubPackets; - } - - public static KeySpecBuilder getBuilder(KeyType type) { - return new KeySpecBuilder(type); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java deleted file mode 100644 index da79fc9b..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilder.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation; - -import javax.annotation.Nonnull; - -import org.bouncycastle.bcpg.sig.Features; -import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.pgpainless.algorithm.AlgorithmSuite; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.Feature; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.key.generation.type.KeyType; - -public class KeySpecBuilder implements KeySpecBuilderInterface { - - private KeyType type; - private PGPSignatureSubpacketGenerator hashedSubPackets = new PGPSignatureSubpacketGenerator(); - - KeySpecBuilder(@Nonnull KeyType type) { - this.type = type; - } - - @Override - public WithDetailedConfiguration withKeyFlags(@Nonnull KeyFlag... flags) { - int val = 0; - for (KeyFlag f : flags) { - val |= f.getFlag(); - } - this.hashedSubPackets.setKeyFlags(false, val); - return new WithDetailedConfigurationImpl(); - } - - @Override - public WithDetailedConfiguration withDefaultKeyFlags() { - return withKeyFlags( - KeyFlag.CERTIFY_OTHER, - KeyFlag.SIGN_DATA, - KeyFlag.ENCRYPT_COMMS, - KeyFlag.ENCRYPT_STORAGE, - KeyFlag.AUTHENTICATION); - } - - @Override - public KeySpec withInheritedSubPackets() { - return new KeySpec(type, null, true); - } - - class WithDetailedConfigurationImpl implements WithDetailedConfiguration { - - @Deprecated - @Override - public WithPreferredSymmetricAlgorithms withDetailedConfiguration() { - return new WithPreferredSymmetricAlgorithmsImpl(); - } - - @Override - public KeySpec withDefaultAlgorithms() { - AlgorithmSuite defaultSuite = AlgorithmSuite.getDefaultAlgorithmSuite(); - hashedSubPackets.setPreferredCompressionAlgorithms(false, defaultSuite.getCompressionAlgorithmIds()); - hashedSubPackets.setPreferredSymmetricAlgorithms(false, defaultSuite.getSymmetricKeyAlgorithmIds()); - hashedSubPackets.setPreferredHashAlgorithms(false, defaultSuite.getHashAlgorithmIds()); - hashedSubPackets.setFeature(false, Features.FEATURE_MODIFICATION_DETECTION); - - return new KeySpec( - KeySpecBuilder.this.type, - KeySpecBuilder.this.hashedSubPackets, - false); - } - } - - class WithPreferredSymmetricAlgorithmsImpl implements WithPreferredSymmetricAlgorithms { - - @Override - public WithPreferredHashAlgorithms withPreferredSymmetricAlgorithms(@Nonnull SymmetricKeyAlgorithm... algorithms) { - int[] ids = new int[algorithms.length]; - for (int i = 0; i < ids.length; i++) { - ids[i] = algorithms[i].getAlgorithmId(); - } - KeySpecBuilder.this.hashedSubPackets.setPreferredSymmetricAlgorithms(false, ids); - return new WithPreferredHashAlgorithmsImpl(); - } - - @Override - public WithPreferredHashAlgorithms withDefaultSymmetricAlgorithms() { - KeySpecBuilder.this.hashedSubPackets.setPreferredSymmetricAlgorithms(false, - AlgorithmSuite.getDefaultAlgorithmSuite().getSymmetricKeyAlgorithmIds()); - return new WithPreferredHashAlgorithmsImpl(); - } - - @Override - public WithFeatures withDefaultAlgorithms() { - hashedSubPackets.setPreferredSymmetricAlgorithms(false, - AlgorithmSuite.getDefaultAlgorithmSuite().getSymmetricKeyAlgorithmIds()); - hashedSubPackets.setPreferredCompressionAlgorithms(false, - AlgorithmSuite.getDefaultAlgorithmSuite().getCompressionAlgorithmIds()); - hashedSubPackets.setPreferredHashAlgorithms(false, - AlgorithmSuite.getDefaultAlgorithmSuite().getHashAlgorithmIds()); - return new WithFeaturesImpl(); - } - } - - class WithPreferredHashAlgorithmsImpl implements WithPreferredHashAlgorithms { - - @Override - public WithPreferredCompressionAlgorithms withPreferredHashAlgorithms(@Nonnull HashAlgorithm... algorithms) { - int[] ids = new int[algorithms.length]; - for (int i = 0; i < ids.length; i++) { - ids[i] = algorithms[i].getAlgorithmId(); - } - KeySpecBuilder.this.hashedSubPackets.setPreferredHashAlgorithms(false, ids); - return new WithPreferredCompressionAlgorithmsImpl(); - } - - @Override - public WithPreferredCompressionAlgorithms withDefaultHashAlgorithms() { - KeySpecBuilder.this.hashedSubPackets.setPreferredHashAlgorithms(false, - AlgorithmSuite.getDefaultAlgorithmSuite().getHashAlgorithmIds()); - return new WithPreferredCompressionAlgorithmsImpl(); - } - } - - class WithPreferredCompressionAlgorithmsImpl implements WithPreferredCompressionAlgorithms { - - @Override - public WithFeatures withPreferredCompressionAlgorithms(@Nonnull CompressionAlgorithm... algorithms) { - int[] ids = new int[algorithms.length]; - for (int i = 0; i < ids.length; i++) { - ids[i] = algorithms[i].getAlgorithmId(); - } - KeySpecBuilder.this.hashedSubPackets.setPreferredCompressionAlgorithms(false, ids); - return new WithFeaturesImpl(); - } - - @Override - public WithFeatures withDefaultCompressionAlgorithms() { - KeySpecBuilder.this.hashedSubPackets.setPreferredCompressionAlgorithms(false, - AlgorithmSuite.getDefaultAlgorithmSuite().getCompressionAlgorithmIds()); - return new WithFeaturesImpl(); - } - } - - class WithFeaturesImpl implements WithFeatures { - - @Override - public WithFeatures withFeature(@Nonnull Feature feature) { - KeySpecBuilder.this.hashedSubPackets.setFeature(false, feature.getFeatureId()); - return this; - } - - @Override - public KeySpec done() { - return new KeySpec( - KeySpecBuilder.this.type, - hashedSubPackets, - false); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilderInterface.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilderInterface.java deleted file mode 100644 index 310abf82..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/KeySpecBuilderInterface.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation; - -import javax.annotation.Nonnull; - -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.Feature; -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; - -public interface KeySpecBuilderInterface { - - WithDetailedConfiguration withKeyFlags(@Nonnull KeyFlag... flags); - - WithDetailedConfiguration withDefaultKeyFlags(); - - KeySpec withInheritedSubPackets(); - - interface WithDetailedConfiguration { - - WithPreferredSymmetricAlgorithms withDetailedConfiguration(); - - KeySpec withDefaultAlgorithms(); - } - - interface WithPreferredSymmetricAlgorithms { - - WithPreferredHashAlgorithms withPreferredSymmetricAlgorithms(@Nonnull SymmetricKeyAlgorithm... algorithms); - - WithPreferredHashAlgorithms withDefaultSymmetricAlgorithms(); - - WithFeatures withDefaultAlgorithms(); - - } - - interface WithPreferredHashAlgorithms { - - WithPreferredCompressionAlgorithms withPreferredHashAlgorithms(@Nonnull HashAlgorithm... algorithms); - - WithPreferredCompressionAlgorithms withDefaultHashAlgorithms(); - - } - - interface WithPreferredCompressionAlgorithms { - - WithFeatures withPreferredCompressionAlgorithms(@Nonnull CompressionAlgorithm... algorithms); - - WithFeatures withDefaultCompressionAlgorithms(); - - } - - interface WithFeatures { - - WithFeatures withFeature(@Nonnull Feature feature); - - KeySpec done(); - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/package-info.java deleted file mode 100644 index b869e1a7..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes related to OpenPGP key generation. - */ -package org.pgpainless.key.generation; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDH.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDH.java deleted file mode 100644 index 73f9b81e..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDH.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - -import javax.annotation.Nonnull; -import java.security.spec.AlgorithmParameterSpec; - -import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.key.generation.type.curve.EllipticCurve; - -public class ECDH implements KeyType { - - private final EllipticCurve curve; - - ECDH(EllipticCurve curve) { - this.curve = curve; - } - - public static ECDH fromCurve(@Nonnull EllipticCurve curve) { - return new ECDH(curve); - } - - @Override - public String getName() { - return "ECDH"; - } - - @Override - public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.ECDH; - } - - @Override - public AlgorithmParameterSpec getAlgorithmSpec() { - return new ECNamedCurveGenParameterSpec(curve.getName()); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDSA.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDSA.java deleted file mode 100644 index 414d9209..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ECDSA.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - - -import javax.annotation.Nonnull; - -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.key.generation.type.curve.EllipticCurve; - -public class ECDSA extends ECDH { - - ECDSA(@Nonnull EllipticCurve curve) { - super(curve); - } - - public static ECDSA fromCurve(@Nonnull EllipticCurve curve) { - return new ECDSA(curve); - } - - @Override - public String getName() { - return "ECDSA"; - } - - @Override - public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.ECDSA; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_ENCRYPT.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_ENCRYPT.java deleted file mode 100644 index bd7ae3aa..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_ENCRYPT.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - -import javax.annotation.Nonnull; - -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.key.generation.type.length.ElGamalLength; - -public class ElGamal_ENCRYPT extends ElGamal_GENERAL { - - ElGamal_ENCRYPT(@Nonnull ElGamalLength length) { - super(length); - } - - @Override - public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.ELGAMAL_ENCRYPT; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_GENERAL.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_GENERAL.java deleted file mode 100644 index 7d7fd717..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/ElGamal_GENERAL.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - -import javax.annotation.Nonnull; -import java.security.spec.AlgorithmParameterSpec; - -import org.bouncycastle.jce.spec.ElGamalParameterSpec; -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.key.generation.type.length.ElGamalLength; - -public class ElGamal_GENERAL implements KeyType { - - private final ElGamalLength length; - - ElGamal_GENERAL(@Nonnull ElGamalLength length) { - this.length = length; - } - - public static ElGamal_GENERAL withLength(@Nonnull ElGamalLength length) { - return new ElGamal_GENERAL(length); - } - - @Override - public String getName() { - return "ElGamal"; - } - - @Override - public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.ELGAMAL_GENERAL; - } - - @Override - public AlgorithmParameterSpec getAlgorithmSpec() { - return new ElGamalParameterSpec(length.getP(), length.getG()); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java deleted file mode 100644 index 72f181da..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/KeyType.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - -import java.security.spec.AlgorithmParameterSpec; - -import org.pgpainless.algorithm.PublicKeyAlgorithm; - -public interface KeyType { - - String getName(); - - PublicKeyAlgorithm getAlgorithm(); - - AlgorithmParameterSpec getAlgorithmSpec(); -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_ENCRYPT.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_ENCRYPT.java deleted file mode 100644 index e1c547a7..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_ENCRYPT.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - -import javax.annotation.Nonnull; - -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.key.generation.type.length.RsaLength; - -public class RSA_ENCRYPT extends RSA_GENERAL { - - RSA_ENCRYPT(@Nonnull RsaLength length) { - super(length); - } - - @Override - public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.RSA_ENCRYPT; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_GENERAL.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_GENERAL.java deleted file mode 100644 index 6a0ee6b8..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_GENERAL.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - -import javax.annotation.Nonnull; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.RSAKeyGenParameterSpec; - -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.key.generation.type.length.RsaLength; - -public class RSA_GENERAL implements KeyType { - - private final RsaLength length; - - RSA_GENERAL(@Nonnull RsaLength length) { - this.length = length; - } - - public static RSA_GENERAL withLength(@Nonnull RsaLength length) { - return new RSA_GENERAL(length); - } - - @Override - public String getName() { - return "RSA"; - } - - @Override - public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.RSA_GENERAL; - } - - @Override - public AlgorithmParameterSpec getAlgorithmSpec() { - return new RSAKeyGenParameterSpec(length.getLength(), RSAKeyGenParameterSpec.F4); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_SIGN.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_SIGN.java deleted file mode 100644 index 525bd297..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/RSA_SIGN.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type; - -import javax.annotation.Nonnull; - -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.key.generation.type.length.RsaLength; - -public class RSA_SIGN extends RSA_GENERAL { - - RSA_SIGN(@Nonnull RsaLength length) { - super(length); - } - - @Override - public PublicKeyAlgorithm getAlgorithm() { - return PublicKeyAlgorithm.RSA_SIGN; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/EllipticCurve.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/EllipticCurve.java deleted file mode 100644 index 74703e2d..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/EllipticCurve.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type.curve; - -import javax.annotation.Nonnull; - -public enum EllipticCurve { - _P256("P-256"), - ; - - private final String name; - - EllipticCurve(@Nonnull String name) { - this.name = name; - } - - public String getName() { - return name; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/package-info.java deleted file mode 100644 index bf7cff10..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/curve/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes related to elliptic curve cryptography. - */ -package org.pgpainless.key.generation.type.curve; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/DiffieHellmanLength.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/DiffieHellmanLength.java deleted file mode 100644 index f1953b30..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/DiffieHellmanLength.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type.length; - -public enum DiffieHellmanLength implements KeyLength { - - _1024(1024), - _2048(2048), - _3072(3072), - ; - - private final int length; - - DiffieHellmanLength(int length) { - this.length = length; - } - - @Override - public int getLength() { - return length; - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/ElGamalLength.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/ElGamalLength.java deleted file mode 100644 index 61a507d1..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/ElGamalLength.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type.length; - -import java.math.BigInteger; - -/** - * The following primes are taken from RFC-3526. - * - * @see - * RFC-3526: More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE) - */ -public enum ElGamalLength implements KeyLength { - - /** - * prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }. - * generator: 2 - */ - _1536(1536, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", "2"), - - /** - * prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }. - * generator: 2 - */ - _2048(2048, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF", "2"), - - /** - * prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }. - * generator: 2 - */ - _3072(3072, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", "2"), - - /** - * prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }. - * generator: 2 - */ - _4096(4096, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199FFFFFFFFFFFFFFFF", "2"), - - /** - * prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }. - * generator: 2 - */ - _6144(6144, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DCC4024FFFFFFFFFFFFFFFF", "2"), - - /** - * prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }. - * generator: 2 - */ - _8192(8192, "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C93402849236C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AACC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E438777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F5683423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD922222E04A4037C0713EB57A81A23F0C73473FC646CEA306B4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A364597E899A0255DC164F31CC50846851DF9AB48195DED7EA1B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F924009438B481C6CD7889A002ED5EE382BC9190DA6FC026E479558E4475677E9AA9E3050E2765694DFC81F56E880B96E7160C980DD98EDD3DFFFFFFFFFFFFFFFFF", "2") - ; - - private final int length; - private final BigInteger p; - private final BigInteger g; - - ElGamalLength(int length, String p, String g) { - this.length = length; - this.p = new BigInteger(p, 16); - this.g = new BigInteger(g, 16); - } - - @Override - public int getLength() { - return length; - } - - public BigInteger getP() { - return p; - } - - public BigInteger getG() { - return g; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/KeyLength.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/KeyLength.java deleted file mode 100644 index f624c9fb..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/KeyLength.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type.length; - -public interface KeyLength { - - int getLength(); -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/RsaLength.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/RsaLength.java deleted file mode 100644 index 823f67ff..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/RsaLength.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.generation.type.length; - -public enum RsaLength implements KeyLength { - @Deprecated - _1024(1024), - @Deprecated - _2048(2048), - _3072(3072), - _4096(4096), - _8192(8192), - ; - - private final int length; - - RsaLength(int length) { - this.length = length; - } - - @Override - public int getLength() { - return length; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/package-info.java deleted file mode 100644 index 4864d5e6..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/length/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes describing the lengths of different public key crypto systems. - */ -package org.pgpainless.key.generation.type.length; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/package-info.java deleted file mode 100644 index c4cff4c9..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/generation/type/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes describing different OpenPGP key types. - */ -package org.pgpainless.key.generation.type; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/package-info.java deleted file mode 100644 index 04c318c0..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes related to OpenPGP keys. - */ -package org.pgpainless.key; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/parsing/KeyRingReader.java b/pgpainless-core/src/main/java/org/pgpainless/key/parsing/KeyRingReader.java deleted file mode 100644 index f9225eb5..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/parsing/KeyRingReader.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.parsing; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; -import org.pgpainless.key.collection.PGPKeyRing; - -public class KeyRingReader { - - public static final Charset UTF8 = Charset.forName("UTF-8"); - - public @Nonnull PGPPublicKeyRing publicKeyRing(@Nonnull InputStream inputStream) throws IOException { - return readPublicKeyRing(inputStream); - } - - public PGPPublicKeyRing publicKeyRing(@Nonnull byte[] bytes) throws IOException { - return publicKeyRing(new ByteArrayInputStream(bytes)); - } - - public PGPPublicKeyRing publicKeyRing(@Nonnull String asciiArmored) throws IOException { - return publicKeyRing(asciiArmored.getBytes(UTF8)); - } - - public PGPPublicKeyRingCollection publicKeyRingCollection(@Nonnull InputStream inputStream) - throws IOException, PGPException { - return readPublicKeyRingCollection(inputStream); - } - - public PGPPublicKeyRingCollection publicKeyRingCollection(@Nonnull byte[] bytes) throws IOException, PGPException { - return publicKeyRingCollection(new ByteArrayInputStream(bytes)); - } - - public PGPPublicKeyRingCollection publicKeyRingCollection(@Nonnull String asciiArmored) throws IOException, PGPException { - return publicKeyRingCollection(asciiArmored.getBytes(UTF8)); - } - - public PGPSecretKeyRing secretKeyRing(@Nonnull InputStream inputStream) throws IOException, PGPException { - return readSecretKeyRing(inputStream); - } - - public PGPSecretKeyRing secretKeyRing(@Nonnull byte[] bytes) throws IOException, PGPException { - return secretKeyRing(new ByteArrayInputStream(bytes)); - } - - public PGPSecretKeyRing secretKeyRing(@Nonnull String asciiArmored) throws IOException, PGPException { - return secretKeyRing(asciiArmored.getBytes(UTF8)); - } - - public PGPSecretKeyRingCollection secretKeyRingCollection(@Nonnull InputStream inputStream) - throws IOException, PGPException { - return readSecretKeyRingCollection(inputStream); - } - - public PGPSecretKeyRingCollection secretKeyRingCollection(@Nonnull byte[] bytes) throws IOException, PGPException { - return secretKeyRingCollection(new ByteArrayInputStream(bytes)); - } - - public PGPSecretKeyRingCollection secretKeyRingCollection(@Nonnull String asciiArmored) throws IOException, PGPException { - return secretKeyRingCollection(asciiArmored.getBytes(UTF8)); - } - - public PGPKeyRing keyRing(@Nullable InputStream publicIn, @Nullable InputStream secretIn) throws IOException, PGPException { - return readKeyRing(publicIn, secretIn); - } - - public PGPKeyRing keyRing(@Nullable byte[] publicBytes, @Nullable byte[] secretBytes) throws IOException, PGPException { - return keyRing( - publicBytes != null ? new ByteArrayInputStream(publicBytes) : null, - secretBytes != null ? new ByteArrayInputStream(secretBytes) : null - ); - } - - public PGPKeyRing keyRing(@Nullable String asciiPublic, @Nullable String asciiSecret) throws IOException, PGPException { - return keyRing( - asciiPublic != null ? asciiPublic.getBytes(UTF8) : null, - asciiSecret != null ? asciiSecret.getBytes(UTF8) : null - ); - } - - /* - STATIC METHODS - */ - - public static PGPPublicKeyRing readPublicKeyRing(@Nonnull InputStream inputStream) throws IOException { - return new PGPPublicKeyRing( - PGPUtil.getDecoderStream(inputStream), - new BcKeyFingerprintCalculator()); - } - - public static PGPPublicKeyRingCollection readPublicKeyRingCollection(@Nonnull InputStream inputStream) - throws IOException, PGPException { - return new PGPPublicKeyRingCollection( - PGPUtil.getDecoderStream(inputStream), - new BcKeyFingerprintCalculator()); - } - - public static PGPSecretKeyRing readSecretKeyRing(@Nonnull InputStream inputStream) throws IOException, PGPException { - return new PGPSecretKeyRing( - PGPUtil.getDecoderStream(inputStream), - new BcKeyFingerprintCalculator()); - } - - public static PGPSecretKeyRingCollection readSecretKeyRingCollection(@Nonnull InputStream inputStream) - throws IOException, PGPException { - return new PGPSecretKeyRingCollection( - PGPUtil.getDecoderStream(inputStream), - new BcKeyFingerprintCalculator()); - } - - public static PGPKeyRing readKeyRing(@Nullable InputStream publicIn, @Nullable InputStream secretIn) throws IOException, PGPException { - - if (publicIn == null && secretIn == null) { - throw new NullPointerException("publicIn and secretIn cannot be BOTH null."); - } - - PGPPublicKeyRing publicKeys = null; - if (publicIn != null) { - publicKeys = readPublicKeyRing(publicIn); - } - PGPSecretKeyRing secretKeys = null; - if (secretIn != null) { - secretKeys = readSecretKeyRing(secretIn); - } - - if (secretKeys == null) { - return new PGPKeyRing(publicKeys); - } - - if (publicKeys == null) { - return new PGPKeyRing(secretKeys); - } - - return new PGPKeyRing(publicKeys, secretKeys); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/parsing/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/parsing/package-info.java deleted file mode 100644 index aa7192a8..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/parsing/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes related to OpenPGP key reading. - */ -package org.pgpainless.key.parsing; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/KeyRingProtectionSettings.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/KeyRingProtectionSettings.java deleted file mode 100644 index c34577cc..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/KeyRingProtectionSettings.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.protection; - -import javax.annotation.Nonnull; - -import org.pgpainless.algorithm.HashAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; - -public class KeyRingProtectionSettings { - - private final SymmetricKeyAlgorithm encryptionAlgorithm; - private final HashAlgorithm hashAlgorithm; - private final int s2kCount; - - public KeyRingProtectionSettings(@Nonnull SymmetricKeyAlgorithm encryptionAlgorithm, @Nonnull HashAlgorithm hashAlgorithm, int s2kCount) { - this.encryptionAlgorithm = encryptionAlgorithm; - this.hashAlgorithm = hashAlgorithm; - if (s2kCount > 1) { - throw new IllegalArgumentException("s2kCount cannot be less than 1."); - } - this.s2kCount = s2kCount; - } - - public @Nonnull SymmetricKeyAlgorithm getEncryptionAlgorithm() { - return encryptionAlgorithm; - } - - public @Nonnull HashAlgorithm getHashAlgorithm() { - return hashAlgorithm; - } - - public int getS2kCount() { - return s2kCount; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/PassphraseMapKeyRingProtector.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/PassphraseMapKeyRingProtector.java deleted file mode 100644 index 481f30c4..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/PassphraseMapKeyRingProtector.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.protection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.HashMap; -import java.util.Map; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; -import org.pgpainless.util.Passphrase; - -/** - * Implementation of the {@link SecretKeyRingProtector} which holds a map of key ids and their passwords. - * In case the needed passphrase is not contained in the map, the {@code missingPassphraseCallback} will be consulted, - * and the passphrase is added to the map. - */ -public class PassphraseMapKeyRingProtector implements SecretKeyRingProtector, SecretKeyPassphraseProvider { - - private final Map cache = new HashMap<>(); - private final SecretKeyRingProtector protector; - private final SecretKeyPassphraseProvider provider; - - public PassphraseMapKeyRingProtector(@Nonnull Map passphrases, - @Nonnull KeyRingProtectionSettings protectionSettings, - @Nullable SecretKeyPassphraseProvider missingPassphraseCallback) { - this.cache.putAll(passphrases); - this.protector = new PasswordBasedSecretKeyRingProtector(protectionSettings, this); - this.provider = missingPassphraseCallback; - } - - /** - * Add a passphrase to the cache. - * - * @param keyId id of the key - * @param passphrase passphrase - */ - public void addPassphrase(@Nonnull Long keyId, @Nullable Passphrase passphrase) { - this.cache.put(keyId, passphrase); - } - - /** - * Remove a passphrase from the cache. - * The passphrase will be cleared and then removed. - * - * @param keyId id of the key - */ - public void forgetPassphrase(@Nonnull Long keyId) { - Passphrase passphrase = cache.get(keyId); - passphrase.clear(); - cache.remove(keyId); - } - - @Override - @Nullable - public Passphrase getPassphraseFor(@Nonnull Long keyId) { - Passphrase passphrase = cache.get(keyId); - if (passphrase == null || !passphrase.isValid()) { - passphrase = provider.getPassphraseFor(keyId); - if (passphrase != null) { - cache.put(keyId, passphrase); - } - } - return passphrase; - } - - @Override - @Nullable - public PBESecretKeyDecryptor getDecryptor(@Nonnull Long keyId) { - return protector.getDecryptor(keyId); - } - - @Override - @Nullable - public PBESecretKeyEncryptor getEncryptor(@Nonnull Long keyId) throws PGPException { - return protector.getEncryptor(keyId); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.java deleted file mode 100644 index 4fbc2145..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/PasswordBasedSecretKeyRingProtector.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.protection; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; -import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; -import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyDecryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPBESecretKeyEncryptorBuilder; -import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; -import org.pgpainless.util.Passphrase; - -/** - * Provides {@link PBESecretKeyDecryptor} and {@link PBESecretKeyEncryptor} objects while getting the passphrases - * from a {@link SecretKeyPassphraseProvider} and using settings from an {@link KeyRingProtectionSettings}. - */ -public class PasswordBasedSecretKeyRingProtector implements SecretKeyRingProtector { - - private static final PGPDigestCalculatorProvider calculatorProvider = new BcPGPDigestCalculatorProvider(); - - protected final KeyRingProtectionSettings protectionSettings; - protected final SecretKeyPassphraseProvider passphraseProvider; - - /** - * Constructor. - * Passphrases for keys are sourced from the {@code passphraseProvider} and decryptors/encryptors are constructed - * following the settings given in {@code settings}. - * - * @param settings S2K settings etc. - * @param passphraseProvider provider which provides passphrases. - */ - public PasswordBasedSecretKeyRingProtector(@Nonnull KeyRingProtectionSettings settings, @Nonnull SecretKeyPassphraseProvider passphraseProvider) { - this.protectionSettings = settings; - this.passphraseProvider = passphraseProvider; - } - - @Override - @Nullable - public PBESecretKeyDecryptor getDecryptor(Long keyId) { - Passphrase passphrase = passphraseProvider.getPassphraseFor(keyId); - return new BcPBESecretKeyDecryptorBuilder(calculatorProvider) - .build(passphrase != null ? passphrase.getChars() : null); - } - - @Override - @Nullable - public PBESecretKeyEncryptor getEncryptor(Long keyId) throws PGPException { - Passphrase passphrase = passphraseProvider.getPassphraseFor(keyId); - return new BcPBESecretKeyEncryptorBuilder( - protectionSettings.getEncryptionAlgorithm().getAlgorithmId(), - calculatorProvider.get(protectionSettings.getHashAlgorithm().getAlgorithmId()), - protectionSettings.getS2kCount()) - .build(passphrase != null ? passphrase.getChars() : null); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyPassphraseProvider.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyPassphraseProvider.java deleted file mode 100644 index 4c878024..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyPassphraseProvider.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.protection; - -import javax.annotation.Nullable; - -import org.pgpainless.util.Passphrase; - -/** - * Interface to allow the user to provide a passphrase for an encrypted OpenPGP secret key. - */ -public interface SecretKeyPassphraseProvider { - - /** - * Return a passphrase for the given key. If no record has been found, return null. - * Note: In case of an unprotected secret key, this method must may not return null, but a {@link Passphrase} with - * a content of null. - * - * @param keyId id of the key - * @return passphrase or null, if no passphrase record has been found. - */ - @Nullable Passphrase getPassphraseFor(Long keyId); -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyRingProtector.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyRingProtector.java deleted file mode 100644 index 83672913..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/SecretKeyRingProtector.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.protection; - -import javax.annotation.Nullable; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; - -public interface SecretKeyRingProtector { - - /** - * Return a decryptor for the key of id {@code keyId}. - * This method returns null if the key is unprotected. - * - * @param keyId id of the key - * @return decryptor for the key - */ - @Nullable PBESecretKeyDecryptor getDecryptor(Long keyId); - - /** - * Return an encryptor for the key of id {@code keyId}. - * This method returns null if the key is unprotected. - * - * @param keyId id of the key - * @return encryptor for the key - * @throws PGPException if the encryptor cannot be created for some reason - */ - @Nullable PBESecretKeyEncryptor getEncryptor(Long keyId) throws PGPException; - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/UnprotectedKeysProtector.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/UnprotectedKeysProtector.java deleted file mode 100644 index fdac82da..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/UnprotectedKeysProtector.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.protection; - -import javax.annotation.Nullable; - -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; - -/** - * Implementation of the {@link SecretKeyRingProtector} which assumes that all handled keys are not password protected. - */ -public class UnprotectedKeysProtector implements SecretKeyRingProtector { - - @Override - @Nullable - public PBESecretKeyDecryptor getDecryptor(Long keyId) { - return null; - } - - @Override - @Nullable - public PBESecretKeyEncryptor getEncryptor(Long keyId) { - return null; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/protection/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/protection/package-info.java deleted file mode 100644 index f177f3ae..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/protection/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes related to OpenPGP secret key password protection. - */ -package org.pgpainless.key.protection; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/KeySelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/KeySelectionStrategy.java deleted file mode 100644 index d71fd049..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/KeySelectionStrategy.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key; - -import javax.annotation.Nonnull; -import java.util.Set; - -import org.pgpainless.util.MultiMap; - - -/** - * Interface that describes a selection strategy for OpenPGP keys. - * @param Type of the Key - * @param Type of the PGPKeyRing - * @param Type that describes the owner of this key - */ -public interface KeySelectionStrategy { - - boolean accept(O identifier, K key); - - Set selectKeysFromKeyRing(O identifier, @Nonnull R ring); - - MultiMap selectKeysFromKeyRings(MultiMap rings); - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/PublicKeySelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/PublicKeySelectionStrategy.java deleted file mode 100644 index 76af04f3..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/PublicKeySelectionStrategy.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key; - -import javax.annotation.Nonnull; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.pgpainless.util.MultiMap; - -/** - * Key Selection Strategy which accepts {@link PGPPublicKey}s that are accepted by the abstract method - * {@link #accept(Object, Object)}. - * - * @param Type that describes the owner of the key. - */ -public abstract class PublicKeySelectionStrategy implements KeySelectionStrategy { - - @Override - public Set selectKeysFromKeyRing(O identifier, @Nonnull PGPPublicKeyRing ring) { - Set keys = new HashSet<>(); - for (Iterator i = ring.getPublicKeys(); i.hasNext(); ) { - PGPPublicKey key = i.next(); - if (accept(identifier, key)) keys.add(key); - } - return keys; - } - - @Override - public MultiMap selectKeysFromKeyRings(@Nonnull MultiMap keyRings) { - MultiMap keys = new MultiMap<>(); - for (O identifier : keyRings.keySet()) { - for (PGPPublicKeyRing ring : keyRings.get(identifier)) { - keys.put(identifier, selectKeysFromKeyRing(identifier, ring)); - } - } - return keys; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/SecretKeySelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/SecretKeySelectionStrategy.java deleted file mode 100644 index 5f569862..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/SecretKeySelectionStrategy.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key; - -import javax.annotation.Nonnull; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.pgpainless.util.MultiMap; - -/** - * Key Selection Strategy which accepts {@link PGPSecretKey}s that are accepted by the abstract method - * {@link #accept(Object, Object)}. - * - * @param Type that describes the owner of the key. - */ -public abstract class SecretKeySelectionStrategy implements KeySelectionStrategy { - - @Override - public Set selectKeysFromKeyRing(O identifier, @Nonnull PGPSecretKeyRing ring) { - Set keys = new HashSet<>(); - for (Iterator i = ring.getSecretKeys(); i.hasNext(); ) { - PGPSecretKey key = i.next(); - if (accept(identifier, key)) keys.add(key); - } - return keys; - } - - @Override - public MultiMap selectKeysFromKeyRings(@Nonnull MultiMap keyRings) { - MultiMap keys = new MultiMap<>(); - for (O identifier : keyRings.keySet()) { - for (PGPSecretKeyRing ring : keyRings.get(identifier)) { - keys.put(identifier, selectKeysFromKeyRing(identifier, ring)); - } - } - return keys; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/And.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/And.java deleted file mode 100644 index 662deaa3..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/And.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key.impl; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; -import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; - -public class And { - - public static class PubKeySelectionStrategy extends PublicKeySelectionStrategy { - - private final PublicKeySelectionStrategy left; - private final PublicKeySelectionStrategy right; - - public PubKeySelectionStrategy(@Nonnull PublicKeySelectionStrategy left, - @Nonnull PublicKeySelectionStrategy right) { - this.left = left; - this.right = right; - } - - @Override - public boolean accept(O identifier, PGPPublicKey key) { - return left.accept(identifier, key) && right.accept(identifier, key); - } - } - - public static class SecKeySelectionStrategy extends SecretKeySelectionStrategy { - - private final SecretKeySelectionStrategy left; - private final SecretKeySelectionStrategy right; - - public SecKeySelectionStrategy(@Nonnull SecretKeySelectionStrategy left, - @Nonnull SecretKeySelectionStrategy right) { - this.left = left; - this.right = right; - } - - @Override - public boolean accept(O identifier, PGPSecretKey key) { - return left.accept(identifier, key) && right.accept(identifier, key); - } - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java deleted file mode 100644 index 876edd20..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/EncryptionKeySelectionStrategy.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key.impl; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; - -/** - * Key Selection Strategy that only accepts {@link PGPPublicKey}s which are capable of encryption. - * - * @param Type that describes the owner of the key (not used for decision). - */ -public class EncryptionKeySelectionStrategy extends PublicKeySelectionStrategy { - - @Override - public boolean accept(O identifier, @Nonnull PGPPublicKey key) { - return key.isEncryptionKey(); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/NoRevocation.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/NoRevocation.java deleted file mode 100644 index c7e882ca..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/NoRevocation.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key.impl; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; -import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; - -/** - * Key Selection Strategies that do accept only keys, which have no revocation. - */ -public class NoRevocation { - - /** - * Key Selection Strategy which only accepts {@link PGPPublicKey}s which have no revocation. - * - * @param Type that describes the owner of this key (not used for this decision). - */ - public static class PubKeySelectionStrategy extends PublicKeySelectionStrategy { - - @Override - public boolean accept(O identifier, @Nonnull PGPPublicKey key) { - return !key.hasRevocation(); - } - } - - /** - * Key Selection Strategy which only accepts {@link PGPSecretKey}s which have no revocation. - * - * @param Type that describes the owner of this key (not used for this decision). - */ - public static class SecKeySelectionStrategy extends SecretKeySelectionStrategy { - - @Override - public boolean accept(O identifier, @Nonnull PGPSecretKey key) { - return !key.getPublicKey().hasRevocation(); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/Or.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/Or.java deleted file mode 100644 index 55e263e3..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/Or.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key.impl; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; -import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; - -public class Or { - - public static class PubKeySelectionStrategy extends PublicKeySelectionStrategy { - - private final PublicKeySelectionStrategy left; - private final PublicKeySelectionStrategy right; - - public PubKeySelectionStrategy(@Nonnull PublicKeySelectionStrategy left, - @Nonnull PublicKeySelectionStrategy right) { - this.left = left; - this.right = right; - } - - @Override - public boolean accept(O identifier, PGPPublicKey key) { - return left.accept(identifier, key) || right.accept(identifier, key); - } - } - - public static class SecKeySelectionStrategy extends SecretKeySelectionStrategy { - - private final SecretKeySelectionStrategy left; - private final SecretKeySelectionStrategy right; - - public SecKeySelectionStrategy(@Nonnull SecretKeySelectionStrategy left, - @Nonnull SecretKeySelectionStrategy right) { - this.left = left; - this.right = right; - } - - @Override - public boolean accept(O identifier, PGPSecretKey key) { - return left.accept(identifier, key) || right.accept(identifier, key); - } - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignatureKeySelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignatureKeySelectionStrategy.java deleted file mode 100644 index 51275e4f..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignatureKeySelectionStrategy.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key.impl; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPSecretKey; -import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; - -/** - * Key Selection Strategy that only accepts {@link PGPSecretKey}s which are capable of signing. - * - * @param Type that describes the owner of the key (not used for this decision). - */ -public class SignatureKeySelectionStrategy extends SecretKeySelectionStrategy { - - @Override - public boolean accept(O identifier, @Nonnull PGPSecretKey key) { - return key.isSigningKey(); - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignedByMasterKey.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignedByMasterKey.java deleted file mode 100644 index e3e6a134..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/SignedByMasterKey.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.key.impl; - -import javax.annotation.Nonnull; -import java.util.Arrays; -import java.util.Iterator; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; - -public class SignedByMasterKey { - - private static final Logger LOGGER = Logger.getLogger(SignedByMasterKey.class.getName()); - - public static class PubkeySelectionStrategy extends PublicKeySelectionStrategy { - - @Override - public boolean accept(PGPPublicKey masterKey, @Nonnull PGPPublicKey key) { - // Same key -> accept - if (Arrays.equals(masterKey.getFingerprint(), key.getFingerprint())) { - return true; - } - - Iterator signatures = key.getSignaturesForKeyID(masterKey.getKeyID()); - while (signatures.hasNext()) { - PGPSignature signature = signatures.next(); - if (signature.getSignatureType() == PGPSignature.SUBKEY_BINDING) { - try { - signature.init(new BcPGPContentVerifierBuilderProvider(), masterKey); - return signature.verifyCertification(masterKey, key); - } catch (PGPException e) { - LOGGER.log(Level.WARNING, "Could not verify subkey signature of key " + - Long.toHexString(masterKey.getKeyID()) + " on key " + Long.toHexString(key.getKeyID())); - - return false; - } - } - } - return false; - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/package-info.java deleted file mode 100644 index b1f317ac..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/impl/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Implementations of Key Selection Strategies. - */ -package org.pgpainless.key.selection.key.impl; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/package-info.java deleted file mode 100644 index 36cc3712..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/key/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Different Key Selection Strategies. - */ -package org.pgpainless.key.selection.key; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/KeyRingSelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/KeyRingSelectionStrategy.java deleted file mode 100644 index 7285b1d4..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/KeyRingSelectionStrategy.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring; - -import java.util.Set; - -import org.pgpainless.util.MultiMap; - -public interface KeyRingSelectionStrategy { - - boolean accept(O identifier, R keyRing); - - Set selectKeyRingsFromCollection(O identifier, C keyRingCollection); - - MultiMap selectKeyRingsFromCollections(MultiMap keyRingCollections); -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/PublicKeyRingSelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/PublicKeyRingSelectionStrategy.java deleted file mode 100644 index 75ac536f..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/PublicKeyRingSelectionStrategy.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring; - -import javax.annotation.Nonnull; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.pgpainless.util.MultiMap; - -public abstract class PublicKeyRingSelectionStrategy implements KeyRingSelectionStrategy { - - @Override - public Set selectKeyRingsFromCollection(@Nonnull O identifier, @Nonnull PGPPublicKeyRingCollection keyRingCollection) { - Set accepted = new HashSet<>(); - for (Iterator i = keyRingCollection.getKeyRings(); i.hasNext(); ) { - PGPPublicKeyRing ring = i.next(); - if (accept(identifier, ring)) accepted.add(ring); - } - return accepted; - } - - @Override - public MultiMap selectKeyRingsFromCollections(@Nonnull MultiMap keyRingCollections) { - MultiMap keyRings = new MultiMap<>(); - for (O identifier : keyRingCollections.keySet()) { - for (PGPPublicKeyRingCollection collection : keyRingCollections.get(identifier)) { - keyRings.put(identifier, selectKeyRingsFromCollection(identifier, collection)); - } - } - return keyRings; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/SecretKeyRingSelectionStrategy.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/SecretKeyRingSelectionStrategy.java deleted file mode 100644 index 51475652..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/SecretKeyRingSelectionStrategy.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring; - -import javax.annotation.Nonnull; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.pgpainless.util.MultiMap; - -public abstract class SecretKeyRingSelectionStrategy implements KeyRingSelectionStrategy { - @Override - public Set selectKeyRingsFromCollection(O identifier, @Nonnull PGPSecretKeyRingCollection keyRingCollection) { - Set accepted = new HashSet<>(); - for (Iterator i = keyRingCollection.getKeyRings(); i.hasNext(); ) { - PGPSecretKeyRing ring = i.next(); - if (accept(identifier, ring)) accepted.add(ring); - } - return accepted; - } - - @Override - public MultiMap selectKeyRingsFromCollections(@Nonnull MultiMap keyRingCollections) { - MultiMap keyRings = new MultiMap<>(); - for (O identifier : keyRingCollections.keySet()) { - for (PGPSecretKeyRingCollection collection : keyRingCollections.get(identifier)) { - keyRings.put(identifier, selectKeyRingsFromCollection(identifier, collection)); - } - } - return keyRings; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Email.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Email.java deleted file mode 100644 index 2a33df1b..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Email.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring.impl; - -import javax.annotation.Nonnull; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; - -public class Email { - - public static class PubRingSelectionStrategy extends PartialUserId.PubRingSelectionStrategy { - - @Override - public boolean accept(@Nonnull String email, @Nonnull PGPPublicKey key) { - // Ensure, that email address is encapsulated in "<",">" - if (!email.matches("^<.+>$")) { - email = "<" + email + ">"; - } - return super.accept(email, key); - } - } - - public static class SecRingSelectionStrategy extends PartialUserId.SecRingSelectionStrategy { - - @Override - public boolean accept(String email, PGPSecretKey key) { - // Ensure, that email address is encapsulated in "<",">" - if (!email.matches("^<.+>$")) { - email = "<" + email + ">"; - } - return super.accept(email, key); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/ExactUserId.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/ExactUserId.java deleted file mode 100644 index f0846a30..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/ExactUserId.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring.impl; - -import java.util.Iterator; - -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy; -import org.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy; - -public class ExactUserId { - - public static class PubRingSelectionStrategy extends PublicKeyRingSelectionStrategy { - - @Override - public boolean accept(String identifier, PGPPublicKeyRing keyRing) { - Iterator userIds = keyRing.getPublicKey().getUserIDs(); - while (userIds.hasNext()) { - if (userIds.next().equals(identifier)) return true; - } - return false; - } - } - - public static class SecRingSelectionStrategy extends SecretKeyRingSelectionStrategy { - - @Override - public boolean accept(String identifier, PGPSecretKeyRing keyRing) { - Iterator userIds = keyRing.getPublicKey().getUserIDs(); - while (userIds.hasNext()) { - if (userIds.next().equals(identifier)) return true; - } - return false; - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/PartialUserId.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/PartialUserId.java deleted file mode 100644 index 9e67a8dd..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/PartialUserId.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring.impl; - -import javax.annotation.Nonnull; -import java.util.Iterator; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; -import org.pgpainless.key.selection.key.SecretKeySelectionStrategy; - -public class PartialUserId { - - public static class PubRingSelectionStrategy extends PublicKeySelectionStrategy { - - @Override - public boolean accept(String identifier, @Nonnull PGPPublicKey key) { - for (Iterator userIds = key.getUserIDs(); userIds.hasNext(); ) { - String userId = userIds.next(); - if (userId.contains(identifier)) { - return true; - } - } - return false; - } - } - - public static class SecRingSelectionStrategy extends SecretKeySelectionStrategy { - - @Override - public boolean accept(String identifier, @Nonnull PGPSecretKey key) { - for (Iterator userIds = key.getUserIDs(); userIds.hasNext(); ) { - String userId = (String) userIds.next(); - if (userId.contains(identifier)) { - return true; - } - } - return false; - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Whitelist.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Whitelist.java deleted file mode 100644 index 6a894122..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Whitelist.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring.impl; - -import java.util.Map; -import java.util.Set; - -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy; -import org.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy; -import org.pgpainless.util.MultiMap; - -public class Whitelist { - - public static class PubRingSelectionStrategy extends PublicKeyRingSelectionStrategy { - - private final MultiMap whitelist; - - public PubRingSelectionStrategy(MultiMap whitelist) { - this.whitelist = whitelist; - } - - public PubRingSelectionStrategy(Map> whitelist) { - this.whitelist = new MultiMap<>(whitelist); - } - - @Override - public boolean accept(O identifier, PGPPublicKeyRing keyRing) { - Set whitelistedKeyIds = whitelist.get(identifier); - - if (whitelistedKeyIds == null) { - return false; - } - - return whitelistedKeyIds.contains(keyRing.getPublicKey().getKeyID()); - } - } - - public static class SecRingSelectionStrategy extends SecretKeyRingSelectionStrategy { - - private final MultiMap whitelist; - - public SecRingSelectionStrategy(MultiMap whitelist) { - this.whitelist = whitelist; - } - - public SecRingSelectionStrategy(Map> whitelist) { - this.whitelist = new MultiMap<>(whitelist); - } - - @Override - public boolean accept(O identifier, PGPSecretKeyRing keyRing) { - Set whitelistedKeyIds = whitelist.get(identifier); - - if (whitelistedKeyIds == null) { - return false; - } - - return whitelistedKeyIds.contains(keyRing.getPublicKey().getKeyID()); - } - - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Wildcard.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Wildcard.java deleted file mode 100644 index 2528321a..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/Wildcard.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring.impl; - -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.pgpainless.key.selection.keyring.PublicKeyRingSelectionStrategy; -import org.pgpainless.key.selection.keyring.SecretKeyRingSelectionStrategy; - -public class Wildcard { - - public class PubRingSelectionStrategy extends PublicKeyRingSelectionStrategy { - - @Override - public boolean accept(O identifier, PGPPublicKeyRing keyRing) { - return true; - } - } - - public class SecRingSelectionStrategy extends SecretKeyRingSelectionStrategy { - - @Override - public boolean accept(O identifier, PGPSecretKeyRing keyRing) { - return true; - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/XMPP.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/XMPP.java deleted file mode 100644 index 34397c4c..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/XMPP.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.key.selection.keyring.impl; - -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; - -public class XMPP { - - public static class PubRingSelectionStrategy extends ExactUserId.PubRingSelectionStrategy { - - @Override - public boolean accept(String jid, PGPPublicKeyRing keyRing) { - return super.accept("xmpp:" + jid, keyRing); - } - } - - public static class SecRingSelectionStrategy extends ExactUserId.SecRingSelectionStrategy { - - @Override - public boolean accept(String jid, PGPSecretKeyRing keyRing) { - return super.accept("xmpp:" + jid, keyRing); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/package-info.java deleted file mode 100644 index 2b5b6ab0..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/impl/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Implementations of Key Ring Selection Strategies. - */ -package org.pgpainless.key.selection.keyring.impl; diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/package-info.java deleted file mode 100644 index b4c602fb..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/key/selection/keyring/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Different Key Ring Selection Strategies. - */ -package org.pgpainless.key.selection.keyring; diff --git a/pgpainless-core/src/main/java/org/pgpainless/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/package-info.java deleted file mode 100644 index fdc0fe96..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/package-info.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * PGPainless - Use OpenPGP Painlessly! - * - * @see org.pgpainless.core.org - */ -package org.pgpainless; diff --git a/pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/SymmetricEncryptorDecryptor.java b/pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/SymmetricEncryptorDecryptor.java deleted file mode 100644 index 87ec4404..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/SymmetricEncryptorDecryptor.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.symmetric_encryption; - -import javax.annotation.Nonnull; -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.SecureRandom; -import java.util.Date; - -import org.bouncycastle.openpgp.PGPCompressedData; -import org.bouncycastle.openpgp.PGPCompressedDataGenerator; -import org.bouncycastle.openpgp.PGPEncryptedDataGenerator; -import org.bouncycastle.openpgp.PGPEncryptedDataList; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPLiteralData; -import org.bouncycastle.openpgp.PGPLiteralDataGenerator; -import org.bouncycastle.openpgp.PGPPBEEncryptedData; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.bc.BcPGPObjectFactory; -import org.bouncycastle.openpgp.operator.bc.BcPBEDataDecryptorFactory; -import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; -import org.bouncycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; -import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; -import org.bouncycastle.util.io.Streams; -import org.pgpainless.algorithm.CompressionAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.util.Passphrase; - -/** - * Stolen from - * Bouncycastle examples. - */ -public class SymmetricEncryptorDecryptor { - - /** - * Encrypt some {@code data} symmetrically using an {@code encryptionAlgorithm} and a given {@code password}. - * The input data will be compressed using the given {@code compressionAlgorithm} and packed in a modification - * detection package, which is then encrypted. - * - * @param data bytes that will be encrypted - * @param password password that will be used to encrypt the data - * @param encryptionAlgorithm symmetric algorithm that will be used to encrypt the data - * @param compressionAlgorithm compression algorithm that will be used to compress the data - * @return encrypted data - * @throws IOException IO is dangerous - * @throws PGPException OpenPGP is brittle - */ - public static byte[] symmetricallyEncrypt(@Nonnull byte[] data, - @Nonnull Passphrase password, - @Nonnull SymmetricKeyAlgorithm encryptionAlgorithm, - @Nonnull CompressionAlgorithm compressionAlgorithm) - throws IOException, PGPException { - - byte[] compressedData = compress(data, compressionAlgorithm.getAlgorithmId()); - - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - PGPEncryptedDataGenerator encGen = new PGPEncryptedDataGenerator( - new JcePGPDataEncryptorBuilder(encryptionAlgorithm.getAlgorithmId()) - .setWithIntegrityPacket(true) - .setSecureRandom(new SecureRandom()) - .setProvider("BC")); - - encGen.addMethod(new JcePBEKeyEncryptionMethodGenerator(password.getChars()).setProvider("BC")); - - OutputStream encOut = encGen.open(bOut, compressedData.length); - - encOut.write(compressedData); - encOut.close(); - - return bOut.toByteArray(); - } - - /** - * Decrypt and decompress some symmetrically encrypted data using a password. - * Note, that decryption will fail if the given data is not integrity protected with a modification detection - * package. - * - * @param data encrypted data - * @param password password to decrypt the data - * @return decrypted data - * @throws IOException IO is dangerous - * @throws PGPException OpenPGP is brittle - */ - public static byte[] symmetricallyDecrypt(@Nonnull byte[] data, @Nonnull Passphrase password) - throws IOException, PGPException { - InputStream in = new BufferedInputStream(new ByteArrayInputStream(data)); - in = PGPUtil.getDecoderStream(in); - - BcPGPObjectFactory pgpF = new BcPGPObjectFactory(in); - PGPEncryptedDataList enc; - Object o = pgpF.nextObject(); - - if (o instanceof PGPEncryptedDataList) { - enc = (PGPEncryptedDataList) o; - } else { - enc = (PGPEncryptedDataList) pgpF.nextObject(); - } - - PGPPBEEncryptedData pbe = (PGPPBEEncryptedData) enc.get(0); - - InputStream clear = pbe.getDataStream(new BcPBEDataDecryptorFactory( - password.getChars(), new BcPGPDigestCalculatorProvider())); - - - BcPGPObjectFactory pgpFact = new BcPGPObjectFactory(clear); - - o = pgpFact.nextObject(); - if (o instanceof PGPCompressedData) { - PGPCompressedData cData = (PGPCompressedData) o; - pgpFact = new BcPGPObjectFactory(cData.getDataStream()); - o = pgpFact.nextObject(); - } - - PGPLiteralData ld = (PGPLiteralData) o; - InputStream unc = ld.getInputStream(); - - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - - Streams.pipeAll(unc, outputStream); - - outputStream.close(); - - if (pbe.isIntegrityProtected()) { - if (!pbe.verify()) { - throw new PGPException("Integrity check failed."); - } - } else { - throw new PGPException("Symmetrically encrypted data is not integrity protected."); - } - - return outputStream.toByteArray(); - } - - /** - * Wrap some data in an OpenPGP compressed data package. - * - * @param clearData uncompressed data - * @param algorithm compression algorithm - * @return compressed data - * @throws IOException IO is dangerous - */ - private static byte[] compress(@Nonnull byte[] clearData, int algorithm) throws IOException { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - PGPCompressedDataGenerator comData = new PGPCompressedDataGenerator(algorithm); - OutputStream cos = comData.open(bOut); - - PGPLiteralDataGenerator lData = new PGPLiteralDataGenerator(); - - OutputStream pOut = lData.open(cos, - PGPLiteralData.BINARY, - PGPLiteralDataGenerator.CONSOLE, - clearData.length, - new Date() - ); - - pOut.write(clearData); - pOut.close(); - - comData.close(); - - return bOut.toByteArray(); - } - -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/package-info.java deleted file mode 100644 index a250b706..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/symmetric_encryption/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Classes related to OpenPGP symmetric encryption. - */ -package org.pgpainless.symmetric_encryption; diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/BCUtil.java b/pgpainless-core/src/main/java/org/pgpainless/util/BCUtil.java deleted file mode 100644 index a022bfcc..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/util/BCUtil.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.util; - -import javax.annotation.Nonnull; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPKeyRing; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; -import org.bouncycastle.util.io.Streams; -import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.key.selection.key.PublicKeySelectionStrategy; -import org.pgpainless.key.selection.key.impl.And; -import org.pgpainless.key.selection.key.impl.NoRevocation; -import org.pgpainless.key.selection.key.impl.SignedByMasterKey; - -public class BCUtil { - - private static final Logger LOGGER = Logger.getLogger(BCUtil.class.getName()); - - /* - PGPXxxKeyRing -> PGPXxxKeyRingCollection - */ - public static PGPPublicKeyRingCollection keyRingsToKeyRingCollection(@Nonnull PGPPublicKeyRing... rings) - throws IOException, PGPException { - return new PGPPublicKeyRingCollection(Arrays.asList(rings)); - } - - public static PGPSecretKeyRingCollection keyRingsToKeyRingCollection(@Nonnull PGPSecretKeyRing... rings) - throws IOException, PGPException { - return new PGPSecretKeyRingCollection(Arrays.asList(rings)); - } - - public static PGPPublicKeyRing publicKeyRingFromSecretKeyRing(@Nonnull PGPSecretKeyRing secretKeys) - throws PGPException, IOException { - PGPSecretKeyRing fixedSecretKeys = KeyRingSubKeyFix.repairSubkeyPackets(secretKeys, null, null); - - ByteArrayOutputStream buffer = new ByteArrayOutputStream(512); - for (PGPSecretKey secretKey : fixedSecretKeys) { - PGPPublicKey publicKey = secretKey.getPublicKey(); - if (publicKey != null) { - publicKey.encode(buffer, false); - } - } - - return new PGPPublicKeyRing(buffer.toByteArray(), new BcKeyFingerprintCalculator()); - } - - /* - PGPXxxKeyRingCollection -> PGPXxxKeyRing - */ - - public static PGPSecretKeyRing getKeyRingFromCollection(@Nonnull PGPSecretKeyRingCollection collection, - @Nonnull Long id) - throws PGPException { - PGPSecretKeyRing uncleanedRing = collection.getSecretKeyRing(id); - - // Determine ids of signed keys - Set signedKeyIds = new HashSet<>(); - signedKeyIds.add(id); // Add the signing key itself - Iterator signedPubKeys = uncleanedRing.getKeysWithSignaturesBy(id); - while (signedPubKeys.hasNext()) { - signedKeyIds.add(signedPubKeys.next().getKeyID()); - } - - PGPSecretKeyRing cleanedRing = uncleanedRing; - Iterator secretKeys = uncleanedRing.getSecretKeys(); - while (secretKeys.hasNext()) { - PGPSecretKey secretKey = secretKeys.next(); - if (!signedKeyIds.contains(secretKey.getKeyID())) { - cleanedRing = PGPSecretKeyRing.removeSecretKey(cleanedRing, secretKey); - } - } - return cleanedRing; - } - - public static PGPPublicKeyRing getKeyRingFromCollection(@Nonnull PGPPublicKeyRingCollection collection, - @Nonnull Long id) - throws PGPException { - PGPPublicKey key = collection.getPublicKey(id); - return removeUnassociatedKeysFromKeyRing(collection.getPublicKeyRing(id), key); - } - - public static InputStream getPgpDecoderInputStream(@Nonnull byte[] bytes) - throws IOException { - return getPgpDecoderInputStream(new ByteArrayInputStream(bytes)); - } - - public static InputStream getPgpDecoderInputStream(@Nonnull InputStream inputStream) - throws IOException { - return PGPUtil.getDecoderStream(inputStream); - } - - public static byte[] getDecodedBytes(@Nonnull byte[] bytes) - throws IOException { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - Streams.pipeAll(getPgpDecoderInputStream(bytes), buffer); - return buffer.toByteArray(); - } - - public static byte[] getDecodedBytes(@Nonnull InputStream inputStream) - throws IOException { - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - Streams.pipeAll(inputStream, buffer); - return getDecodedBytes(buffer.toByteArray()); - } - - /** - * Remove all keys from the key ring, are either not having a subkey signature from the master key - * (identified by {@code masterKeyId}), or are revoked ("normal" key revocation, as well as subkey revocation). - * - * @param ring key ring - * @param masterKey master key - * @return "cleaned" key ring - */ - public static PGPPublicKeyRing removeUnassociatedKeysFromKeyRing(@Nonnull PGPPublicKeyRing ring, - @Nonnull PGPPublicKey masterKey) { - if (!masterKey.isMasterKey()) { - throw new IllegalArgumentException("Given key is not a master key."); - } - // Only select keys which are signed by the master key and not revoked. - PublicKeySelectionStrategy selector = new And.PubKeySelectionStrategy<>( - new SignedByMasterKey.PubkeySelectionStrategy(), - new NoRevocation.PubKeySelectionStrategy<>()); - - PGPPublicKeyRing cleaned = ring; - - Iterator publicKeys = ring.getPublicKeys(); - while (publicKeys.hasNext()) { - PGPPublicKey publicKey = publicKeys.next(); - if (!selector.accept(masterKey, publicKey)) { - cleaned = PGPPublicKeyRing.removePublicKey(cleaned, publicKey); - } - } - - return cleaned; - } - - /** - * Remove all keys from the key ring, are either not having a subkey signature from the master key - * (identified by {@code masterKeyId}), or are revoked ("normal" key revocation, as well as subkey revocation). - * - * @param ring key ring - * @param masterKey master key - * @return "cleaned" key ring - */ - public static PGPSecretKeyRing removeUnassociatedKeysFromKeyRing(@Nonnull PGPSecretKeyRing ring, - @Nonnull PGPPublicKey masterKey) { - if (!masterKey.isMasterKey()) { - throw new IllegalArgumentException("Given key is not a master key."); - } - // Only select keys which are signed by the master key and not revoked. - PublicKeySelectionStrategy selector = new And.PubKeySelectionStrategy<>( - new SignedByMasterKey.PubkeySelectionStrategy(), - new NoRevocation.PubKeySelectionStrategy<>()); - - PGPSecretKeyRing cleaned = ring; - - Iterator secretKeys = ring.getSecretKeys(); - while (secretKeys.hasNext()) { - PGPSecretKey secretKey = secretKeys.next(); - if (!selector.accept(masterKey, secretKey.getPublicKey())) { - cleaned = PGPSecretKeyRing.removeSecretKey(cleaned, secretKey); - } - } - - return cleaned; - } - - /** - * Return the {@link PGPPublicKey} which is the master key of the key ring. - * - * @param ring key ring - * @return master key - */ - public static PGPPublicKey getMasterKeyFrom(@Nonnull PGPPublicKeyRing ring) { - Iterator it = ring.getPublicKeys(); - while (it.hasNext()) { - PGPPublicKey k = it.next(); - if (k.isMasterKey()) { - // There can only be one master key, so we can immediately return - return k; - } - } - return null; - } - - public static PGPPublicKey getMasterKeyFrom(@Nonnull PGPKeyRing ring) { - Iterator it = ring.getPublicKeys(); - while (it.hasNext()) { - PGPPublicKey k = (PGPPublicKey) it.next(); - if (k.isMasterKey()) { - // There can only be one master key, so we can immediately return - return k; - } - } - return null; - } - - public static Set signingKeyIds(@Nonnull PGPSecretKeyRing ring) { - Set ids = new HashSet<>(); - Iterator it = ring.getPublicKeys(); - while (it.hasNext()) { - PGPPublicKey k = it.next(); - - boolean signingKey = false; - - Iterator sit = k.getSignatures(); - while (sit.hasNext()) { - Object n = sit.next(); - if (!(n instanceof PGPSignature)) { - continue; - } - - PGPSignature s = (PGPSignature) n; - if (!s.hasSubpackets()) { - continue; - } - - try { - s.verifyCertification(ring.getPublicKey(s.getKeyID())); - } catch (PGPException e) { - LOGGER.log(Level.WARNING, "Could not verify signature on " + Long.toHexString(k.getKeyID()) + " made by " + Long.toHexString(s.getKeyID())); - continue; - } - - PGPSignatureSubpacketVector hashed = s.getHashedSubPackets(); - if (KeyFlag.fromInteger(hashed.getKeyFlags()).contains(KeyFlag.SIGN_DATA)) { - signingKey = true; - break; - } - } - - if (signingKey) { - ids.add(k.getKeyID()); - } - } - return ids; - } - - public static boolean keyRingContainsKeyWithId(@Nonnull PGPPublicKeyRing ring, - long keyId) { - return ring.getPublicKey(keyId) != null; - } - - public static boolean keyRingContainsKeyWithId(@Nonnull PGPSecretKeyRing ring, - long keyId) { - return ring.getSecretKey(keyId) != null; - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/KeyRingSubKeyFix.java b/pgpainless-core/src/main/java/org/pgpainless/util/KeyRingSubKeyFix.java deleted file mode 100644 index 6927ec29..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/util/KeyRingSubKeyFix.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.util; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyPacket; -import org.bouncycastle.bcpg.PublicSubkeyPacket; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPrivateKey; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor; -import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider; - -public class KeyRingSubKeyFix { - - private static final Logger LOGGER = Logger.getLogger(KeyRingSubKeyFix.class.getName()); - - /** - * This method makes sure, that sub keys do consist of sub key packets. - * Bouncycastle versions up to and including 1.60 created {@link PGPSecretKeyRing}s which sub keys consisted of - * normal public key packets, which would result in lost keys when converting PGPSecretKeyRings to PGPPublicKeyRings. - * - * This method throws a {@link RuntimeException} of a {@link NoSuchFieldException} or {@link IllegalAccessException}. - * - * @see Bouncycastle Java bug report #381 - * - * @param secretKeys possibly faulty PGPSecretKeyRing - * @param decryptor decryptor in case the keys are encrypted (can be null) - * @param encryptor encryptor to re-encrypt the keys in case they are encrypted (can be null) - * - * @return fixed PGPSecretKeyRing - * - * @throws PGPException in case we cannot dismantle or reassemble the key. - */ - public static PGPSecretKeyRing repairSubkeyPackets(@Nonnull PGPSecretKeyRing secretKeys, - @Nullable PBESecretKeyDecryptor decryptor, - @Nullable PBESecretKeyEncryptor encryptor) - throws PGPException { - - PGPDigestCalculator calculator = new BcPGPDigestCalculatorProvider().get(HashAlgorithmTags.SHA1); - - List _secretKeys = new ArrayList<>(); - Iterator secretKeyIterator = secretKeys.iterator(); - try { - - while (secretKeyIterator.hasNext()) { - PGPSecretKey secSubKey = secretKeyIterator.next(); - - if (secSubKey.isMasterKey()) { - LOGGER.log(Level.INFO, Long.toHexString(secSubKey.getKeyID()) + " is master key. Skip."); - _secretKeys.add(secSubKey); - continue; - } - - PGPPublicKey pubSubKey = secSubKey.getPublicKey(); - - // check for public key packet type - - Field publicPk = pubSubKey.getClass().getDeclaredField("publicPk"); - publicPk.setAccessible(true); - PublicKeyPacket keyPacket = (PublicKeyPacket) publicPk.get(pubSubKey); - - if (keyPacket instanceof PublicSubkeyPacket) { - // Sub key is already sub key - _secretKeys.add(secSubKey); - continue; - } - - // Sub key is normal key -> fix - LOGGER.log(Level.INFO, "Subkey " + Long.toHexString(secSubKey.getKeyID()) + " does not have a subkey key packet. Convert it..."); - keyPacket = new PublicSubkeyPacket(pubSubKey.getAlgorithm(), pubSubKey.getCreationTime(), keyPacket.getKey()); - publicPk.set(pubSubKey, keyPacket); - - PGPPrivateKey privateKey = secSubKey.extractPrivateKey(decryptor); - - PGPSecretKey secretKey = new PGPSecretKey(privateKey, pubSubKey, calculator, false, encryptor); - _secretKeys.add(secretKey); - } - - return new PGPSecretKeyRing(_secretKeys); - } catch (NoSuchFieldException | IllegalAccessException e) { - throw new RuntimeException("Cannot apply fix due to an error while using reflections.", e); - } - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/MultiMap.java b/pgpainless-core/src/main/java/org/pgpainless/util/MultiMap.java deleted file mode 100644 index ee5e70f8..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/util/MultiMap.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.util; - -import javax.annotation.Nonnull; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -public class MultiMap { - - private final Map> map; - - public MultiMap() { - map = new HashMap<>(); - } - - public MultiMap(@Nonnull MultiMap other) { - this.map = new HashMap<>(); - for (K k : other.map.keySet()) { - map.put(k, new HashSet<>(other.map.get(k))); - } - } - - public MultiMap(@Nonnull Map> content) { - this.map = new HashMap<>(content); - } - - public int size() { - return map.size(); - } - - public boolean isEmpty() { - return map.isEmpty(); - } - - public boolean containsKey(K o) { - return map.containsKey(o); - } - - public boolean containsValue(V o) { - for (Set values : map.values()) { - if (values.contains(o)) return true; - } - return false; - } - - public Set get(K o) { - return map.get(o); - } - - public void put(K k, V v) { - Set values = map.get(k); - if (values == null) { - values = new HashSet<>(); - map.put(k, values); - } - values.add(v); - } - - public void put(K k, Set vs) { - for (V v : vs) { - put(k, v); - } - } - - public void remove(K o) { - for (Set values : map.values()) { - values.remove(o); - } - } - - public void putAll(Map> _map) { - for (K key : _map.keySet()) { - Set vs = this.map.get(key); - if (vs == null) { - vs = new HashSet<>(); - this.map.put(key, vs); - } - vs.addAll(_map.get(key)); - } - } - - public void clear() { - map.clear(); - } - - public Set keySet() { - return map.keySet(); - } - - public Collection> values() { - return map.values(); - } - - public Set>> entrySet() { - return map.entrySet(); - } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - - if (!(o instanceof MultiMap)) { - return false; - } - - if (this == o) { - return true; - } - - return map.equals(((MultiMap) o).map); - } - - @Override - public int hashCode() { - return map.hashCode(); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/Passphrase.java b/pgpainless-core/src/main/java/org/pgpainless/util/Passphrase.java deleted file mode 100644 index 10fddf8c..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/util/Passphrase.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless.util; - -import javax.annotation.Nullable; -import java.util.Arrays; - -public class Passphrase { - - private final Object lock = new Object(); - - private final char[] chars; - private boolean valid = true; - - /** - * Passphrase for keys etc. - * - * @param chars may be null for empty passwords. - */ - public Passphrase(@Nullable char[] chars) { - this.chars = chars; - } - - /** - * Overwrite the char array with spaces and mark the {@link Passphrase} as invalidated. - */ - public void clear() { - synchronized (lock) { - if (chars != null) { - Arrays.fill(chars, ' '); - } - valid = false; - } - } - - /** - * Call {@link #clear()} to make sure the memory is overwritten. - * - * @throws Throwable bad things might happen in {@link Object#finalize()}. - */ - @Override - protected void finalize() throws Throwable { - clear(); - super.finalize(); - } - - /** - * Return a copy of the underlying char array. - * A return value of {@code null} represents no password. - * - * @return passphrase chars. - * - * @throws IllegalStateException in case the password has been cleared at this point. - */ - public @Nullable char[] getChars() { - synchronized (lock) { - if (!valid) { - throw new IllegalStateException("Passphrase has been cleared."); - } - - if (chars == null) { - return null; - } - - char[] copy = new char[chars.length]; - System.arraycopy(chars, 0, copy, 0, chars.length); - return copy; - } - } - - /** - * Return true if the passphrase has not yet been cleared. - * - * @return valid - */ - public boolean isValid() { - synchronized (lock) { - return valid; - } - } - - /** - * Represents a {@link Passphrase} instance that represents no password. - * - * @return empty passphrase - */ - public static Passphrase emptyPassphrase() { - return new Passphrase(null); - } -} diff --git a/pgpainless-core/src/main/java/org/pgpainless/util/package-info.java b/pgpainless-core/src/main/java/org/pgpainless/util/package-info.java deleted file mode 100644 index 9f7b28ca..00000000 --- a/pgpainless-core/src/main/java/org/pgpainless/util/package-info.java +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/** - * Utility classes. - */ -package org.pgpainless.util; diff --git a/pgpainless-core/src/test/java/org/pgpainless/AbstractPGPainlessTest.java b/pgpainless-core/src/test/java/org/pgpainless/AbstractPGPainlessTest.java deleted file mode 100644 index 68722887..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/AbstractPGPainlessTest.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import java.security.Security; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.junit.BeforeClass; - -public abstract class AbstractPGPainlessTest { - - @BeforeClass - public static void registerProvider() { - Security.addProvider(new BouncyCastleProvider()); - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/BCUtilTest.java b/pgpainless-core/src/test/java/org/pgpainless/BCUtilTest.java deleted file mode 100644 index 3e8dea69..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/BCUtilTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertTrue; - -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Arrays; -import java.util.Iterator; -import java.util.logging.Level; -import java.util.logging.Logger; - -import junit.framework.TestCase; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.junit.Test; -import org.pgpainless.key.collection.PGPKeyRing; -import org.pgpainless.key.generation.KeySpec; -import org.pgpainless.key.generation.type.RSA_GENERAL; -import org.pgpainless.key.generation.type.length.RsaLength; -import org.pgpainless.util.BCUtil; - -public class BCUtilTest extends AbstractPGPainlessTest { - - private static final Logger LOGGER = Logger.getLogger(BCUtil.class.getName()); - - @Test - public void keyRingToCollectionTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing ring = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder(RSA_GENERAL.withLength(RsaLength._3072)).withDefaultKeyFlags().withDefaultAlgorithms()) - .withMasterKey(KeySpec.getBuilder(RSA_GENERAL.withLength(RsaLength._3072)).withDefaultKeyFlags().withDefaultAlgorithms()) - .withPrimaryUserId("donald@duck.tails").withoutPassphrase().build(); - PGPSecretKeyRing sec = ring.getSecretKeys(); - PGPPublicKeyRing pub = ring.getPublicKeys(); - - LOGGER.log(Level.INFO, "Main ID: " + sec.getPublicKey().getKeyID() + " " + pub.getPublicKey().getKeyID()); - - int secSize = 1; - Iterator secPubIt = sec.getPublicKeys(); - while (secPubIt.hasNext()) { - PGPPublicKey k = secPubIt.next(); - LOGGER.log(Level.INFO, secSize + " " + k.getKeyID() + " " + k.isEncryptionKey() + " " + k.isMasterKey()); - secSize++; - } - - LOGGER.log(Level.INFO, "After BCUtil.publicKeyRingFromSecretKeyRing()"); - int pubSize = 1; - Iterator pubPubIt = pub.getPublicKeys(); - while (pubPubIt.hasNext()) { - PGPPublicKey k = pubPubIt.next(); - LOGGER.log(Level.INFO, pubSize + " " + k.getKeyID() + " " + k.isEncryptionKey() + " " + k.isMasterKey()); - pubSize++; - } - - assertEquals(secSize, pubSize); - - PGPSecretKeyRingCollection secCol = BCUtil.keyRingsToKeyRingCollection(sec); - - int secColSize = 0; - Iterator secColIt = secCol.getKeyRings(); - while (secColIt.hasNext()) { - PGPSecretKeyRing r = secColIt.next(); - LOGGER.log(Level.INFO, "" + r.getPublicKey().getKeyID()); - secColSize++; - } - - LOGGER.log(Level.INFO, "SecCol: " + secColSize); - - PGPPublicKeyRingCollection pubCol = BCUtil.keyRingsToKeyRingCollection(pub); - - int pubColSize = 0; - Iterator pubColIt = pubCol.getKeyRings(); - while (pubColIt.hasNext()) { - PGPPublicKeyRing r = pubColIt.next(); - LOGGER.log(Level.INFO, "" + r.getPublicKey().getKeyID()); - pubColSize++; - } - - LOGGER.log(Level.INFO, "PubCol: " + pubColSize); - } - - @Test - public void removeUnsignedKeysTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { - PGPKeyRing alice = PGPainless.generateKeyRing().simpleRsaKeyRing("alice@wonderland.lit", RsaLength._1024); - PGPKeyRing mallory = PGPainless.generateKeyRing().simpleEcKeyRing("mallory@mall.ory"); - - PGPSecretKey subKey = null; - Iterator sit = mallory.getSecretKeys().getSecretKeys(); - while (sit.hasNext()) { - PGPSecretKey s = sit.next(); - if (!s.isMasterKey()) { - subKey = s; - break; - } - } - - TestCase.assertNotNull(subKey); - - PGPSecretKeyRing alice_mallory = PGPSecretKeyRing.insertSecretKey(alice.getSecretKeys(), subKey); - - // Check, if alice_mallory contains mallory's key - TestCase.assertNotNull(alice_mallory.getSecretKey(subKey.getKeyID())); - - PGPSecretKeyRing cleaned = BCUtil.removeUnassociatedKeysFromKeyRing(alice_mallory, alice.getPublicKeys().getPublicKey()); - TestCase.assertNull(cleaned.getSecretKey(subKey.getKeyID())); - } - - @Test - public void removeUnsignedKeysECTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing ring = PGPainless.generateKeyRing().simpleEcKeyRing("alice@wonderland.lit"); - PGPPublicKeyRing publicKeys = ring.getPublicKeys(); - PGPSecretKeyRing secretKeys = ring.getSecretKeys(); - PGPSecretKeyRing secCleaned = ring.getSecretKeys(); - - assertTrue(Arrays.equals(secretKeys.getEncoded(), secCleaned.getEncoded())); - - PGPPublicKeyRing pubCleaned = BCUtil.removeUnassociatedKeysFromKeyRing(publicKeys, publicKeys.getPublicKey()); - - assertTrue(Arrays.equals(publicKeys.getEncoded(), pubCleaned.getEncoded())); - - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/BouncycastleExportSubkeys.java b/pgpainless-core/src/test/java/org/pgpainless/BouncycastleExportSubkeys.java deleted file mode 100644 index 76547318..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/BouncycastleExportSubkeys.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import java.security.InvalidAlgorithmParameterException; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Date; - -import org.bouncycastle.bcpg.CompressionAlgorithmTags; -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; -import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; -import org.bouncycastle.bcpg.sig.Features; -import org.bouncycastle.bcpg.sig.KeyFlags; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPKeyPair; -import org.bouncycastle.openpgp.PGPKeyRingGenerator; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSignature; -import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; -import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder; -import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; -import org.junit.Test; - -public class BouncycastleExportSubkeys extends AbstractPGPainlessTest { - - @Test - public void testExportImport() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, PGPException { - KeyPairGenerator generator; - KeyPair pair; - - // Generate master key - - generator = KeyPairGenerator.getInstance("ECDSA", BouncyCastleProvider.PROVIDER_NAME); - generator.initialize(new ECNamedCurveGenParameterSpec("P-256")); - - pair = generator.generateKeyPair(); - PGPKeyPair pgpMasterKey = new JcaPGPKeyPair(PublicKeyAlgorithmTags.ECDSA, pair, new Date()); - - PGPSignatureSubpacketGenerator subPackets = new PGPSignatureSubpacketGenerator(); - subPackets.setKeyFlags(false, KeyFlags.AUTHENTICATION & KeyFlags.CERTIFY_OTHER & KeyFlags.SIGN_DATA); - subPackets.setPreferredCompressionAlgorithms(false, new int[] { - SymmetricKeyAlgorithmTags.AES_256, - SymmetricKeyAlgorithmTags.AES_128, - SymmetricKeyAlgorithmTags.AES_128}); - subPackets.setPreferredHashAlgorithms(false, new int[] { - HashAlgorithmTags.SHA512, - HashAlgorithmTags.SHA384, - HashAlgorithmTags.SHA256, - HashAlgorithmTags.SHA224}); - subPackets.setPreferredCompressionAlgorithms(false, new int[] { - CompressionAlgorithmTags.ZLIB, - CompressionAlgorithmTags.BZIP2, - CompressionAlgorithmTags.ZIP, - CompressionAlgorithmTags.UNCOMPRESSED}); - subPackets.setFeature(false, Features.FEATURE_MODIFICATION_DETECTION); - - // Generate sub key - - generator = KeyPairGenerator.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME); - generator.initialize(new ECNamedCurveGenParameterSpec("P-256")); - - pair = generator.generateKeyPair(); - PGPKeyPair pgpSubKey = new JcaPGPKeyPair(PublicKeyAlgorithmTags.ECDH, pair, new Date()); - - // Assemble key - - PGPDigestCalculator calculator = new JcaPGPDigestCalculatorProviderBuilder() - .setProvider(BouncyCastleProvider.PROVIDER_NAME) - .build() - .get(HashAlgorithmTags.SHA1); - - PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( - pgpMasterKey.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA512) - .setProvider(BouncyCastleProvider.PROVIDER_NAME); - - PGPKeyRingGenerator pgpGenerator = new PGPKeyRingGenerator(PGPSignature.POSITIVE_CERTIFICATION, - pgpMasterKey, "alice@wonderland.lit", calculator, subPackets.generate(), null, - signerBuilder, null); - - // Add sub key - - subPackets.setKeyFlags(false, KeyFlags.ENCRYPT_STORAGE & KeyFlags.ENCRYPT_COMMS); - - pgpGenerator.addSubKey(pgpSubKey, subPackets.generate(), null); - - // Generate SecretKeyRing - - PGPSecretKeyRing secretKeys = pgpGenerator.generateSecretKeyRing(); - PGPPublicKeyRing publicKeys = pgpGenerator.generatePublicKeyRing(); - - // Test - - /* - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(2048); - outputStream.write(secretKeys.getEncoded()); - - PGPPublicKeyRing publicKeys = new PGPPublicKeyRing(outputStream.toByteArray(), new BcKeyFingerprintCalculator()); - - Iterator iterator = secretKeys.getPublicKeys(); - while (iterator.hasNext()) { - assertNotNull(publicKeys.getPublicKey(iterator.next().getKeyID())); - } - */ - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/EncryptDecryptTest.java b/pgpainless-core/src/test/java/org/pgpainless/EncryptDecryptTest.java deleted file mode 100644 index f8c294d5..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/EncryptDecryptTest.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import static junit.framework.TestCase.assertEquals; -import static junit.framework.TestCase.assertFalse; -import static junit.framework.TestCase.assertTrue; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.util.io.Streams; -import org.junit.Ignore; -import org.junit.Test; -import org.pgpainless.algorithm.KeyFlag; -import org.pgpainless.algorithm.PublicKeyAlgorithm; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.decryption_verification.DecryptionStream; -import org.pgpainless.decryption_verification.OpenPgpMetadata; -import org.pgpainless.encryption_signing.EncryptionStream; -import org.pgpainless.key.collection.PGPKeyRing; -import org.pgpainless.key.generation.KeySpec; -import org.pgpainless.key.generation.type.ElGamal_GENERAL; -import org.pgpainless.key.generation.type.RSA_GENERAL; -import org.pgpainless.key.generation.type.length.ElGamalLength; -import org.pgpainless.key.generation.type.length.RsaLength; -import org.pgpainless.key.protection.SecretKeyRingProtector; -import org.pgpainless.key.protection.UnprotectedKeysProtector; -import org.pgpainless.util.BCUtil; - -public class EncryptDecryptTest extends AbstractPGPainlessTest { - - private static final Logger LOGGER = Logger.getLogger(EncryptDecryptTest.class.getName()); - private static final Charset UTF8 = Charset.forName("UTF-8"); - - private static final String testMessage = "Ah, Juliet, if the measure of thy joy\n" + - "Be heaped like mine, and that thy skill be more\n" + - "To blazon it, then sweeten with thy breath\n" + - "This neighbor air, and let rich music’s tongue\n" + - "Unfold the imagined happiness that both\n" + - "Receive in either by this dear encounter."; - - public EncryptDecryptTest() { - LOGGER.log(Level.INFO, "Plain Length: " + testMessage.getBytes(UTF8).length); - } - - @Test - public void freshKeysRsaToElGamalTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("romeo@montague.lit", RsaLength._3072); - PGPKeyRing recipient = PGPainless.generateKeyRing() - .withSubKey(KeySpec.getBuilder(ElGamal_GENERAL.withLength(ElGamalLength._3072)).withKeyFlags(KeyFlag.ENCRYPT_STORAGE, KeyFlag.ENCRYPT_COMMS).withDefaultAlgorithms()) - .withMasterKey(KeySpec.getBuilder(RSA_GENERAL.withLength(RsaLength._4096)).withKeyFlags(KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER).withDefaultAlgorithms()) - .withPrimaryUserId("juliet@capulet.lit").withoutPassphrase().build(); - - encryptDecryptForSecretKeyRings(sender, recipient); - } - - @Test - public void freshKeysRsaToRsaTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("romeo@montague.lit", RsaLength._4096); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleRsaKeyRing("juliet@capulet.lit", RsaLength._4096); - - encryptDecryptForSecretKeyRings(sender, recipient); - } - - @Test - public void freshKeysEcToEcTest() throws IOException, PGPException, NoSuchAlgorithmException, NoSuchProviderException, - InvalidAlgorithmParameterException { - PGPKeyRing sender = PGPainless.generateKeyRing().simpleEcKeyRing("romeo@montague.lit"); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleEcKeyRing("juliet@capulet.lit"); - - encryptDecryptForSecretKeyRings(sender, recipient); - } - - @Test - public void freshKeysEcToRsaTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing sender = PGPainless.generateKeyRing().simpleEcKeyRing("romeo@montague.lit"); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleRsaKeyRing("juliet@capulet.lit", RsaLength._4096); - - encryptDecryptForSecretKeyRings(sender, recipient); - } - - @Test - public void freshKeysRsaToEcTest() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("romeo@montague.lit", RsaLength._4096); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleEcKeyRing("juliet@capulet.lit"); - - encryptDecryptForSecretKeyRings(sender, recipient); - } - - @Ignore - private void encryptDecryptForSecretKeyRings(PGPKeyRing sender, PGPKeyRing recipient) - throws PGPException, - IOException { - PGPSecretKeyRing recipientSec = recipient.getSecretKeys(); - PGPSecretKeyRing senderSec = sender.getSecretKeys(); - PGPPublicKeyRing recipientPub = recipient.getPublicKeys(); - PGPPublicKeyRing senderPub = sender.getPublicKeys(); - - SecretKeyRingProtector keyDecryptor = new UnprotectedKeysProtector(); - - byte[] secretMessage = testMessage.getBytes(UTF8); - - ByteArrayOutputStream envelope = new ByteArrayOutputStream(); - - EncryptionStream encryptor = PGPainless.createEncryptor() - .onOutputStream(envelope) - .toRecipients(recipientPub) - .usingSecureAlgorithms() - .signWith(keyDecryptor, senderSec) - .noArmor(); - - OpenPgpMetadata encryptionResult = encryptor.getResult(); - - assertFalse(encryptionResult.getAllSignatureKeyFingerprints().isEmpty()); - for (long keyId : encryptionResult.getAllSignatureKeyFingerprints()) { - assertTrue(BCUtil.keyRingContainsKeyWithId(senderPub, keyId)); - } - - assertFalse(encryptionResult.getRecipientKeyIds().isEmpty()); - for (long keyId : encryptionResult.getRecipientKeyIds()) { - assertTrue(BCUtil.keyRingContainsKeyWithId(recipientPub, keyId)); - } - - assertEquals(SymmetricKeyAlgorithm.AES_256, encryptionResult.getSymmetricKeyAlgorithm()); - - Streams.pipeAll(new ByteArrayInputStream(secretMessage), encryptor); - encryptor.close(); - byte[] encryptedSecretMessage = envelope.toByteArray(); - - LOGGER.log(Level.INFO, "Sender: " + PublicKeyAlgorithm.fromId(senderPub.getPublicKey().getAlgorithm()) + - " Receiver: " + PublicKeyAlgorithm.fromId(recipientPub.getPublicKey().getAlgorithm()) + - " Encrypted Length: " + encryptedSecretMessage.length); - - // Juliet trieth to comprehend Romeos words - - ByteArrayInputStream envelopeIn = new ByteArrayInputStream(encryptedSecretMessage); - DecryptionStream decryptor = PGPainless.createDecryptor() - .onInputStream(envelopeIn) - .decryptWith(keyDecryptor, BCUtil.keyRingsToKeyRingCollection(recipientSec)) - .verifyWith(BCUtil.keyRingsToKeyRingCollection(senderPub)) - .ignoreMissingPublicKeys() - .build(); - - ByteArrayOutputStream decryptedSecretMessage = new ByteArrayOutputStream(); - - Streams.pipeAll(decryptor, decryptedSecretMessage); - decryptor.close(); - - assertTrue(Arrays.equals(secretMessage, decryptedSecretMessage.toByteArray())); - OpenPgpMetadata result = decryptor.getResult(); - assertTrue(result.containsVerifiedSignatureFrom(senderPub)); - assertTrue(result.isIntegrityProtected()); - assertTrue(result.isSigned()); - assertTrue(result.isEncrypted()); - assertTrue(result.isVerified()); - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/ImportExportKeyTest.java b/pgpainless-core/src/test/java/org/pgpainless/ImportExportKeyTest.java deleted file mode 100644 index 9ead5553..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/ImportExportKeyTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import static junit.framework.TestCase.assertTrue; - -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Arrays; -import java.util.Iterator; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; -import org.junit.Test; -import org.pgpainless.key.collection.PGPKeyRing; - -public class ImportExportKeyTest extends AbstractPGPainlessTest { - - /** - * Test the export and import of a key ring with sub keys. - * @throws PGPException very - * @throws NoSuchAlgorithmException much - * @throws NoSuchProviderException some - * @throws InvalidAlgorithmParameterException annoying - * @throws IOException exceptions - */ - @Test - public void test() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing keyRing = PGPainless.generateKeyRing().simpleEcKeyRing("alice@bla.blub"); - PGPSecretKeyRing secretKeys = keyRing.getSecretKeys(); - PGPPublicKeyRing publicKeys = keyRing.getPublicKeys(); - - BcKeyFingerprintCalculator calc = new BcKeyFingerprintCalculator(); - byte[] bytes = publicKeys.getEncoded(); - PGPPublicKeyRing parsed = new PGPPublicKeyRing(bytes, calc); - assertTrue(Arrays.equals(publicKeys.getEncoded(), parsed.getEncoded())); - - Iterator it = secretKeys.getPublicKeys(); - assertTrue(it.hasNext()); - it.next(); - assertTrue(it.hasNext()); - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/KeyRingSubKeyFixTest.java b/pgpainless-core/src/test/java/org/pgpainless/KeyRingSubKeyFixTest.java deleted file mode 100644 index 43bcfd45..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/KeyRingSubKeyFixTest.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import static junit.framework.TestCase.assertTrue; - -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Arrays; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.junit.Test; -import org.pgpainless.key.collection.PGPKeyRing; -import org.pgpainless.util.BCUtil; -import org.pgpainless.util.KeyRingSubKeyFix; - -public class KeyRingSubKeyFixTest extends AbstractPGPainlessTest { - - @Test - public void test() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - PGPKeyRing ring = PGPainless.generateKeyRing().simpleEcKeyRing("hallo@welt.de"); - PGPSecretKeyRing secretKeys = ring.getSecretKeys(); - PGPPublicKeyRing publicKeys = ring.getPublicKeys(); - - PGPSecretKeyRing fixed = KeyRingSubKeyFix.repairSubkeyPackets(secretKeys, null, null); - - assertTrue(Arrays.equals(secretKeys.getEncoded(), fixed.getEncoded())); - - PGPPublicKeyRing fixedPub = BCUtil.publicKeyRingFromSecretKeyRing(fixed); - - assertTrue(Arrays.equals(publicKeys.getEncoded(), fixedPub.getEncoded())); - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/LengthTest.java b/pgpainless-core/src/test/java/org/pgpainless/LengthTest.java deleted file mode 100644 index 7b4dd2c2..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/LengthTest.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.security.InvalidAlgorithmParameterException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.Random; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.util.io.Streams; -import org.junit.Ignore; -import org.pgpainless.key.collection.PGPKeyRing; -import org.pgpainless.key.generation.type.length.RsaLength; -import org.pgpainless.key.protection.SecretKeyRingProtector; -import org.pgpainless.key.protection.UnprotectedKeysProtector; - -/** - * Class used to determine the length of cipher-text depending on used algorithms. - */ -public class LengthTest extends AbstractPGPainlessTest { - - private static final Logger LOGGER = Logger.getLogger(LengthTest.class.getName()); - - // @Test - public void ecEc() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - LOGGER.log(Level.INFO, "\nEC -> EC"); - PGPKeyRing sender = PGPainless.generateKeyRing().simpleEcKeyRing("simplejid@server.tld"); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleEcKeyRing("otherjid@other.srv"); - encryptDecryptForSecretKeyRings(sender, recipient); - } - - - // @Test - public void RsaRsa() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - LOGGER.log(Level.INFO, "\nRSA-2048 -> RSA-2048"); - PGPKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("simplejid@server.tld", RsaLength._2048); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleRsaKeyRing("otherjid@other.srv", RsaLength._2048); - encryptDecryptForSecretKeyRings(sender, recipient); - } - - // @Test - public void RsaRsa4096() - throws PGPException, - IOException { - LOGGER.log(Level.INFO, "\nRSA-4096 -> RSA-4096"); - PGPKeyRing sender = PGPainless.readKeyRing().keyRing(TestKeys.JULIET_PUB, TestKeys.JULIET_SEC); - PGPKeyRing recipient = PGPainless.readKeyRing().keyRing(TestKeys.ROMEO_PUB, TestKeys.ROMEO_SEC); - encryptDecryptForSecretKeyRings(sender, recipient); - } - - // @Test - public void rsaEc() throws PGPException, IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, - NoSuchProviderException { - LOGGER.log(Level.INFO, "\nRSA-2048 -> EC"); - PGPKeyRing sender = PGPainless.generateKeyRing().simpleRsaKeyRing("simplejid@server.tld", RsaLength._2048); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleEcKeyRing("otherjid@other.srv"); - encryptDecryptForSecretKeyRings(sender, recipient); - } - - // @Test - public void ecRsa() - throws PGPException, NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException, - IOException { - LOGGER.log(Level.INFO, "\nEC -> RSA-2048"); - PGPKeyRing sender = PGPainless.generateKeyRing().simpleEcKeyRing("simplejid@server.tld"); - PGPKeyRing recipient = PGPainless.generateKeyRing().simpleRsaKeyRing("otherjid@other.srv", RsaLength._2048); - encryptDecryptForSecretKeyRings(sender, recipient); - } - - @Ignore - private void encryptDecryptForSecretKeyRings(PGPKeyRing sender, PGPKeyRing recipient) - throws PGPException, - IOException { - PGPSecretKeyRing recipientSec = recipient.getSecretKeys(); - PGPSecretKeyRing senderSec = sender.getSecretKeys(); - PGPPublicKeyRing recipientPub = recipient.getPublicKeys(); - PGPPublicKeyRing senderPub = sender.getPublicKeys(); - - SecretKeyRingProtector keyDecryptor = new UnprotectedKeysProtector(); - - for (int i = 1; i <= 100; i++) { - byte[] secretMessage = new byte[i * 20]; - new Random().nextBytes(secretMessage); - - ByteArrayOutputStream envelope = new ByteArrayOutputStream(); - - OutputStream encryptor = PGPainless.createEncryptor() - .onOutputStream(envelope) - .toRecipients(recipientPub) - // .doNotEncrypt() - .usingSecureAlgorithms() - .signWith(keyDecryptor, senderSec) - .noArmor(); - - Streams.pipeAll(new ByteArrayInputStream(secretMessage), encryptor); - encryptor.close(); - byte[] encryptedSecretMessage = envelope.toByteArray(); - - LOGGER.log(Level.INFO,"\n" + encryptedSecretMessage.length); - } - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/OpenPgpV4FingerprintTest.java b/pgpainless-core/src/test/java/org/pgpainless/OpenPgpV4FingerprintTest.java deleted file mode 100644 index f3d5f5e8..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/OpenPgpV4FingerprintTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import static junit.framework.TestCase.assertEquals; -import static org.junit.Assert.assertNotEquals; - -import java.io.IOException; - -import org.bouncycastle.openpgp.PGPPublicKey; -import org.junit.Test; -import org.pgpainless.key.OpenPgpV4Fingerprint; - -public class OpenPgpV4FingerprintTest extends AbstractPGPainlessTest { - - @Test(expected = IllegalArgumentException.class) - public void fpTooShort() { - String fp = "484f57414c495645"; // Asking Mark - new OpenPgpV4Fingerprint(fp); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidHexTest() { - String fp = "UNFORTUNATELYTHISISNOVALIDHEXADECIMALDOH"; - new OpenPgpV4Fingerprint(fp); - } - - @Test - public void validFingerprintTest() { - String fp = "4A4F48414E4E53454E2049532041204E45524421"; - OpenPgpV4Fingerprint finger = new OpenPgpV4Fingerprint(fp); - assertEquals(fp, finger.toString()); - assertEquals(fp.length(), finger.length()); - for (int i = 0; i < finger.length(); i++) { - assertEquals(fp.charAt(i), finger.charAt(i)); - } - assertEquals("4A4F", finger.subSequence(0, 4)); - } - - @Test - public void convertsToUpperCaseTest() { - String fp = "444f4e5420552048415645204120484f4242593f"; - OpenPgpV4Fingerprint finger = new OpenPgpV4Fingerprint(fp); - assertEquals("444F4E5420552048415645204120484F4242593F", finger.toString()); - } - - @Test - public void equalsOtherFingerprintTest() { - OpenPgpV4Fingerprint finger = new OpenPgpV4Fingerprint("5448452043414b452049532041204c4945212121"); - assertEquals(finger, new OpenPgpV4Fingerprint("5448452043414B452049532041204C4945212121")); - assertEquals(0, finger.compareTo(new OpenPgpV4Fingerprint("5448452043414B452049532041204C4945212121"))); - assertNotEquals(finger, new OpenPgpV4Fingerprint("0000000000000000000000000000000000000000")); - assertNotEquals(finger, null); - assertNotEquals(finger, new Object()); - } - - @Test - public void keyIdTest() throws IOException { - PGPPublicKey key = TestKeys.getJulietPublicKeyRing().getPublicKey(); - long keyId = key.getKeyID(); - - OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(key); - assertEquals(keyId, fingerprint.getKeyId()); - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/SymmetricTest.java b/pgpainless-core/src/test/java/org/pgpainless/SymmetricTest.java deleted file mode 100644 index 27865f05..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/SymmetricTest.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import static junit.framework.TestCase.assertTrue; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.logging.Level; -import java.util.logging.Logger; - -import org.bouncycastle.bcpg.ArmoredOutputStream; -import org.bouncycastle.openpgp.PGPException; -import org.junit.Test; -import org.pgpainless.algorithm.SymmetricKeyAlgorithm; -import org.pgpainless.util.Passphrase; - -public class SymmetricTest extends AbstractPGPainlessTest { - - private static final Logger LOGGER = Logger.getLogger(SymmetricTest.class.getName()); - - private static final String message = "I grew up with the understanding that the world " + - "I lived in was one where people enjoyed a sort of freedom " + - "to communicate with each other in privacy, without it " + - "being monitored, without it being measured or analyzed " + - "or sort of judged by these shadowy figures or systems, " + - "any time they mention anything that travels across " + - "public lines.\n" + - "\n" + - "- Edward Snowden -"; - - @Test - public void testSymmetricEncryptionDecryption() throws IOException, PGPException { - byte[] plain = message.getBytes(); - Passphrase passphrase = new Passphrase("choose_a_better_password_please".toCharArray()); - byte[] enc = PGPainless.encryptWithPassword(plain, passphrase, SymmetricKeyAlgorithm.AES_128); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ArmoredOutputStream armor = new ArmoredOutputStream(out); - armor.write(enc); - armor.flush(); - armor.close(); - - // Print cipher text for validation with GnuPG. - LOGGER.log(Level.INFO, new String(out.toByteArray())); - - byte[] plain2 = PGPainless.decryptWithPassword(enc, passphrase); - assertTrue(Arrays.equals(plain, plain2)); - } -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/TestKeys.java b/pgpainless-core/src/test/java/org/pgpainless/TestKeys.java deleted file mode 100644 index fbc4585e..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/TestKeys.java +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import java.io.ByteArrayInputStream; -import java.io.IOException; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; -import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; - -public class TestKeys extends AbstractPGPainlessTest { - - private static final KeyFingerPrintCalculator calc = new BcKeyFingerprintCalculator(); - private static PGPSecretKeyRing julietSecretKeyRing = null; - private static PGPPublicKeyRing julietPublicKeyRing = null; - private static PGPSecretKeyRing romeoSecretKeyRing = null; - private static PGPPublicKeyRing romeoPublicKeyRing = null; - - private static PGPSecretKeyRingCollection julietSecretKeyRingCollection = null; - private static PGPPublicKeyRingCollection julietPublicKeyRingCollection = null; - private static PGPSecretKeyRingCollection romeoSecretKeyRingCollection = null; - private static PGPPublicKeyRingCollection romeoPublicKeyRingCollection = null; - - public static final String JULIET_UID = "xmpp:juliet@capulet.lit"; - public static final long JULIET_KEY_ID = -5425419407118114754L; - - /** - * Public key of xmpp:juliet@capulet.lit. - */ - public static final String JULIET_PUB = "" + - "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "\n" + - "mQENBFrxov4BCAChZwPrBxxIlwzpieR5T2pnaOZLWH0WqSON6rVjvfbJHWdDi3Th\n" + - "remHW4gg4IBSTXkVFDIeQNVcOvGNgMg3Oe/x0I6FK12jrw9prycmjFxQ7A0ix7ZG\n" + - "UkTF5jITgzJbkH100gYfXtZsfTyvgISSAT//6vvvQPZ3zCr09XvAG0CyQ1BhULsv\n" + - "mVRe4Oh5b0VK4kLdv+GiA/T+49UKZj6lne9Vdti16ZIj7teVCbicfdhpTzsjur42\n" + - "r8ptouKAuyFPw9KnGNwVlIiv5jt/Kit/LoOBenh74sitsCXq8IQ9kKp/eNt8TF4u\n" + - "D4IGpxnJfB8XCiixYHoFEajmQBVJXNYtvoPvABEBAAG0F3htcHA6anVsaWV0QGNh\n" + - "cHVsZXQubGl0iQFOBBMBCAA4FiEEHQGMdy34xe+GodzJtLUJy1k24D4FAlrxov4C\n" + - "Gy8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQtLUJy1k24D6H7AgAoTjx4ezc\n" + - "A83NeOY3tMHVQTM7hKuy0wMcSzQgVgJmhLYRZS8r+FocPZua/eke49GPhe2yozvl\n" + - "ByWHtotklQeJiwOKxuPKMzneVA1ZK3/9LdGvtZlHMcAkEKDhit8HIaEcsFd4Z1re\n" + - "EhF2lyvY/E+rrx9YxV0QjisSWV2dSptv6FeGSztr9e5E+Head6hEQhsugiTVRF+1\n" + - "6mG90te0WGQ9YNiJ2FJovx5kBLTTuhwUz8Oacqihd2+RDDI5p3wJoogVL31aNb4n\n" + - "c7dGo8ieJPHGlkBsOfmreSxijTodZz9MXsgcx7b//u0uQryViJoZHWbtnXOFjjNc\n" + - "GWBtS084NKWl9w==\n" + - "=ecwX\n" + - "-----END PGP PUBLIC KEY BLOCK-----"; - - /** - * Private key of xmpp:juliet@capulet.lit. - */ - public static final String JULIET_SEC = "" + - "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - "\n" + - "lQOYBFrxov4BCAChZwPrBxxIlwzpieR5T2pnaOZLWH0WqSON6rVjvfbJHWdDi3Th\n" + - "remHW4gg4IBSTXkVFDIeQNVcOvGNgMg3Oe/x0I6FK12jrw9prycmjFxQ7A0ix7ZG\n" + - "UkTF5jITgzJbkH100gYfXtZsfTyvgISSAT//6vvvQPZ3zCr09XvAG0CyQ1BhULsv\n" + - "mVRe4Oh5b0VK4kLdv+GiA/T+49UKZj6lne9Vdti16ZIj7teVCbicfdhpTzsjur42\n" + - "r8ptouKAuyFPw9KnGNwVlIiv5jt/Kit/LoOBenh74sitsCXq8IQ9kKp/eNt8TF4u\n" + - "D4IGpxnJfB8XCiixYHoFEajmQBVJXNYtvoPvABEBAAEAB/4jMbXagW3q7DkOEZnm\n" + - "0+jVTLvu0QhRsScGEphj+++8sfMq+NVPQp9p+w0Hcjy49ZjB/mnhS+zaVCYI33yJ\n" + - "AlKubXYuVqLwBsO7HUzRrIiSwq4ol9jIo7bIWmYv+As6iRq6JvPb0k+6T2K0uDbw\n" + - "KWKduM0fwhAcVkJFsOO/o5GrbQaJc3oioFk8uFWTnO+FPBRTJ9oTlVG2M/tEatZK\n" + - "gl7I8Ukl0YYruCNUFKZ0tvO8HqulxBgUbGPBer1uOlfUD4RXdc8/PUiFKNo48XSu\n" + - "ZUEAZKGbFBjuX5Z8ha7+sUMEYEt70qlbkiLQxgHKAmpyridAk3q/SB3y2VB8Ik7I\n" + - "gpExBADInzLROYuUcXqmty+znVwm6nRIB75JBAy778zgIxx1v0O3QlVnR+YI8gJM\n" + - "mQ/9pD6LyP9hktWDmJxG8tX+kSuIp3wNJc5EMeXtCCmkUW0CP1gUhAbNW3MezKa5\n" + - "II5IhE9RgIsYqSU8ZgeIh72ON8XTp8i/wGipCXvJPggSAMXukQQAzfRmtLW+JHEK\n" + - "B8ETIYh8IUjXJ6TVlmuBwZ0eXjCpqy9arJi6tacesDJwnL3sqOMQWUmqGsCGSKA5\n" + - "cLITkVsxX/htIq8GFyludjg8t4Nr+fOGfChEq8QE0PHE2CgskQMHpfHvfIdnwKve\n" + - "Fg2Q8twoMw849O6PF3k/848Z65lDin8EAMDbuPWL7KU2sWeqvDEuoulS5K1gsq8X\n" + - "p3Od3+f0OG8YViMjKcVlSKHVvdlK4dlsccJrJJx6VzotV47LsmvVbzDwUE//MYq7\n" + - "QwwQetZbpdQZDysSGVqHMTuAg/1pr2u5rqh4cFqCYatgZwinEI2TQMXEqnSc+mj8\n" + - "xp/LNq5BZZQuO4y0F3htcHA6anVsaWV0QGNhcHVsZXQubGl0iQFOBBMBCAA4FiEE\n" + - "HQGMdy34xe+GodzJtLUJy1k24D4FAlrxov4CGy8FCwkIBwIGFQoJCAsCBBYCAwEC\n" + - "HgECF4AACgkQtLUJy1k24D6H7AgAoTjx4ezcA83NeOY3tMHVQTM7hKuy0wMcSzQg\n" + - "VgJmhLYRZS8r+FocPZua/eke49GPhe2yozvlByWHtotklQeJiwOKxuPKMzneVA1Z\n" + - "K3/9LdGvtZlHMcAkEKDhit8HIaEcsFd4Z1reEhF2lyvY/E+rrx9YxV0QjisSWV2d\n" + - "Sptv6FeGSztr9e5E+Head6hEQhsugiTVRF+16mG90te0WGQ9YNiJ2FJovx5kBLTT\n" + - "uhwUz8Oacqihd2+RDDI5p3wJoogVL31aNb4nc7dGo8ieJPHGlkBsOfmreSxijTod\n" + - "Zz9MXsgcx7b//u0uQryViJoZHWbtnXOFjjNcGWBtS084NKWl9w==\n" + - "=yPPE\n" + - "-----END PGP PRIVATE KEY BLOCK-----"; - - public static final String ROMEO_UID = "xmpp:romeo@montague.lit"; - public static final long ROMEO_KEY_ID = 334147643349279223L; - - /** - * Public key of xmpp:romeo@montague.lit. - */ - public static final String ROMEO_PUB = "" + - "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "\n" + - "mQENBFrxopkBCADiYg/+mEObXgxuMW6/LFKpEyaJK9pBMgutuxnYZ9PXWZmOhDIT\n" + - "Ugm9X9YJ3Qh94KaHge9F4uCeFASmM1vvUTRFTEb1W5RR9ZE/sy/cdAttnZ5JloPi\n" + - "CT3HDMIJAxIXhRJkeUR9GUb51ql27bMXl6lFh865VdNSXN/B8FzRQHENxv1Bq/6Z\n" + - "iQOViIETeRRgO+u6u2iZkYlHgYMaoMK7+YiNlHXanU9Atcuaz0ZCJS/XFNH89iqB\n" + - "Kvnv7KCQh4FhrNMLJRzNPXV8MY05nn0zF72qeEsniB16Xde18lMro8fQehg2mLwc\n" + - "XGtCwCKI6QbZVxYQt77r3ZACiwl66soFWijVABEBAAG0F3htcHA6cm9tZW9AbW9u\n" + - "dGFndWUubGl0iQFOBBMBCAA4FiEENdKZ0IovfYAjCwldBKMhguBeIfcFAlrxopkC\n" + - "Gy8FCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQBKMhguBeIfcj8AgAu1wubUwr\n" + - "2aQmDN3OqRM4M4yRL3oyYMkCKIjqD6KEeFsIXSSkXOuREJKEo8Mb1+ewV0SYmHCC\n" + - "K3bKKq3m71AQ7evDhKGshacPYesiDvMdHWQdQnjfaoHhyn9qIKl7H0Xv1yf/wyuG\n" + - "ANy1jYgtCEuYw7D+EsqNDdn8Xh+k/9s4aMI/6mfC0yGZgG8EyLTfbZkGPoS4aZfV\n" + - "AGFbuqryg48dXtnuzAPKcdgMTTMSnmR729YlfkjCffcFaldyXoe1VMbudUO7nkO9\n" + - "g65i5EXenkbc2h0TRDQ4lDFQyModqFTwYFYxAf/RA6tuhIQEoCnpCytFMvrRKMb3\n" + - "Bx5vYRDVmE3jeg==\n" + - "=2jSg\n" + - "-----END PGP PUBLIC KEY BLOCK-----"; - - /** - * Private key of xmpp:romeo@montague.lit. - */ - public static final String ROMEO_SEC = "" + - "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - "\n" + - "lQOYBFrxopkBCADiYg/+mEObXgxuMW6/LFKpEyaJK9pBMgutuxnYZ9PXWZmOhDIT\n" + - "Ugm9X9YJ3Qh94KaHge9F4uCeFASmM1vvUTRFTEb1W5RR9ZE/sy/cdAttnZ5JloPi\n" + - "CT3HDMIJAxIXhRJkeUR9GUb51ql27bMXl6lFh865VdNSXN/B8FzRQHENxv1Bq/6Z\n" + - "iQOViIETeRRgO+u6u2iZkYlHgYMaoMK7+YiNlHXanU9Atcuaz0ZCJS/XFNH89iqB\n" + - "Kvnv7KCQh4FhrNMLJRzNPXV8MY05nn0zF72qeEsniB16Xde18lMro8fQehg2mLwc\n" + - "XGtCwCKI6QbZVxYQt77r3ZACiwl66soFWijVABEBAAEAB/4mu5p69/hRQ+UikWie\n" + - "Yun9rZ4hSBR+pR5kaifA4/rV1Km2PZ4HujiaYyRO6beDOgWkF7IlpezCfzBQc2ce\n" + - "ailkVemqHzIgV8CzQmhE8sHlzlr/wjXsXaJpRSCJxDG7PnRoJmt2b/W512WFSKQk\n" + - "vDklAVh4U1vlsqhCGWr4DmuJbJkRyDhcX01tplRwim283F7bGqRcMBmKMZHiMgVc\n" + - "0u84EYKKVizJ3YAaaVqZyHb4qdeKK2ak3fPNuGT/oGd2sxnkL+BZGjJpu3RGpTA1\n" + - "tbOvOQnJGHQtABFxE8n6H9dHPJGtgyz2+udjUhL/P/E3PDoXazZkXRq2oHZKgg0f\n" + - "AwOBBADsWncHgvz15rXPF7O6AivbGTJ5ctkgVy4U3Fu2sk9rf0fx0sryBSqtTBw1\n" + - "Uvn/p9RwTsKw6fng6Nf78xpZFlUDB00YCcuWkGodxvjTAyB0dtBmkhopeKi0dmHh\n" + - "ndnR6Pv0CsXu8nG7lUi+q6s3oc4h2OfDBhrqsyYY5M2gGit3dQQA9TNuinJD9XXv\n" + - "QRyauMnSJ5xRcfOu8QCxZlllCvffZjSGCPoVjUpJEe9qsVbXVj2GYCxjLCSXV0V+\n" + - "vlJfdPrl1BhZ3fmEpg0u7SyGDDOe8fe1ehk5sAeL8O0eFWlPSEaEccsjlpJ2FO0n\n" + - "P04SZdOeM6wmhDTEDzpFnjbPndQTH+ED/R1zNzr55DvxQodmrW/BvTmhGQ22rHtk\n" + - "IUfbeMaVfUvNLJA/JksrUIx3Gga9QCDZgfm1RsRhLUlHiqTQe23sPWgKOsbf5O1j\n" + - "XJZaCNZ7LloVQbkG7xFcnb/n1+JjBr4FxXjAA6cY/iRGlznjIIaasyklKm1/4LuQ\n" + - "hnH3QqTvCN3dOFS0F3htcHA6cm9tZW9AbW9udGFndWUubGl0iQFOBBMBCAA4FiEE\n" + - "NdKZ0IovfYAjCwldBKMhguBeIfcFAlrxopkCGy8FCwkIBwIGFQoJCAsCBBYCAwEC\n" + - "HgECF4AACgkQBKMhguBeIfcj8AgAu1wubUwr2aQmDN3OqRM4M4yRL3oyYMkCKIjq\n" + - "D6KEeFsIXSSkXOuREJKEo8Mb1+ewV0SYmHCCK3bKKq3m71AQ7evDhKGshacPYesi\n" + - "DvMdHWQdQnjfaoHhyn9qIKl7H0Xv1yf/wyuGANy1jYgtCEuYw7D+EsqNDdn8Xh+k\n" + - "/9s4aMI/6mfC0yGZgG8EyLTfbZkGPoS4aZfVAGFbuqryg48dXtnuzAPKcdgMTTMS\n" + - "nmR729YlfkjCffcFaldyXoe1VMbudUO7nkO9g65i5EXenkbc2h0TRDQ4lDFQyMod\n" + - "qFTwYFYxAf/RA6tuhIQEoCnpCytFMvrRKMb3Bx5vYRDVmE3jeg==\n" + - "=LZ1b\n" + - "-----END PGP PRIVATE KEY BLOCK-----"; - - public static PGPSecretKeyRing getJulietSecretKeyRing() throws IOException, PGPException { - if (julietSecretKeyRing == null) { - julietSecretKeyRing = new PGPSecretKeyRing( - PGPUtil.getDecoderStream(new ByteArrayInputStream(JULIET_SEC.getBytes())), calc); - } - return julietSecretKeyRing; - } - - public static PGPSecretKeyRingCollection getJulietSecretKeyRingCollection() throws IOException, PGPException { - if (julietSecretKeyRingCollection == null) { - julietSecretKeyRingCollection = new PGPSecretKeyRingCollection( - PGPUtil.getDecoderStream(new ByteArrayInputStream(JULIET_SEC.getBytes())), calc); - } - return julietSecretKeyRingCollection; - } - - public static PGPPublicKeyRing getJulietPublicKeyRing() throws IOException { - if (julietPublicKeyRing == null) { - julietPublicKeyRing = new PGPPublicKeyRing( - PGPUtil.getDecoderStream(new ByteArrayInputStream(JULIET_PUB.getBytes())), calc); - } - return julietPublicKeyRing; - } - - public static PGPPublicKeyRingCollection getJulietPublicKeyRingCollection() throws IOException, PGPException { - if (julietPublicKeyRingCollection == null) { - julietPublicKeyRingCollection = new PGPPublicKeyRingCollection( - PGPUtil.getDecoderStream(new ByteArrayInputStream(JULIET_PUB.getBytes())), calc); - } - return julietPublicKeyRingCollection; - } - - public static PGPSecretKeyRing getRomeoSecretKeyRing() throws IOException, PGPException { - if (romeoSecretKeyRing == null) { - romeoSecretKeyRing = new PGPSecretKeyRing( - PGPUtil.getDecoderStream(new ByteArrayInputStream(ROMEO_SEC.getBytes())), calc); - } - return romeoSecretKeyRing; - } - - public static PGPSecretKeyRingCollection getRomeoSecretKeyRingCollection() throws IOException, PGPException { - if (romeoSecretKeyRingCollection == null) { - romeoSecretKeyRingCollection = new PGPSecretKeyRingCollection( - PGPUtil.getDecoderStream(new ByteArrayInputStream(ROMEO_SEC.getBytes())), calc); - } - return romeoSecretKeyRingCollection; - } - - public static PGPPublicKeyRing getRomeoPublicKeyRing() throws IOException { - if (romeoPublicKeyRing == null) { - romeoPublicKeyRing = new PGPPublicKeyRing( - PGPUtil.getDecoderStream(new ByteArrayInputStream(ROMEO_PUB.getBytes())), calc); - } - return romeoPublicKeyRing; - } - - public static PGPPublicKeyRingCollection getRomeoPublicKeyRingCollection() throws IOException, PGPException { - if (romeoPublicKeyRingCollection == null) { - romeoPublicKeyRingCollection = new PGPPublicKeyRingCollection( - PGPUtil.getDecoderStream(new ByteArrayInputStream(ROMEO_PUB.getBytes())), calc); - } - return romeoPublicKeyRingCollection; - } - - public static final String TEST_MESSAGE_01_PLAIN = "This message is encrypted\n"; - - /** - * Test Message signed with {@link #JULIET_SEC} and encrypted for {@link #JULIET_PUB}. - */ - public static final String TEST_MESSAGE_01 = "-----BEGIN PGP MESSAGE-----\n" + - "\n" + - "hQGMAwAAAAAAAAAAAQwAoJtfpcBPCwhUzzHuVIcBzBLyfIWT/EJ527neb46lN56S\n" + - "B05BTIRudIeCsPYz81jwiFi/k0MBecRfozZ1xCPByo8ohSvRgzEHEkCNgObQ1bz0\n" + - "iB+Xb76OEzFOCPUebTaVscLNf8ak/GSzaW7jDc+5vnvDf7cV0x26pe4odpS/U5Tr\n" + - "cO3wb/47K+sJ1cxJmPtcD41O02xu3QisQKPrimM0Kue6ziGeKyw1RkSowv9U47TK\n" + - "wppPCHOTli2Nf+gZizF1oyQZzPGst4fjujygcIoajplfW9nZvxsbmYRSLSdmV9m6\n" + - "k1jQbPDUhVs0gstH92C6hPpoBWxoxkHcwz8gy36nCyB6cYGyq3oN1UnGU4afPyD5\n" + - "SmmEjELBd2i2Ll/DYk2x06SnKZMQuWrSCZzWgl/9HsPo5ydVb97OjuEpWtW9xDMA\n" + - "KlYPNWEq+b+akOEstNraC3pfVKvypz6ZzaMAS1gWWNYg8dlwBJOUVMSo7iLaUQkK\n" + - "yp4uH1DlsyVu1atCUc8thQIMAwAAAAAAAAAAAQ/5AdiZ/sG859Y/rGR7U/8MzGg0\n" + - "j3f2vrgDF/0NRRk5aqd1lb4CaZvrztcYqW3cEK7iF9rKwImZZiWIptjJ9Mz6f1Zl\n" + - "FbODObSVRZAcZqYGswEEfsQvpQFlwG6Qx48OaQaDPr147raFI3C3kEU9Nb2VBg8+\n" + - "MevJaXJft5PXwUTG2Qvfxqr/3hfGAwB4/zHwA8vFd1np3spryfrC9Dq8UXUoRXIS\n" + - "xaFPiLEYt8rLef8f11OypEpmknIibu9jjJtuVZo+SjP6jgLHDwM7rqCZFITM2Qra\n" + - "2iBCt8YVcIiTK137t+EfsdVN/KHiRbc++e9zUbGMEextbtNbdoFOU4dnKBm6Su8l\n" + - "Z5UerNbR8D7+xJKfAEabdi0qI7QFmhTZ/4H/22yrvoD9jMFSBXUTE9ENIX9Hfqom\n" + - "UdsHfuE+5PC0JjkZkhchDO1M7XBX++lBCFsq2abfdpmaX+roVX0iTGboxr5Ag1Cf\n" + - "T2zWyRX/XKnvmdeGICV5qjy/ThuSWvAclazyFxWLamMztJq5BRpfAzKNQRDqlmKw\n" + - "eePtKW2EWUIjFQ5/UAM6Edu/K34ksFxb0w6YGLzQSskGr7gGAipLmpek6vcUSUA1\n" + - "oc9XJGdpx93GDRcqDjKDt/ej06VxG33/pW65ntf5QM/+LScGqaLhAHyEOsBzVIXY\n" + - "BONcadSgzkTrlbSMGAmFAQwDtLUJy1k24D4BB/0brqR0UN1LtO+Lc/vN6X/Um2CZ\n" + - "CM6MRhPnXP63Q9HHkGJ2S8zGWvQLwWL9Y14CFCgm6rACLBSIyPbihhC2OC8afhSy\n" + - "apGkdHtdghS2egs2U8qlJ2Y32IAG9CcUtNkRjxp+/RWSrmZeuL4l7DXCyH5lUadx\n" + - "5bPZhAHqW9408q2rQd9dBg2o7ciGXTJSKVahjuiB/O0gchOnbqnlYJbKbCkntXUo\n" + - "c7h4w1e8MutisSJorh7kbxgxUJSboZzEkiUfnoacPTz6bL+re9tmnpvlee70sIyM\n" + - "BiYRCyPw7Ice4R3XyWtsMTjT/wjZ//whMpWdy2drcJSyhh+GQMbekTVsNWod0lQB\n" + - "JTPUfti2VU7PMB3LjJA+l/T9iWPPx8lirnLhXOOerWKH9I5Wo4Kqv/47aJhfMO6+\n" + - "jmLekAOylq+9DizrslW/EUgQyjIbcWfmyMiV6E2RwbI93tE=\n" + - "=GAhR\n" + - "-----END PGP MESSAGE-----"; -} diff --git a/pgpainless-core/src/test/java/org/pgpainless/TestKeysTest.java b/pgpainless-core/src/test/java/org/pgpainless/TestKeysTest.java deleted file mode 100644 index d9bb0e9e..00000000 --- a/pgpainless-core/src/test/java/org/pgpainless/TestKeysTest.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2018 Paul Schaub. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.pgpainless; - -import static junit.framework.TestCase.assertTrue; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.Collections; - -import junit.framework.TestCase; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRing; -import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; -import org.bouncycastle.util.io.Streams; -import org.junit.Test; -import org.pgpainless.decryption_verification.DecryptionStream; -import org.pgpainless.key.protection.UnprotectedKeysProtector; - -public class TestKeysTest extends AbstractPGPainlessTest { - - private final PGPSecretKeyRing juliet; - private final PGPSecretKeyRing romeo; - - public TestKeysTest() throws IOException, PGPException { - this.juliet = TestKeys.getJulietSecretKeyRing(); - this.romeo = TestKeys.getRomeoSecretKeyRing(); - } - - @Test - public void keyIdTest() { - TestCase.assertEquals(TestKeys.JULIET_KEY_ID, juliet.getSecretKey().getKeyID()); - TestCase.assertEquals(TestKeys.ROMEO_KEY_ID, romeo.getSecretKey().getKeyID()); - } - - @Test - public void decryptVerifyTest() throws Exception { - String encryptedMessage = TestKeys.TEST_MESSAGE_01; - - DecryptionStream decryptor = PGPainless.createDecryptor() - .onInputStream(new ByteArrayInputStream(encryptedMessage.getBytes())) - .decryptWith(new UnprotectedKeysProtector(), new PGPSecretKeyRingCollection(Collections.singleton(juliet))) - .verifyWith(Collections.singleton(new PGPPublicKeyRing(Collections.singletonList(juliet.getPublicKey())))) - .ignoreMissingPublicKeys() - .build(); - - ByteArrayOutputStream toPlain = new ByteArrayOutputStream(); - Streams.pipeAll(decryptor, toPlain); - decryptor.close(); - toPlain.close(); - - byte[] expected = TestKeys.TEST_MESSAGE_01_PLAIN.getBytes(Charset.forName("UTF-8")); - byte[] actual = toPlain.toByteArray(); - - assertTrue(Arrays.equals(expected, actual)); - } -} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index b3ba260c..00000000 --- a/settings.gradle +++ /dev/null @@ -1,4 +0,0 @@ -rootProject.name = 'PGPainless' - -include 'pgpainless-core' - diff --git a/version.gradle b/version.gradle deleted file mode 100644 index f955ae80..00000000 --- a/version.gradle +++ /dev/null @@ -1,9 +0,0 @@ - -allprojects { - ext { - shortVersion = '0.0.1-alpha4' - isSnapshot = true - pgpainlessMinAndroidSdk = 9 - javaSourceCompatibility = 1.8 - } -}