1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-06-25 04:54:49 +02:00

Customize sidebar + delete code

This commit is contained in:
Paul Schaub 2018-08-13 23:46:07 +02:00
parent 1323b48c7a
commit 8bd760aee5
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
120 changed files with 81 additions and 8566 deletions

View file

@ -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
View file

@ -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
View file

@ -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.

View file

@ -1 +1,3 @@
theme: jekyll-theme-minimal
logo: /assets/logo.png
show_downloads: true
theme: jekyll-theme-minimal

78
_layouts/default.html Normal file
View 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 &mdash; 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -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[]
}

View file

@ -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\(&quot;(.|\\.)&quot;\)"/>
<property name="message" value="Don&apos;t use StringBuilder.append(String) when you can use StringBuilder.append(char). Solution: Replace double quotes of append&apos;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>

View file

@ -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.
*/

View file

@ -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>

View file

@ -1 +0,0 @@
www.pgpainless.org

View file

@ -1 +0,0 @@
theme: jekyll-theme-slate

Binary file not shown.

View file

@ -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
View file

@ -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
View file

@ -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

View file

@ -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'
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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);
}
}
}

View file

@ -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);
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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<>());
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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!");
}
}
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;
}
}
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}

View file

@ -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;

View file

@ -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());
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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());
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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;
}
}

View file

@ -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;

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}

View file

@ -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();
}
}
}

View file

@ -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);
}
}
}

View file

@ -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();
}
}

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}
}
}

View file

@ -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;
}
}
}

View file

@ -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;
}
}
}

View file

@ -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());
}
}
}

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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;

View file

@ -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;

View file

@ -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