mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-06-28 14:34:49 +02:00
Customize sidebar + delete code
This commit is contained in:
parent
1323b48c7a
commit
8bd760aee5
|
@ -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/
|
201
LICENSE
201
LICENSE
|
@ -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.
|
149
README.md
149
README.md
|
@ -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 <juliet@montague.lit>", 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 <juliet@montague.lit>")
|
||||
.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.
|
|
@ -1 +1,3 @@
|
|||
logo: /assets/logo.png
|
||||
show_downloads: true
|
||||
theme: jekyll-theme-minimal
|
78
_layouts/default.html
Normal file
78
_layouts/default.html
Normal file
|
@ -0,0 +1,78 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="chrome=1">
|
||||
<title>{{ site.title | default: site.github.repository_name }} by {{
|
||||
site.github.owner_name }}</title>
|
||||
|
||||
<link rel="stylesheet" href="{{ '/assets/css/style.css?v=' | append:
|
||||
site.github.build_revision | relative_url }}">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<!--[if lt IE 9]>
|
||||
<script
|
||||
src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrapper">
|
||||
<header>
|
||||
<h1>{{ site.title | default: site.github.repository_name }}</h1>
|
||||
{% if site.logo %}
|
||||
<img src="{{site.logo | relative_url}}" alt="Logo" />
|
||||
{% endif %}
|
||||
<p>{{ site.description | default: site.github.project_tagline
|
||||
}}</p>
|
||||
|
||||
<a href="https://pgpainless.org">Home</a>
|
||||
<br>
|
||||
<a
|
||||
href="https://search.maven.org/search?q=g:org.pgpainless%20AND%20a:pgpainless-core&core=gav">Releases</a>
|
||||
<br>
|
||||
<a
|
||||
href="https://pgpainless.org/releases/0.0.1-alpha3/javadoc/">Javadoc</a>
|
||||
<br>
|
||||
<a
|
||||
href="https://pgpainless.org/releases/0.0.1-alpha3/jacoco/jacocoRootReport/html/">Jacoco</a>
|
||||
<br>
|
||||
|
||||
|
||||
{% if site.github.is_project_page %}
|
||||
<p class="view"><a href="{{ site.github.repository_url
|
||||
}}">View the Project on GitHub <small>{{ github_name }}</small></a></p>
|
||||
{% endif %}
|
||||
|
||||
{% if site.github.is_user_page %}
|
||||
<p class="view"><a href="{{ site.github.owner_url }}">View My
|
||||
GitHub Profile</a></p>
|
||||
{% endif %}
|
||||
|
||||
{% if site.show_downloads %}
|
||||
<ul>
|
||||
<li><a href="{{ site.github.zip_url }}">Download <strong>ZIP
|
||||
File</strong></a></li>
|
||||
<li><a href="{{ site.github.tar_url }}">Download <strong>TAR
|
||||
Ball</strong></a></li>
|
||||
<li><a href="{{ site.github.repository_url }}">View On
|
||||
<strong>GitHub</strong></a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</header>
|
||||
<section>
|
||||
|
||||
{{ content }}
|
||||
|
||||
</section>
|
||||
<footer>
|
||||
{% if site.github.is_project_page %}
|
||||
<p>This project is maintained by <a href="{{
|
||||
site.github.owner_url }}">{{ site.github.owner_name }}</a></p>
|
||||
{% endif %}
|
||||
<p><small>Hosted on GitHub Pages — Theme by <a
|
||||
href="https://github.com/orderedlist">orderedlist</a></small></p>
|
||||
</footer>
|
||||
</div>
|
||||
<script src="{{ '/assets/js/scale.fix.js' | relative_url
|
||||
}}"></script>
|
||||
</body>
|
||||
</html>
|
BIN
assets/logo.png
Normal file
BIN
assets/logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
254
build.gradle
254
build.gradle
|
@ -1,254 +0,0 @@
|
|||
import java.text.SimpleDateFormat
|
||||
|
||||
buildscript {
|
||||
|
||||
repositories {
|
||||
|
||||
maven {
|
||||
url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.kt3k.gradle.plugin:coveralls-gradle-plugin:2.3.1"
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'ru.vyarus.animalsniffer' version '1.4.3'
|
||||
}
|
||||
|
||||
apply from: 'version.gradle'
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'idea'
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'jacoco'
|
||||
apply plugin: 'checkstyle'
|
||||
|
||||
// animalsniffer
|
||||
apply plugin: 'ru.vyarus.animalsniffer'
|
||||
dependencies {
|
||||
signature "net.sf.androidscents.signature:android-api-level-${pgpainlessMinAndroidSdk}:2.3.1_r2@signature"
|
||||
}
|
||||
animalsniffer {
|
||||
sourceSets = [sourceSets.main]
|
||||
}
|
||||
|
||||
// checkstyle
|
||||
checkstyle {
|
||||
configFile = "${project.rootDir}/config/checkstyle.xml" as File
|
||||
toolVersion = '8.10'
|
||||
}
|
||||
|
||||
group 'org.pgpainless'
|
||||
description = "Simple to use OpenPGP API for Java based on Bouncycastle"
|
||||
version = shortVersion
|
||||
|
||||
sourceCompatibility = javaSourceCompatibility
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
project.ext {
|
||||
junitVersion = 4.12
|
||||
androidBootClasspath = getAndroidRuntimeJar(pgpainlessMinAndroidSdk)
|
||||
rootConfigDir = new File(rootDir, 'config')
|
||||
gitCommit = getGitCommit()
|
||||
builtDate = (new SimpleDateFormat("yyyy-MM-dd")).format(new Date())
|
||||
isReleaseVersion = !isSnapshot
|
||||
signingRequired = isReleaseVersion
|
||||
sonatypeCredentialsAvailable = project.hasProperty('sonatypeUsername') && project.hasProperty('sonatypePassword')
|
||||
sonatypeSnapshotUrl = 'https://oss.sonatype.org/content/repositories/snapshots'
|
||||
sonatypeStagingUrl = 'https://oss.sonatype.org/service/local/staging/deploy/maven2'
|
||||
}
|
||||
|
||||
if (isSnapshot) {
|
||||
version = version + '-SNAPSHOT'
|
||||
}
|
||||
|
||||
if (!project.ext.isSnapshot && !'git describe --exact-match HEAD'.execute().text.trim().equals(ext.shortVersion)) {
|
||||
throw new InvalidUserDataException('Untagged version detected! Please tag every release.')
|
||||
}
|
||||
if (!version.endsWith('-SNAPSHOT') && version != 'git tag --points-at HEAD'.execute().text.trim()) {
|
||||
throw new InvalidUserDataException(
|
||||
'Tag mismatch detected, version is ' + version + ' but should be ' +
|
||||
'git tag --points-at HEAD'.execute().text.trim())
|
||||
}
|
||||
|
||||
jacoco {
|
||||
toolVersion = "0.8.1"
|
||||
}
|
||||
|
||||
jacocoTestReport {
|
||||
dependsOn test
|
||||
sourceDirectories = project.files(sourceSets.main.allSource.srcDirs)
|
||||
classDirectories = project.files(sourceSets.main.output)
|
||||
reports {
|
||||
xml.enabled true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
subprojects {
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
task testJar(type: Jar, dependsOn: testClasses) {
|
||||
classifier = 'tests'
|
||||
from sourceSets.test.output
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives sourcesJar
|
||||
archives javadocJar
|
||||
archives testJar
|
||||
}
|
||||
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
if (signingRequired) {
|
||||
beforeDeployment { MavenDeployment deployment -> 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[]
|
||||
}
|
|
@ -1,233 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
|
||||
<module name="Checker">
|
||||
|
||||
<!-- Suppressions -->
|
||||
<module name="SuppressionFilter">
|
||||
<property name="file" value="config/suppressions.xml"/>
|
||||
</module>
|
||||
|
||||
<!-- License Header -->
|
||||
<module name="Header">
|
||||
<property name="headerFile" value="config/checkstyleLicenseHeader.txt"/>
|
||||
<property name="ignoreLines" value="2"/>
|
||||
<property name="fileExtensions" value="java"/>
|
||||
</module>
|
||||
|
||||
<module name="NewlineAtEndOfFile">
|
||||
<property name="lineSeparator" value="lf"/>
|
||||
</module>
|
||||
|
||||
<module name="RegexpSingleline">
|
||||
<!--
|
||||
Matches StringBuilder.append(String) calls where the
|
||||
argument is a String of length one. Those should be replaced
|
||||
with append(char) for performance reasons.
|
||||
|
||||
TODO: This could be more advanced in order to match also
|
||||
- .append("\u1234")
|
||||
-->
|
||||
<property name="format" value="\.append\("(.|\\.)"\)"/>
|
||||
<property name="message" value="Don't use StringBuilder.append(String) when you can use StringBuilder.append(char). Solution: Replace double quotes of append's argument with single quotes."/>
|
||||
</module>
|
||||
|
||||
<!-- Whitespace only lines -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="^\s+$"/>
|
||||
<property name="message" value="Line containing only whitespace character(s)"/>
|
||||
</module>
|
||||
|
||||
<!-- Mixed spaces/tabs -->
|
||||
<module name="RegexpSingleline">
|
||||
<!-- We use {2,} instead of + here to address the typical case where a file was written
|
||||
with tabs but javadoc is causing '\t *' -->
|
||||
<property name="format" value="^\t+ {2,}"/>
|
||||
<property name="message" value="Line containing space(s) after tab(s)"/>
|
||||
</module>
|
||||
|
||||
<!-- Trailing whitespaces -->
|
||||
<module name="RegexpSingleline">
|
||||
<!--
|
||||
Explaining the following Regex
|
||||
|
||||
\s+ $
|
||||
| +- End of Line (2)
|
||||
+- At least one whitespace (1)
|
||||
|
||||
Rationale:
|
||||
Matches trailing whitespace (2) in lines containing at least one (1) non-whitespace character
|
||||
-->
|
||||
<property name="format" value="\s+$"/>
|
||||
<property name="message" value="Line containing trailing whitespace character(s)"/>
|
||||
</module>
|
||||
|
||||
<!-- <module name="RegexpSingleline"> -->
|
||||
<!-- <property name="format" value="fqdn"/> -->
|
||||
<!-- </module> -->
|
||||
|
||||
<!-- Space after // -->
|
||||
<module name="RegexpSingleline">
|
||||
<property name="format" value="^\s*//[^\s]"/>
|
||||
<property name="message" value="Comment start ('//') followed by non-space character. You would not continue after a punctuation without a space, would you?"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocPackage">
|
||||
</module>
|
||||
|
||||
<module name="TreeWalker">
|
||||
<module name="SuppressionCommentFilter"/>
|
||||
<module name="FinalClass"/>
|
||||
<module name="UnusedImports">
|
||||
<property name="processJavadoc" value="true"/>
|
||||
</module>
|
||||
<module name="AvoidStarImport"/>
|
||||
<module name="IllegalImport"/>
|
||||
<module name="RedundantImport"/>
|
||||
<module name="RedundantModifier"/>
|
||||
<module name="ModifierOrder"/>
|
||||
<module name="UpperEll"/>
|
||||
<module name="ArrayTypeStyle"/>
|
||||
<module name="GenericWhitespace"/>
|
||||
<module name="EmptyStatement"/>
|
||||
<module name="PackageDeclaration"/>
|
||||
<module name="LeftCurly"/>
|
||||
|
||||
<!-- printStackTrace -->
|
||||
<module name="RegexpSinglelineJava">
|
||||
<property name="format" value="printStackTrace"/>
|
||||
<property name="message" value="Usage of printStackTrace. Either rethrow exception, or log using Logger."/>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- println -->
|
||||
<module name="RegexpSinglelineJava">
|
||||
<property name="format" value="println"/>
|
||||
<property name="message" value="Usage of println"/>
|
||||
<property name="ignoreComments" value="true"/>
|
||||
</module>
|
||||
|
||||
<!-- Spaces instead of Tabs -->
|
||||
<module name="RegexpSinglelineJava">
|
||||
<property name="format" value="^\t+"/>
|
||||
<property name="message" value="Indent must not use tab characters. Use space instead."/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocMethod">
|
||||
<!-- TODO stricten those checks -->
|
||||
<property name="scope" value="public"/>
|
||||
<property name="allowUndeclaredRTE" value="true"/>
|
||||
<property name="allowMissingParamTags" value="true"/>
|
||||
<property name="allowMissingThrowsTags" value="true"/>
|
||||
<property name="allowMissingReturnTag" value="true"/>
|
||||
<property name="allowMissingJavadoc" value="true"/>
|
||||
<property name="suppressLoadErrors" value="true"/>
|
||||
</module>
|
||||
|
||||
<module name="JavadocStyle">
|
||||
<property name="scope" value="public"/>
|
||||
<property name="checkEmptyJavadoc" value="true"/>
|
||||
<property name="checkHtml" value="false"/>
|
||||
</module>
|
||||
|
||||
<module name="ParenPad">
|
||||
</module>
|
||||
|
||||
<!-- Whitespace after key tokens -->
|
||||
<module name="NoWhitespaceAfter">
|
||||
<property name="tokens" value="INC
|
||||
, DEC
|
||||
, UNARY_MINUS
|
||||
, UNARY_PLUS
|
||||
, BNOT, LNOT
|
||||
, DOT
|
||||
, ARRAY_DECLARATOR
|
||||
, INDEX_OP
|
||||
"/>
|
||||
</module>
|
||||
|
||||
<!-- Whitespace after key words -->
|
||||
<module name="WhitespaceAfter">
|
||||
<property name="tokens" value="TYPECAST
|
||||
, LITERAL_IF
|
||||
, LITERAL_ELSE
|
||||
, LITERAL_WHILE
|
||||
, LITERAL_DO
|
||||
, LITERAL_FOR
|
||||
, DO_WHILE
|
||||
"/>
|
||||
</module>
|
||||
|
||||
<module name="WhitespaceAround">
|
||||
<property
|
||||
name="ignoreEnhancedForColon"
|
||||
value="false"
|
||||
/>
|
||||
<!-- Currently disabled tokens: LCURLY, RCURLY, WILDCARD_TYPE, GENERIC_START, GENERIC_END -->
|
||||
<property
|
||||
name="tokens"
|
||||
value="ASSIGN
|
||||
, ARRAY_INIT
|
||||
, BAND
|
||||
, BAND_ASSIGN
|
||||
, BOR
|
||||
, BOR_ASSIGN
|
||||
, BSR
|
||||
, BSR_ASSIGN
|
||||
, BXOR
|
||||
, BXOR_ASSIGN
|
||||
, COLON
|
||||
, DIV
|
||||
, DIV_ASSIGN
|
||||
, DO_WHILE
|
||||
, EQUAL
|
||||
, GE
|
||||
, GT
|
||||
, LAMBDA
|
||||
, LAND
|
||||
, LE
|
||||
, LITERAL_CATCH
|
||||
, LITERAL_DO
|
||||
, LITERAL_ELSE
|
||||
, LITERAL_FINALLY
|
||||
, LITERAL_FOR
|
||||
, LITERAL_IF
|
||||
, LITERAL_RETURN
|
||||
, LITERAL_SWITCH
|
||||
, LITERAL_SYNCHRONIZED
|
||||
, LITERAL_TRY
|
||||
, LITERAL_WHILE
|
||||
, LOR
|
||||
, LT
|
||||
, MINUS
|
||||
, MINUS_ASSIGN
|
||||
, MOD
|
||||
, MOD_ASSIGN
|
||||
, NOT_EQUAL
|
||||
, PLUS
|
||||
, PLUS_ASSIGN
|
||||
, QUESTION
|
||||
, SL
|
||||
, SLIST
|
||||
, SL_ASSIGN
|
||||
, SR
|
||||
, SR_ASSIGN
|
||||
, STAR
|
||||
, STAR_ASSIGN
|
||||
, LITERAL_ASSERT
|
||||
, TYPE_EXTENSION_AND
|
||||
"/>
|
||||
</module>
|
||||
|
||||
<!--
|
||||
<module name="CustomImportOrder">
|
||||
<property name="customImportOrderRules"
|
||||
value="STATIC###STANDARD_JAVA_PACKAGE###SPECIAL_IMPORTS###THIRD_PARTY_PACKAGE"/>
|
||||
<property name="specialImportsRegExp" value="^org\.org.pgpainless.core\.org.pgpainless.core"/>
|
||||
<property name="sortImportsInGroupAlphabetically" value="true"/>
|
||||
<property name="separateLineBetweenGroups" value="true"/>
|
||||
</module>
|
||||
-->
|
||||
</module>
|
||||
</module>
|
|
@ -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.
|
||||
*/
|
|
@ -1,13 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
|
||||
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
|
||||
<suppressions>
|
||||
<!-- GenericWhitespace has some problems with false postive, leave
|
||||
it disabled until gradle uses a checkstyle version where this is fixed
|
||||
-->
|
||||
<suppress checks="GenericWhitespace"
|
||||
files="Protocol.java" />
|
||||
<!-- Suppress JavadocPackage in the test packages -->
|
||||
<suppress checks="JavadocPackage" files="[\\/]test[\\/]"/>
|
||||
</suppressions>
|
|
@ -1 +0,0 @@
|
|||
www.pgpainless.org
|
|
@ -1 +0,0 @@
|
|||
theme: jekyll-theme-slate
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
vendored
6
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +0,0 @@
|
|||
#Sat Jun 02 23:06:04 CEST 2018
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip
|
172
gradlew
vendored
172
gradlew
vendored
|
@ -1,172 +0,0 @@
|
|||
#!/usr/bin/env sh
|
||||
|
||||
##############################################################################
|
||||
##
|
||||
## Gradle start up script for UN*X
|
||||
##
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
# Need this for relative symlinks.
|
||||
while [ -h "$PRG" ] ; do
|
||||
ls=`ls -ld "$PRG"`
|
||||
link=`expr "$ls" : '.*-> \(.*\)$'`
|
||||
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" "$@"
|
84
gradlew.bat
vendored
84
gradlew.bat
vendored
|
@ -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
|
|
@ -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'
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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<SymmetricKeyAlgorithm> symmetricKeyAlgorithms;
|
||||
private List<HashAlgorithm> hashAlgorithms;
|
||||
private List<CompressionAlgorithm> compressionAlgorithms;
|
||||
|
||||
public AlgorithmSuite(List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms,
|
||||
List<HashAlgorithm> hashAlgorithms,
|
||||
List<CompressionAlgorithm> compressionAlgorithms) {
|
||||
this.symmetricKeyAlgorithms = Collections.unmodifiableList(symmetricKeyAlgorithms);
|
||||
this.hashAlgorithms = Collections.unmodifiableList(hashAlgorithms);
|
||||
this.compressionAlgorithms = Collections.unmodifiableList(compressionAlgorithms);
|
||||
}
|
||||
|
||||
public void setSymmetricKeyAlgorithms(List<SymmetricKeyAlgorithm> symmetricKeyAlgorithms) {
|
||||
this.symmetricKeyAlgorithms = symmetricKeyAlgorithms;
|
||||
}
|
||||
|
||||
public List<SymmetricKeyAlgorithm> 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<HashAlgorithm> hashAlgorithms) {
|
||||
this.hashAlgorithms = hashAlgorithms;
|
||||
}
|
||||
|
||||
public List<HashAlgorithm> 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<CompressionAlgorithm> compressionAlgorithms) {
|
||||
this.compressionAlgorithms = compressionAlgorithms;
|
||||
}
|
||||
|
||||
public List<CompressionAlgorithm> 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;
|
||||
}
|
||||
}
|
|
@ -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<Integer, CompressionAlgorithm> 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;
|
||||
}
|
||||
}
|
|
@ -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 <a href="https://tools.ietf.org/html/rfc4880#section-5.14">
|
||||
* RFC-4880 §5.14: Modification Detection Code Packet</a>
|
||||
*/
|
||||
MODIFICATION_DETECTION(Features.FEATURE_MODIFICATION_DETECTION),
|
||||
;
|
||||
|
||||
private static final Map<Byte, Feature> 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;
|
||||
}
|
||||
}
|
|
@ -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<Integer, HashAlgorithm> 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;
|
||||
}
|
||||
}
|
|
@ -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<KeyFlag> fromInteger(int bitmask) {
|
||||
List<KeyFlag> flags = new ArrayList<>();
|
||||
for (KeyFlag f : KeyFlag.values()) {
|
||||
if ((bitmask & f.flag) != 0) {
|
||||
flags.add(f);
|
||||
}
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
}
|
|
@ -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<Integer, PublicKeyAlgorithm> 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;
|
||||
}
|
||||
}
|
|
@ -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<Integer, SymmetricKeyAlgorithm> 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<PGPPublicKeyRing> 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<PGPPublicKeyRing> publicKeyRings = new HashSet<>();
|
||||
for (Iterator<PGPPublicKeyRing> i = publicKeyRingCollection.getKeyRings(); i.hasNext(); ) {
|
||||
publicKeyRings.add(i.next());
|
||||
}
|
||||
return verifyWith(publicKeyRings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HandleMissingPublicKeys verifyWith(@Nonnull Set<OpenPgpV4Fingerprint> trustedKeyIds,
|
||||
@Nonnull PGPPublicKeyRingCollection publicKeyRingCollection) {
|
||||
Set<PGPPublicKeyRing> publicKeyRings = new HashSet<>();
|
||||
for (Iterator<PGPPublicKeyRing> 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<PGPPublicKeyRing> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<OpenPgpV4Fingerprint> trustedFingerprints, @Nonnull PGPPublicKeyRingCollection publicKeyRings);
|
||||
|
||||
HandleMissingPublicKeys verifyWith(@Nonnull Set<PGPPublicKeyRing> publicKeyRings);
|
||||
|
||||
Build doNotVerify();
|
||||
|
||||
}
|
||||
|
||||
interface HandleMissingPublicKeys {
|
||||
|
||||
Build handleMissingPublicKeysWith(@Nonnull MissingPublicKeyCallback callback);
|
||||
|
||||
Build ignoreMissingPublicKeys();
|
||||
}
|
||||
|
||||
interface Build {
|
||||
|
||||
DecryptionStream build() throws IOException, PGPException;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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<PGPPublicKeyRing> 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<OpenPgpV4Fingerprint, PGPOnePassSignature> verifiableOnePassSignatures = new HashMap<>();
|
||||
|
||||
private DecryptionStreamFactory(@Nullable PGPSecretKeyRingCollection decryptionKeys,
|
||||
@Nullable SecretKeyRingProtector decryptor,
|
||||
@Nullable Set<PGPPublicKeyRing> 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<PGPPublicKeyRing> 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<PGPOnePassSignature> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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<Long> recipientKeyIds;
|
||||
private final OpenPgpV4Fingerprint decryptionFingerprint;
|
||||
private final Set<Long> unverifiedSignatureKeyIds;
|
||||
private final Set<OpenPgpV4Fingerprint> verifiedSignaturesFingerprints;
|
||||
|
||||
private final SymmetricKeyAlgorithm symmetricKeyAlgorithm;
|
||||
private final CompressionAlgorithm compressionAlgorithm;
|
||||
private final boolean integrityProtected;
|
||||
|
||||
public OpenPgpMetadata(Set<Long> recipientKeyIds,
|
||||
OpenPgpV4Fingerprint decryptionFingerprint,
|
||||
SymmetricKeyAlgorithm symmetricKeyAlgorithm,
|
||||
CompressionAlgorithm algorithm,
|
||||
boolean integrityProtected,
|
||||
Set<Long> unverifiedSignatureKeyIds,
|
||||
Set<OpenPgpV4Fingerprint> 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<Long> 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<Long> getAllSignatureKeyFingerprints() {
|
||||
return unverifiedSignatureKeyIds;
|
||||
}
|
||||
|
||||
public boolean isSigned() {
|
||||
return !unverifiedSignatureKeyIds.isEmpty();
|
||||
}
|
||||
|
||||
public Set<OpenPgpV4Fingerprint> 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<Long> recipientFingerprints = new HashSet<>();
|
||||
private OpenPgpV4Fingerprint decryptionFingerprint;
|
||||
private final Set<Long> unverifiedSignatureKeyIds = new HashSet<>();
|
||||
private final Set<OpenPgpV4Fingerprint> 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<OpenPgpV4Fingerprint, PGPOnePassSignature> onePassSignatures;
|
||||
private final OpenPgpMetadata.Builder resultBuilder;
|
||||
|
||||
private boolean validated = false;
|
||||
|
||||
protected SignatureVerifyingInputStream(@Nonnull InputStream inputStream,
|
||||
@Nonnull PGPObjectFactory objectFactory,
|
||||
@Nonnull Map<OpenPgpV4Fingerprint, PGPOnePassSignature> 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<PGPPublicKey> encryptionKeys = new HashSet<>();
|
||||
private final Set<PGPSecretKey> 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 <O> WithAlgorithms toRecipients(@Nonnull PublicKeyRingSelectionStrategy<O> ringSelectionStrategy,
|
||||
@Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys) {
|
||||
if (keys.isEmpty()) {
|
||||
throw new IllegalArgumentException("Recipient map MUST NOT be empty.");
|
||||
}
|
||||
MultiMap<O, PGPPublicKeyRing> acceptedKeyRings = ringSelectionStrategy.selectKeyRingsFromCollections(keys);
|
||||
for (O identifier : acceptedKeyRings.keySet()) {
|
||||
Set<PGPPublicKeyRing> 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<PGPPublicKey> 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<PGPPublicKey> i = ring.getPublicKeys(); i.hasNext(); ) {
|
||||
PGPPublicKey key = i.next();
|
||||
if (encryptionKeySelector().accept(null, key)) {
|
||||
EncryptionBuilder.this.encryptionKeys.add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <O> WithAlgorithms andToSelf(@Nonnull PublicKeyRingSelectionStrategy<O> ringSelectionStrategy,
|
||||
@Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys) {
|
||||
if (keys.isEmpty()) {
|
||||
throw new IllegalArgumentException("Recipient list MUST NOT be empty.");
|
||||
}
|
||||
MultiMap<O, PGPPublicKeyRing> acceptedKeyRings =
|
||||
ringSelectionStrategy.selectKeyRingsFromCollections(keys);
|
||||
for (O identifier : acceptedKeyRings.keySet()) {
|
||||
Set<PGPPublicKeyRing> acceptedSet = acceptedKeyRings.get(identifier);
|
||||
for (PGPPublicKeyRing k : acceptedSet) {
|
||||
for (Iterator<PGPPublicKey> 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 <O> 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.<O>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 <O> 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<PGPSecretKey> i = key.getSecretKeys(); i.hasNext(); ) {
|
||||
PGPSecretKey s = i.next();
|
||||
if (EncryptionBuilder.this.<O>signingKeySelector().accept(null, s)) {
|
||||
EncryptionBuilder.this.signingKeys.add(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
EncryptionBuilder.this.signingKeysDecryptor = decryptor;
|
||||
return new ArmorImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <O> Armor signWith(@Nonnull SecretKeyRingSelectionStrategy<O> ringSelectionStrategy,
|
||||
@Nonnull SecretKeyRingProtector decryptor,
|
||||
@Nonnull MultiMap<O, PGPSecretKeyRingCollection> keys) {
|
||||
if (keys.isEmpty()) {
|
||||
throw new IllegalArgumentException("Recipient list MUST NOT be empty.");
|
||||
}
|
||||
MultiMap<O, PGPSecretKeyRing> acceptedKeyRings =
|
||||
ringSelectionStrategy.selectKeyRingsFromCollections(keys);
|
||||
for (O identifier : acceptedKeyRings.keySet()) {
|
||||
Set<PGPSecretKeyRing> acceptedSet = acceptedKeyRings.get(identifier);
|
||||
for (PGPSecretKeyRing k : acceptedSet) {
|
||||
for (Iterator<PGPSecretKey> i = k.getSecretKeys(); i.hasNext(); ) {
|
||||
PGPSecretKey s = i.next();
|
||||
if (EncryptionBuilder.this.<O>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<PGPPrivateKey> 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);
|
||||
}
|
||||
}
|
||||
|
||||
<O> PublicKeySelectionStrategy<O> encryptionKeySelector() {
|
||||
return new And.PubKeySelectionStrategy<>(
|
||||
new NoRevocation.PubKeySelectionStrategy<>(),
|
||||
new EncryptionKeySelectionStrategy<>());
|
||||
}
|
||||
|
||||
<O> SecretKeySelectionStrategy<O> signingKeySelector() {
|
||||
return new And.SecKeySelectionStrategy<>(
|
||||
new NoRevocation.SecKeySelectionStrategy<>(),
|
||||
new SignatureKeySelectionStrategy<>());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
<O> WithAlgorithms toRecipients(@Nonnull PublicKeyRingSelectionStrategy<O> selectionStrategy,
|
||||
@Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys);
|
||||
|
||||
SignWith doNotEncrypt();
|
||||
|
||||
}
|
||||
|
||||
interface WithAlgorithms {
|
||||
|
||||
WithAlgorithms andToSelf(@Nonnull PGPPublicKey... keys);
|
||||
|
||||
WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRing... keys);
|
||||
|
||||
WithAlgorithms andToSelf(@Nonnull PGPPublicKeyRingCollection keys);
|
||||
|
||||
<O> WithAlgorithms andToSelf(@Nonnull PublicKeyRingSelectionStrategy<O> selectionStrategy,
|
||||
@Nonnull MultiMap<O, PGPPublicKeyRingCollection> keys);
|
||||
|
||||
SignWith usingAlgorithms(@Nonnull SymmetricKeyAlgorithm symmetricKeyAlgorithm,
|
||||
@Nonnull HashAlgorithm hashAlgorithm,
|
||||
@Nonnull CompressionAlgorithm compressionAlgorithm);
|
||||
|
||||
SignWith usingSecureAlgorithms();
|
||||
|
||||
}
|
||||
|
||||
interface SignWith {
|
||||
|
||||
<O> Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKey... keys);
|
||||
|
||||
<O> Armor signWith(@Nonnull SecretKeyRingProtector decryptor, @Nonnull PGPSecretKeyRing... keyRings);
|
||||
|
||||
<O> Armor signWith(@Nonnull SecretKeyRingSelectionStrategy<O> selectionStrategy,
|
||||
@Nonnull SecretKeyRingProtector decryptor,
|
||||
@Nonnull MultiMap<O, PGPSecretKeyRingCollection> keys)
|
||||
throws SecretKeyNotFoundException;
|
||||
|
||||
Armor doNotSign();
|
||||
|
||||
}
|
||||
|
||||
interface Armor {
|
||||
|
||||
EncryptionStream asciiArmor() throws IOException, PGPException;
|
||||
|
||||
EncryptionStream noArmor() throws IOException, PGPException;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <a href="https://github.com/neuhalje/bouncy-gpg/blob/master/src/main/java/name/neuhalfen/projects/crypto/bouncycastle/openpgp/encrypting/PGPEncryptingStream.java">Source</a>
|
||||
*/
|
||||
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<PGPSignatureGenerator> 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<PGPPublicKey> encryptionKeys,
|
||||
@Nonnull Set<PGPPrivateKey> 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<Long> recipientKeyIds = new HashSet<>();
|
||||
for (PGPPublicKey recipient : encryptionKeys) {
|
||||
recipientKeyIds.add(recipient.getKeyID());
|
||||
}
|
||||
|
||||
Set<Long> 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<OpenPgpV4Fingerprint> {
|
||||
|
||||
private final String fingerprint;
|
||||
|
||||
/**
|
||||
* Create an {@link OpenPgpV4Fingerprint}.
|
||||
* @see <a href="https://xmpp.org/extensions/xep-0373.html#annoucning-pubkey">
|
||||
* XEP-0373 §4.1: The OpenPGP Public-Key Data Node about how to obtain the fingerprint</a>
|
||||
* @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 <a href="https://tools.ietf.org/html/rfc4880#section-12.2">
|
||||
* RFC-4880 §12.2: Key IDs and Fingerprints</a>
|
||||
* @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);
|
||||
}
|
||||
}
|
|
@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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<KeySpec> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <a href="https://www.ietf.org/rfc/rfc3526.txt">
|
||||
* RFC-3526: More Modular Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange (IKE)</a>
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<Long, Passphrase> cache = new HashMap<>();
|
||||
private final SecretKeyRingProtector protector;
|
||||
private final SecretKeyPassphraseProvider provider;
|
||||
|
||||
public PassphraseMapKeyRingProtector(@Nonnull Map<Long, Passphrase> 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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 <K> Type of the Key
|
||||
* @param <R> Type of the PGPKeyRing
|
||||
* @param <O> Type that describes the owner of this key
|
||||
*/
|
||||
public interface KeySelectionStrategy<K, R, O> {
|
||||
|
||||
boolean accept(O identifier, K key);
|
||||
|
||||
Set<K> selectKeysFromKeyRing(O identifier, @Nonnull R ring);
|
||||
|
||||
MultiMap<O, K> selectKeysFromKeyRings(MultiMap<O, R> rings);
|
||||
|
||||
}
|
|
@ -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 <O> Type that describes the owner of the key.
|
||||
*/
|
||||
public abstract class PublicKeySelectionStrategy<O> implements KeySelectionStrategy<PGPPublicKey, PGPPublicKeyRing, O> {
|
||||
|
||||
@Override
|
||||
public Set<PGPPublicKey> selectKeysFromKeyRing(O identifier, @Nonnull PGPPublicKeyRing ring) {
|
||||
Set<PGPPublicKey> keys = new HashSet<>();
|
||||
for (Iterator<PGPPublicKey> i = ring.getPublicKeys(); i.hasNext(); ) {
|
||||
PGPPublicKey key = i.next();
|
||||
if (accept(identifier, key)) keys.add(key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiMap<O, PGPPublicKey> selectKeysFromKeyRings(@Nonnull MultiMap<O, PGPPublicKeyRing> keyRings) {
|
||||
MultiMap<O, PGPPublicKey> keys = new MultiMap<>();
|
||||
for (O identifier : keyRings.keySet()) {
|
||||
for (PGPPublicKeyRing ring : keyRings.get(identifier)) {
|
||||
keys.put(identifier, selectKeysFromKeyRing(identifier, ring));
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
|
@ -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 <O> Type that describes the owner of the key.
|
||||
*/
|
||||
public abstract class SecretKeySelectionStrategy<O> implements KeySelectionStrategy<PGPSecretKey, PGPSecretKeyRing, O> {
|
||||
|
||||
@Override
|
||||
public Set<PGPSecretKey> selectKeysFromKeyRing(O identifier, @Nonnull PGPSecretKeyRing ring) {
|
||||
Set<PGPSecretKey> keys = new HashSet<>();
|
||||
for (Iterator<PGPSecretKey> i = ring.getSecretKeys(); i.hasNext(); ) {
|
||||
PGPSecretKey key = i.next();
|
||||
if (accept(identifier, key)) keys.add(key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiMap<O, PGPSecretKey> selectKeysFromKeyRings(@Nonnull MultiMap<O, PGPSecretKeyRing> keyRings) {
|
||||
MultiMap<O, PGPSecretKey> keys = new MultiMap<>();
|
||||
for (O identifier : keyRings.keySet()) {
|
||||
for (PGPSecretKeyRing ring : keyRings.get(identifier)) {
|
||||
keys.put(identifier, selectKeysFromKeyRing(identifier, ring));
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
|
@ -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<O> extends PublicKeySelectionStrategy<O> {
|
||||
|
||||
private final PublicKeySelectionStrategy<O> left;
|
||||
private final PublicKeySelectionStrategy<O> right;
|
||||
|
||||
public PubKeySelectionStrategy(@Nonnull PublicKeySelectionStrategy<O> left,
|
||||
@Nonnull PublicKeySelectionStrategy<O> 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<O> extends SecretKeySelectionStrategy<O> {
|
||||
|
||||
private final SecretKeySelectionStrategy<O> left;
|
||||
private final SecretKeySelectionStrategy<O> right;
|
||||
|
||||
public SecKeySelectionStrategy(@Nonnull SecretKeySelectionStrategy<O> left,
|
||||
@Nonnull SecretKeySelectionStrategy<O> right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, PGPSecretKey key) {
|
||||
return left.accept(identifier, key) && right.accept(identifier, key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <O> Type that describes the owner of the key (not used for decision).
|
||||
*/
|
||||
public class EncryptionKeySelectionStrategy<O> extends PublicKeySelectionStrategy<O> {
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, @Nonnull PGPPublicKey key) {
|
||||
return key.isEncryptionKey();
|
||||
}
|
||||
}
|
|
@ -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 <O> Type that describes the owner of this key (not used for this decision).
|
||||
*/
|
||||
public static class PubKeySelectionStrategy<O> extends PublicKeySelectionStrategy<O> {
|
||||
|
||||
@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 <O> Type that describes the owner of this key (not used for this decision).
|
||||
*/
|
||||
public static class SecKeySelectionStrategy<O> extends SecretKeySelectionStrategy<O> {
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, @Nonnull PGPSecretKey key) {
|
||||
return !key.getPublicKey().hasRevocation();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<O> extends PublicKeySelectionStrategy<O> {
|
||||
|
||||
private final PublicKeySelectionStrategy<O> left;
|
||||
private final PublicKeySelectionStrategy<O> right;
|
||||
|
||||
public PubKeySelectionStrategy(@Nonnull PublicKeySelectionStrategy<O> left,
|
||||
@Nonnull PublicKeySelectionStrategy<O> 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<O> extends SecretKeySelectionStrategy<O> {
|
||||
|
||||
private final SecretKeySelectionStrategy<O> left;
|
||||
private final SecretKeySelectionStrategy<O> right;
|
||||
|
||||
public SecKeySelectionStrategy(@Nonnull SecretKeySelectionStrategy<O> left,
|
||||
@Nonnull SecretKeySelectionStrategy<O> right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, PGPSecretKey key) {
|
||||
return left.accept(identifier, key) || right.accept(identifier, key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <O> Type that describes the owner of the key (not used for this decision).
|
||||
*/
|
||||
public class SignatureKeySelectionStrategy<O> extends SecretKeySelectionStrategy<O> {
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, @Nonnull PGPSecretKey key) {
|
||||
return key.isSigningKey();
|
||||
}
|
||||
|
||||
}
|
|
@ -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<PGPPublicKey> {
|
||||
|
||||
@Override
|
||||
public boolean accept(PGPPublicKey masterKey, @Nonnull PGPPublicKey key) {
|
||||
// Same key -> accept
|
||||
if (Arrays.equals(masterKey.getFingerprint(), key.getFingerprint())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Iterator<PGPSignature> 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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<R, C, O> {
|
||||
|
||||
boolean accept(O identifier, R keyRing);
|
||||
|
||||
Set<R> selectKeyRingsFromCollection(O identifier, C keyRingCollection);
|
||||
|
||||
MultiMap<O, R> selectKeyRingsFromCollections(MultiMap<O, C> keyRingCollections);
|
||||
}
|
|
@ -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<O> implements KeyRingSelectionStrategy<PGPPublicKeyRing, PGPPublicKeyRingCollection, O> {
|
||||
|
||||
@Override
|
||||
public Set<PGPPublicKeyRing> selectKeyRingsFromCollection(@Nonnull O identifier, @Nonnull PGPPublicKeyRingCollection keyRingCollection) {
|
||||
Set<PGPPublicKeyRing> accepted = new HashSet<>();
|
||||
for (Iterator<PGPPublicKeyRing> i = keyRingCollection.getKeyRings(); i.hasNext(); ) {
|
||||
PGPPublicKeyRing ring = i.next();
|
||||
if (accept(identifier, ring)) accepted.add(ring);
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiMap<O, PGPPublicKeyRing> selectKeyRingsFromCollections(@Nonnull MultiMap<O, PGPPublicKeyRingCollection> keyRingCollections) {
|
||||
MultiMap<O, PGPPublicKeyRing> keyRings = new MultiMap<>();
|
||||
for (O identifier : keyRingCollections.keySet()) {
|
||||
for (PGPPublicKeyRingCollection collection : keyRingCollections.get(identifier)) {
|
||||
keyRings.put(identifier, selectKeyRingsFromCollection(identifier, collection));
|
||||
}
|
||||
}
|
||||
return keyRings;
|
||||
}
|
||||
}
|
|
@ -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<O> implements KeyRingSelectionStrategy<PGPSecretKeyRing, PGPSecretKeyRingCollection, O> {
|
||||
@Override
|
||||
public Set<PGPSecretKeyRing> selectKeyRingsFromCollection(O identifier, @Nonnull PGPSecretKeyRingCollection keyRingCollection) {
|
||||
Set<PGPSecretKeyRing> accepted = new HashSet<>();
|
||||
for (Iterator<PGPSecretKeyRing> i = keyRingCollection.getKeyRings(); i.hasNext(); ) {
|
||||
PGPSecretKeyRing ring = i.next();
|
||||
if (accept(identifier, ring)) accepted.add(ring);
|
||||
}
|
||||
return accepted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MultiMap<O, PGPSecretKeyRing> selectKeyRingsFromCollections(@Nonnull MultiMap<O, PGPSecretKeyRingCollection> keyRingCollections) {
|
||||
MultiMap<O, PGPSecretKeyRing> keyRings = new MultiMap<>();
|
||||
for (O identifier : keyRingCollections.keySet()) {
|
||||
for (PGPSecretKeyRingCollection collection : keyRingCollections.get(identifier)) {
|
||||
keyRings.put(identifier, selectKeyRingsFromCollection(identifier, collection));
|
||||
}
|
||||
}
|
||||
return keyRings;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<String> {
|
||||
|
||||
@Override
|
||||
public boolean accept(String identifier, PGPPublicKeyRing keyRing) {
|
||||
Iterator<String> userIds = keyRing.getPublicKey().getUserIDs();
|
||||
while (userIds.hasNext()) {
|
||||
if (userIds.next().equals(identifier)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SecRingSelectionStrategy extends SecretKeyRingSelectionStrategy<String> {
|
||||
|
||||
@Override
|
||||
public boolean accept(String identifier, PGPSecretKeyRing keyRing) {
|
||||
Iterator<String> userIds = keyRing.getPublicKey().getUserIDs();
|
||||
while (userIds.hasNext()) {
|
||||
if (userIds.next().equals(identifier)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<String> {
|
||||
|
||||
@Override
|
||||
public boolean accept(String identifier, @Nonnull PGPPublicKey key) {
|
||||
for (Iterator<String> userIds = key.getUserIDs(); userIds.hasNext(); ) {
|
||||
String userId = userIds.next();
|
||||
if (userId.contains(identifier)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SecRingSelectionStrategy extends SecretKeySelectionStrategy<String> {
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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<O> extends PublicKeyRingSelectionStrategy<O> {
|
||||
|
||||
private final MultiMap<O, Long> whitelist;
|
||||
|
||||
public PubRingSelectionStrategy(MultiMap<O, Long> whitelist) {
|
||||
this.whitelist = whitelist;
|
||||
}
|
||||
|
||||
public PubRingSelectionStrategy(Map<O, Set<Long>> whitelist) {
|
||||
this.whitelist = new MultiMap<>(whitelist);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, PGPPublicKeyRing keyRing) {
|
||||
Set<Long> whitelistedKeyIds = whitelist.get(identifier);
|
||||
|
||||
if (whitelistedKeyIds == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return whitelistedKeyIds.contains(keyRing.getPublicKey().getKeyID());
|
||||
}
|
||||
}
|
||||
|
||||
public static class SecRingSelectionStrategy<O> extends SecretKeyRingSelectionStrategy<O> {
|
||||
|
||||
private final MultiMap<O, Long> whitelist;
|
||||
|
||||
public SecRingSelectionStrategy(MultiMap<O, Long> whitelist) {
|
||||
this.whitelist = whitelist;
|
||||
}
|
||||
|
||||
public SecRingSelectionStrategy(Map<O, Set<Long>> whitelist) {
|
||||
this.whitelist = new MultiMap<>(whitelist);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, PGPSecretKeyRing keyRing) {
|
||||
Set<Long> whitelistedKeyIds = whitelist.get(identifier);
|
||||
|
||||
if (whitelistedKeyIds == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return whitelistedKeyIds.contains(keyRing.getPublicKey().getKeyID());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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<O> extends PublicKeyRingSelectionStrategy<O> {
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, PGPPublicKeyRing keyRing) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class SecRingSelectionStrategy<O> extends SecretKeyRingSelectionStrategy<O> {
|
||||
|
||||
@Override
|
||||
public boolean accept(O identifier, PGPSecretKeyRing keyRing) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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;
|
|
@ -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 <a href="http://pgpainless.org">org.pgpainless.core.org</a>
|
||||
*/
|
||||
package org.pgpainless;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue