mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-09 18:29:39 +02:00
Compare commits
76 commits
Author | SHA1 | Date | |
---|---|---|---|
0fe3a7abf6 | |||
0d807cb6b8 | |||
9b0a3cd4c7 | |||
0ee31b232a | |||
f2cbde43be | |||
4cf6c6b16a | |||
0f54cc615c | |||
a74db2d26d | |||
|
5f30df6d16 | ||
7953ade136 | |||
0649c041cd | |||
5a413f53a4 | |||
3b92ccc59d | |||
83613250ef | |||
05c84835e6 | |||
d20a3b7556 | |||
2d0608cf0f | |||
143c9777d6 | |||
9ac928fcf1 | |||
811f72ffef | |||
a6f8058fb4 | |||
de5ef4de00 | |||
2b9c5ea272 | |||
f054c30460 | |||
65113a6d82 | |||
a0254f47fb | |||
eebd02e309 | |||
7dc4329c52 | |||
f22cada0ce | |||
cb51bb64f3 | |||
c861a5eb73 | |||
62b0d0a560 | |||
effc9e747a | |||
bb9393d948 | |||
3b1dbf4102 | |||
d7e08186ac | |||
883eb80a63 | |||
9a1a01fe05 | |||
13c3295e64 | |||
8854429205 | |||
d5845d94a0 | |||
|
4185bf0326 | ||
74b28afd4a | |||
bfdbac0f2d | |||
cb6dde4e39 | |||
25c720b033 | |||
8d03810bf3 | |||
2d18d05bd7 | |||
|
c5bae9d50d | ||
588b9d7469 | |||
3af506fedb | |||
1db59acf0d | |||
02330a5aa1 | |||
4dbc633d7d | |||
5018386318 | |||
a43ae43722 | |||
3e96af5450 | |||
391549a7d6 | |||
fdf49cfafb | |||
b99822f405 | |||
89790a0a94 | |||
e46cbae6b8 | |||
df5297a661 | |||
f6c4ddd288 | |||
34e9748d0f | |||
de4a113528 | |||
f1610f6425 | |||
d966349032 | |||
54569b3b02 | |||
dabafe538f | |||
fac23745b4 | |||
60c963fca5 | |||
ab6cde3ec6 | |||
e5a0617621 | |||
52b6d5c3f7 | |||
fb71ef2193 |
59 changed files with 1664 additions and 579 deletions
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
|
@ -36,7 +36,7 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'java' ]
|
||||
language: [ 'java-kotlin' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
|
@ -46,7 +46,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
@ -57,7 +57,7 @@ jobs:
|
|||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
@ -71,4 +71,4 @@ jobs:
|
|||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
|
8
.github/workflows/gradle_push.yml
vendored
8
.github/workflows/gradle_push.yml
vendored
|
@ -28,9 +28,13 @@ jobs:
|
|||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
- name: Build, Check and Coverage
|
||||
- name: Build and Check
|
||||
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
|
||||
with:
|
||||
arguments: check jacocoRootReport
|
||||
- name: Coveralls
|
||||
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
|
||||
env:
|
||||
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
|
||||
with:
|
||||
arguments: check jacocoRootReport coveralls
|
||||
arguments: coveralls
|
||||
|
|
86
.reuse/dep5
86
.reuse/dep5
|
@ -1,86 +0,0 @@
|
|||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: PGPainless
|
||||
Upstream-Contact: Paul Schaub <info@pgpainless.org>
|
||||
Source: https://pgpainless.org
|
||||
|
||||
# Sample paragraph, commented out:
|
||||
#
|
||||
# Files: src/*
|
||||
# Copyright: $YEAR $NAME <$CONTACT>
|
||||
# License: ...
|
||||
|
||||
# GitBlameIgnore
|
||||
Files: .git-blame-ignore-revs
|
||||
Copyright: 2023 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
||||
|
||||
# Documentation
|
||||
Files: docs/*
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>
|
||||
License: CC-BY-3.0
|
||||
|
||||
Files: .readthedocs.yaml
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
||||
|
||||
# Gradle build tool
|
||||
Files: gradle*
|
||||
Copyright: 2015 the original author or authors.
|
||||
License: Apache-2.0
|
||||
|
||||
# Editorconfig
|
||||
Files: .editorconfig
|
||||
Copyright: Facebook
|
||||
License: Apache-2.0
|
||||
|
||||
# PGPainless Logo
|
||||
Files: assets/repository-open-graph.png
|
||||
Copyright: 2021 Paul Schaub <info@pgpainless.org>
|
||||
License: CC-BY-3.0
|
||||
|
||||
Files: assets/pgpainless.svg
|
||||
Copyright: 2021 Paul Schaub <info@pgpainless.org>
|
||||
License: CC-BY-3.0
|
||||
|
||||
Files: assets/logo.png
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>
|
||||
License: CC-BY-3.0
|
||||
|
||||
Files: assets/test_vectors/*
|
||||
Copyright: 2018 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: pgpainless-core/src/test/resources/*
|
||||
Copyright: 2020 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: audit/*
|
||||
Copyright: 2021 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
||||
|
||||
# GH Pages
|
||||
Files: CNAME
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: _config.yml
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
||||
|
||||
Files: _layouts/*
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>, 2017 Steve Smith
|
||||
License: CC-BY-SA-3.0
|
||||
|
||||
# Man Pages
|
||||
Files: pgpainless-cli/rewriteManPages.sh
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>
|
||||
License: Apache-2.0
|
||||
|
||||
Files: pgpainless-cli/packaging/man/*
|
||||
Copyright: 2022 Paul Schaub <info@pgpainless.org>
|
||||
License: Apache-2.0
|
||||
|
||||
# Github Issue Templates
|
||||
Files: .github/ISSUE_TEMPLATE/*
|
||||
Copyright: 2024 Paul Schaub <info@pgpainless.org>
|
||||
License: CC0-1.0
|
45
CHANGELOG.md
45
CHANGELOG.md
|
@ -5,8 +5,44 @@ SPDX-License-Identifier: CC0-1.0
|
|||
|
||||
# PGPainless Changelog
|
||||
|
||||
## 1.7.7-SNAPSHOT
|
||||
- Bump `bcpg-jdk8on` to `1.81`
|
||||
- Bump `bcprov-jdk18on` to `1.81`
|
||||
|
||||
## 1.7.0-SNAPSHOT
|
||||
## 1.7.6
|
||||
- Fix `RevocationSignatureBuilder` properly calculating third-party signatures of type `KeyRevocation` (delegation revocations)
|
||||
- Enable support for native images
|
||||
- Re-enable shadow plugin and build fat-jar
|
||||
|
||||
## 1.7.5
|
||||
- Actually attempt to fix Kotlin desugaring.
|
||||
- Bump javaSourceCompatibility and javaTargetCompatibility to 11
|
||||
- Bump gradle-wrapper to 8.8
|
||||
|
||||
## 1.7.4
|
||||
- Fix proper Kotlin desugaring for Java 8
|
||||
|
||||
## 1.7.3
|
||||
- Bump `bcpg-jdk8on` to `1.80`
|
||||
- Bump `bcprov-jdk18on` to `1.80`
|
||||
- Add dependency on `bcutil-jdk18on` as a workaround
|
||||
- Ignore unknown type signatures on certificates
|
||||
- Fix typo on signature creation bounds check (thanks @elduffy)
|
||||
- Fix superfluous newline added in CRLF encoding (thanks @bjansen)
|
||||
- Bump `sop-java` to `1.10.0`
|
||||
- SOP inline-sign: Do not apply compression
|
||||
|
||||
## 1.7.2
|
||||
- Fix bug in `KeyRingInfo.lastModified` (thanks to @Jerbell, @sosnovsky for reporting)
|
||||
- Bump `sop-java` to `10.0.3`
|
||||
- allow multiple arguments `--with-key-password` in `revoke-key` command
|
||||
- Properly pass `--old-key-password` and `--new-key-password` options as indirect arguments in `change-key-password` command
|
||||
|
||||
## 1.7.1
|
||||
- Bump `sop-java` to `10.0.2`
|
||||
- Downgrade `logback-core` and `logback-classic` to `1.2.13` (fix CLI spam)
|
||||
|
||||
## 1.7.0
|
||||
- Bump `bcpg-jdk8on` to `1.78.1`
|
||||
- Bump `bcprov-jdk18on` to `1.78.1`
|
||||
- Bump `logback-core` and `logback-classic` to `1.4.14`
|
||||
|
@ -27,7 +63,7 @@ SPDX-License-Identifier: CC0-1.0
|
|||
- Do not choke on LibrePGP OED packets
|
||||
- Supersede `addPassphrase()`/`addDecryptionPassphrase()` methods with more clear `addMessagePassphrase()`
|
||||
- `pgpainless-sop`, `pgpainless-cli`
|
||||
- Bump `sop-java` to `10.0.0`, implementing [SOP Spec Revision 10](https://www.ietf.org/archive/id/draft-dkg-openpgp-stateless-cli-10.html)
|
||||
- Bump `sop-java` to `10.0.1`, implementing [SOP Spec Revision 10](https://www.ietf.org/archive/id/draft-dkg-openpgp-stateless-cli-10.html)
|
||||
- Change API of `sop.encrypt` to return a `ReadyWithResult<EncryptionResult>` to expose the session key
|
||||
- `decrypt --verify-with`: Fix to not throw `NoSignature` exception (exit code 3) if `VERIFICATIONS` is empty
|
||||
- Separate signature verification operations into `SOPV` interface
|
||||
|
@ -35,6 +71,11 @@ SPDX-License-Identifier: CC0-1.0
|
|||
- Throw `BadData` error when passing KEYS where CERTS are expected.
|
||||
- `armor`: Remove `--label` option
|
||||
|
||||
## 1.6.8
|
||||
- Bump `sop-java` to `7.0.2`
|
||||
- SOP `change-key-password`: Fix reading password from indirect parameter instead of erroneously passing filename (fixes #453)
|
||||
- SOP `revoke-key`: Allow for multiple `--with-key-password` options
|
||||
|
||||
## 1.6.7
|
||||
- SOP: Fix OOM error when detached-signing large amounts of data (fix #432)
|
||||
- Move `CachingBcPublicKeyDataDecryptorFactory` from `org.bouncycastle` packet to `org.pgpainless.decryption_verification` to avoid package split (partially addresses #428)
|
||||
|
|
|
@ -164,7 +164,7 @@ This behaviour can be modified though using the `Policy` class.
|
|||
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
|
||||
.onInputStream(encryptedInputStream)
|
||||
.withOptions(new ConsumerOptions()
|
||||
.addMessagePassphrase(bobSecKeys, secretKeyProtector)
|
||||
.addDecryptionKey(bobSecKeys, secretKeyProtector)
|
||||
.addVerificationCert(alicePubKeys)
|
||||
);
|
||||
|
||||
|
@ -191,7 +191,7 @@ repositories {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.pgpainless:pgpainless-core:1.7.0'
|
||||
implementation 'org.pgpainless:pgpainless-core:1.7.6'
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -222,9 +222,6 @@ Parts of PGPainless development ([project page](https://nlnet.nl/project/PGPainl
|
|||
NGI Assure is made possible with financial support from the [European Commission](https://ec.europa.eu/)'s [Next Generation Internet](https://ngi.eu/) programme, under the aegis of [DG Communications Networks, Content and Technology](https://ec.europa.eu/info/departments/communications-networks-content-and-technology_en).
|
||||
[](https://nlnet.nl/assure/)
|
||||
|
||||
Thanks to [YourKit](https://www.yourkit.com/) for providing a free license of the [YourKit Java Profiler](https://www.yourkit.com/java/profiler/) to support PGPainless Development!
|
||||
[](https://www.yourkit.com/)
|
||||
|
||||
Big thank you also to those who decided to support the work by donating!
|
||||
Notably @msfjarvis
|
||||
|
||||
|
|
118
REUSE.toml
Normal file
118
REUSE.toml
Normal file
|
@ -0,0 +1,118 @@
|
|||
version = 1
|
||||
SPDX-PackageName = "PGPainless"
|
||||
SPDX-PackageSupplier = "Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-PackageDownloadLocation = "https://pgpainless.org"
|
||||
|
||||
[[annotations]]
|
||||
path = "REUSE.toml"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2025 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ".git-blame-ignore-revs"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2023 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "docs/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC-BY-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ".readthedocs.yaml"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "gradle**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2015 the original author or authors."
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ".editorconfig"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "Facebook"
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "assets/repository-open-graph.png"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2021 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC-BY-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "assets/pgpainless.svg"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2021 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC-BY-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "assets/logo.png"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC-BY-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "assets/test_vectors/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2018 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "pgpainless-core/src/test/resources/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2020 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "audit/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2021 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "CNAME"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "_config.yml"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "_layouts/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>, 2017 Steve Smith"
|
||||
SPDX-License-Identifier = "CC-BY-SA-3.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "pgpainless-cli/src/main/resources/META-INF/native-image/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2025 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "pgpainless-cli/rewriteManPages.sh"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "pgpainless-cli/packaging/man/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2022 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "Apache-2.0"
|
||||
|
||||
[[annotations]]
|
||||
path = ".github/ISSUE_TEMPLATE/**"
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "2024 Paul Schaub <info@pgpainless.org>"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
78
build.gradle
78
build.gradle
|
@ -33,24 +33,17 @@ allprojects {
|
|||
apply plugin: 'kotlin'
|
||||
apply plugin: 'com.diffplug.spotless'
|
||||
|
||||
java {
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.release = 8
|
||||
}
|
||||
|
||||
// Only generate jar for submodules
|
||||
// without this we would generate an empty pgpainless.jar for the project root
|
||||
// https://stackoverflow.com/a/25445035
|
||||
jar {
|
||||
reproducibleFileOrder = true
|
||||
onlyIf { !sourceSets.main.allSource.files.isEmpty() }
|
||||
}
|
||||
|
||||
// checkstyle
|
||||
checkstyle {
|
||||
toolVersion = '10.12.1'
|
||||
toolVersion = '10.25.0'
|
||||
}
|
||||
|
||||
spotless {
|
||||
|
@ -63,8 +56,6 @@ allprojects {
|
|||
description = "Simple to use OpenPGP API for Java based on Bouncycastle"
|
||||
version = shortVersion
|
||||
|
||||
sourceCompatibility = javaSourceCompatibility
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
|
@ -79,6 +70,10 @@ allprojects {
|
|||
fileMode = 0644
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(javaSourceCompatibility)
|
||||
}
|
||||
|
||||
// Compatibility of default implementations in kotlin interfaces with Java implementations.
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
kotlinOptions {
|
||||
|
@ -119,7 +114,7 @@ allprojects {
|
|||
sourceDirectories.setFrom(project.files(sourceSets.main.allSource.srcDirs))
|
||||
classDirectories.setFrom(project.files(sourceSets.main.output))
|
||||
reports {
|
||||
xml.enabled true
|
||||
xml.required = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,15 +132,15 @@ subprojects {
|
|||
apply plugin: 'signing'
|
||||
|
||||
task sourcesJar(type: Jar, dependsOn: classes) {
|
||||
classifier = 'sources'
|
||||
archiveClassifier = 'sources'
|
||||
from sourceSets.main.allSource
|
||||
}
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
classifier = 'javadoc'
|
||||
archiveClassifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
task testsJar(type: Jar, dependsOn: testClasses) {
|
||||
classifier = 'tests'
|
||||
archiveClassifier = 'tests'
|
||||
from sourceSets.test.output
|
||||
}
|
||||
|
||||
|
@ -242,7 +237,7 @@ task jacocoRootReport(type: JacocoReport) {
|
|||
classDirectories.setFrom(files(subprojects.sourceSets.main.output))
|
||||
executionData.setFrom(files(subprojects.jacocoTestReport.executionData))
|
||||
reports {
|
||||
xml.enabled true
|
||||
xml.required = true
|
||||
xml.destination file("${buildDir}/reports/jacoco/test/jacocoTestReport.xml")
|
||||
}
|
||||
// We could remove the following setOnlyIf line, but then
|
||||
|
@ -253,10 +248,6 @@ task jacocoRootReport(type: JacocoReport) {
|
|||
}
|
||||
|
||||
task javadocAll(type: Javadoc) {
|
||||
def currentJavaVersion = JavaVersion.current()
|
||||
if (currentJavaVersion.compareTo(JavaVersion.VERSION_1_9) >= 0) {
|
||||
options.addStringOption("-release", "8");
|
||||
}
|
||||
source subprojects.collect {project ->
|
||||
project.sourceSets.main.allJava }
|
||||
destinationDir = new File(buildDir, 'javadoc')
|
||||
|
@ -270,18 +261,6 @@ task javadocAll(type: Javadoc) {
|
|||
] as String[]
|
||||
}
|
||||
|
||||
if (JavaVersion.current().isJava8Compatible()) {
|
||||
tasks.withType(Javadoc) {
|
||||
// The '-quiet' as second argument is actually a hack,
|
||||
// since the one paramater addStringOption doesn't seem to
|
||||
// work, we extra add '-quiet', which is added anyway by
|
||||
// gradle. See https://github.com/gradle/gradle/issues/2354
|
||||
// See JDK-8200363 (https://bugs.openjdk.java.net/browse/JDK-8200363)
|
||||
// for information about the -Xwerror option.
|
||||
options.addStringOption('Xwerror', '-quiet')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch sha256 checksums of artifacts published to maven central.
|
||||
*
|
||||
|
@ -291,34 +270,13 @@ task mavenCentralChecksums() {
|
|||
description 'Fetch and display checksums for artifacts published to Maven Central'
|
||||
String ver = project.hasProperty('release') ? release : shortVersion
|
||||
doLast {
|
||||
Process p = "curl -f https://repo1.maven.org/maven2/org/pgpainless/pgpainless-core/${ver}/pgpainless-core-${ver}.jar.sha256".execute()
|
||||
if (p.waitFor() == 0) {
|
||||
print p.text.trim()
|
||||
println " pgpainless-core/build/libs/pgpainless-core-${ver}.jar"
|
||||
}
|
||||
|
||||
p = "curl -f https://repo1.maven.org/maven2/org/pgpainless/pgpainless-sop/${ver}/pgpainless-sop-${ver}.jar.sha256".execute()
|
||||
if (p.waitFor() == 0) {
|
||||
print p.text.trim()
|
||||
println " pgpainless-sop/build/libs/pgpainless-sop-${ver}.jar"
|
||||
}
|
||||
|
||||
p = "curl -f https://repo1.maven.org/maven2/org/pgpainless/pgpainless-cli/${ver}/pgpainless-cli-${ver}-all.jar.sha256".execute()
|
||||
if (p.waitFor() == 0) {
|
||||
print p.text.trim()
|
||||
println " pgpainless-cli/build/libs/pgpainless-cli-${ver}-all.jar"
|
||||
}
|
||||
|
||||
p = "curl -f https://repo1.maven.org/maven2/org/pgpainless/pgpainless-cli/${ver}/pgpainless-cli-${ver}.jar.sha256".execute()
|
||||
if (p.waitFor() == 0) {
|
||||
print p.text.trim()
|
||||
println " pgpainless-cli/build/libs/pgpainless-cli-${ver}.jar"
|
||||
}
|
||||
|
||||
p = "curl -f https://repo1.maven.org/maven2/org/pgpainless/hsregex/${ver}/hsregex-${ver}.jar.sha256".execute()
|
||||
if (p.waitFor() == 0) {
|
||||
print p.text.trim()
|
||||
println " hsregex/build/libs/hsregex-${ver}.jar"
|
||||
for (Project p : rootProject.subprojects) {
|
||||
String url = "https://repo1.maven.org/maven2/org/pgpainless/${p.name}/${ver}/${p.name}-${ver}.jar.sha256"
|
||||
Process fetch = "curl -f $url".execute()
|
||||
if (fetch.waitFor() == 0) {
|
||||
print fetch.text.trim()
|
||||
println " ${p.name}/build/libs/${p.name}-${ver}.jar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,5 +1,5 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
|
|
@ -4,27 +4,13 @@
|
|||
|
||||
plugins {
|
||||
id 'application'
|
||||
id "com.github.johnrengelman.shadow" version "6.1.0"
|
||||
}
|
||||
def generatedVersionDir = "${buildDir}/generated-version"
|
||||
|
||||
sourceSets {
|
||||
main {
|
||||
output.dir(generatedVersionDir, builtBy: 'generateVersionProperties')
|
||||
}
|
||||
id 'org.graalvm.buildtools.native' version '0.10.6'
|
||||
id 'com.gradleup.shadow' version '8.3.6'
|
||||
}
|
||||
|
||||
task generateVersionProperties {
|
||||
doLast {
|
||||
def propertiesFile = file "$generatedVersionDir/version.properties"
|
||||
propertiesFile.parentFile.mkdirs()
|
||||
propertiesFile.createNewFile()
|
||||
// Instead of using a Properties object here, we directly write to the file
|
||||
// since Properties adds a timestamp, ruining reproducibility
|
||||
propertiesFile.write("version="+rootProject.version.toString())
|
||||
}
|
||||
graalvmNative {
|
||||
toolchainDetection = true
|
||||
}
|
||||
processResources.dependsOn generateVersionProperties
|
||||
|
||||
dependencies {
|
||||
|
||||
|
@ -32,13 +18,12 @@ dependencies {
|
|||
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||
// https://todd.ginsberg.com/post/testing-system-exit/
|
||||
testImplementation 'com.ginsberg:junit5-system-exit:1.1.2'
|
||||
|
||||
// implementation "ch.qos.logback:logback-core:1.2.6"
|
||||
// We want logback logging in tests and in the app
|
||||
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
implementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
// implementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
implementation "org.slf4j:slf4j-nop:$slf4jVersion"
|
||||
|
||||
implementation(project(":pgpainless-sop"))
|
||||
implementation "org.pgpainless:sop-java-picocli:$sopJavaVersion"
|
||||
|
@ -52,22 +37,6 @@ mainClassName = 'org.pgpainless.cli.PGPainlessCLI'
|
|||
application {
|
||||
mainClass = mainClassName
|
||||
}
|
||||
/**
|
||||
jar {
|
||||
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
|
||||
manifest {
|
||||
attributes 'Main-Class': "$mainClassName"
|
||||
}
|
||||
|
||||
from {
|
||||
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
|
||||
} {
|
||||
exclude "META-INF/*.SF"
|
||||
exclude "META-INF/*.DSA"
|
||||
exclude "META-INF/*.RSA"
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
run {
|
||||
// https://stackoverflow.com/questions/59445306/pipe-into-gradle-run
|
||||
|
@ -77,5 +46,3 @@ run {
|
|||
args Eval.me(appArgs)
|
||||
}
|
||||
}
|
||||
|
||||
// tasks."jar".dependsOn(":pgpainless-core:assemble", ":pgpainless-sop:assemble")
|
||||
|
|
|
@ -14,6 +14,10 @@ import sop.cli.picocli.SopCLI;
|
|||
public class PGPainlessCLI {
|
||||
|
||||
static {
|
||||
// Prevent slf4j initialization logging
|
||||
// https://github.com/qos-ch/slf4j/issues/422#issuecomment-2277280185
|
||||
System.setProperty("slf4j.internal.verbosity", "WARN");
|
||||
|
||||
SopCLI.EXECUTABLE_NAME = "pgpainless-cli";
|
||||
SopCLI.setSopInstance(new SOPImpl());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
|
@ -0,0 +1,7 @@
|
|||
[
|
||||
{
|
||||
"type":"agent-extracted",
|
||||
"classes":[
|
||||
]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
|
@ -0,0 +1,891 @@
|
|||
[
|
||||
{
|
||||
"name":"[Ljava.lang.Object;"
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.classic.encoder.PatternLayoutEncoder",
|
||||
"queryAllPublicMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.classic.joran.SerializedModelConfigurator",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.classic.util.DefaultJoranConfigurator",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.ConsoleAppender",
|
||||
"queryAllPublicMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"setTarget","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.OutputStreamAppender",
|
||||
"methods":[{"name":"setEncoder","parameterTypes":["ch.qos.logback.core.encoder.Encoder"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.encoder.Encoder",
|
||||
"methods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.encoder.LayoutWrappingEncoder",
|
||||
"methods":[{"name":"setParent","parameterTypes":["ch.qos.logback.core.spi.ContextAware"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.pattern.PatternLayoutEncoderBase",
|
||||
"methods":[{"name":"setPattern","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"ch.qos.logback.core.spi.ContextAware",
|
||||
"methods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"groovy.lang.Closure"
|
||||
},
|
||||
{
|
||||
"name":"java.io.FilePermission"
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Enum"
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Object",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.RuntimePermission"
|
||||
},
|
||||
{
|
||||
"name":"java.lang.System",
|
||||
"methods":[{"name":"console","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"java.lang.invoke.MethodHandle"
|
||||
},
|
||||
{
|
||||
"name":"java.net.NetPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.net.SocketPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.net.URLPermission",
|
||||
"methods":[{"name":"<init>","parameterTypes":["java.lang.String","java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.channels.SelectionKey",
|
||||
"fields":[{"name":"attachment"}]
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.Path"
|
||||
},
|
||||
{
|
||||
"name":"java.nio.file.Paths",
|
||||
"methods":[{"name":"get","parameterTypes":["java.lang.String","java.lang.String[]"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.security.AllPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.security.MessageDigestSpi"
|
||||
},
|
||||
{
|
||||
"name":"java.security.SecureRandomParameters"
|
||||
},
|
||||
{
|
||||
"name":"java.security.SecurityPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.security.cert.PKIXRevocationChecker"
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Connection"
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Driver"
|
||||
},
|
||||
{
|
||||
"name":"java.sql.DriverManager",
|
||||
"methods":[{"name":"getConnection","parameterTypes":["java.lang.String"] }, {"name":"getDriver","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Time",
|
||||
"methods":[{"name":"<init>","parameterTypes":["long"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.sql.Timestamp",
|
||||
"methods":[{"name":"valueOf","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Duration",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Instant",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.LocalDate",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.LocalDateTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.LocalTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.MonthDay",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.OffsetDateTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.OffsetTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Period",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.Year",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.YearMonth",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.ZoneId",
|
||||
"methods":[{"name":"of","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.ZoneOffset",
|
||||
"methods":[{"name":"of","parameterTypes":["java.lang.String"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.time.ZonedDateTime",
|
||||
"methods":[{"name":"parse","parameterTypes":["java.lang.CharSequence"] }]
|
||||
},
|
||||
{
|
||||
"name":"java.util.HashSet"
|
||||
},
|
||||
{
|
||||
"name":"java.util.LinkedHashSet"
|
||||
},
|
||||
{
|
||||
"name":"java.util.PropertyPermission"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.ArrayBlockingQueue"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.atomic.AtomicReference",
|
||||
"fields":[{"name":"value"}]
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.AbstractOwnableSynchronizer"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.AbstractQueuedSynchronizer"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.ReentrantLock"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.ReentrantLock$NonfairSync"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.ReentrantLock$Sync"
|
||||
},
|
||||
{
|
||||
"name":"javax.smartcardio.CardPermission"
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.COMPOSITE$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.CONTEXT$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.CompositeSignatures$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.DSTU4145$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.Dilithium$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.ECGOST$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.EXTERNAL$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.EdEC$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.ElGamal$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.Falcon$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.GM$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.GOST$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.IES$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.LMS$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.MLDSA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.MLKEM$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.NTRU$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.NoSig$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.RSA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.SLHDSA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.SPHINCSPlus$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.X509$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi$EdDSA",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi$XDH",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyPairGeneratorSpi",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Blake2b$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Blake2s$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Blake3$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.DSTU7564$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.GOST3411$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Haraka$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Keccak$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.MD2$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.MD4$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.MD5$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.RIPEMD128$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.RIPEMD160$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.RIPEMD256$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.RIPEMD320$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.SHA1$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.SHA224$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.SHA256$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.SHA3$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.SHA384$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.SHA512$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.SM3$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Skein$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Tiger$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.digest.Whirlpool$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.drbg.DRBG$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.keystore.BC$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.keystore.BCFKS$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.AES$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.ARC4$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.ARIA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Blowfish$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.CAST5$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.CAST6$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Camellia$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.ChaCha$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.DES$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.DSTU7624$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.GOST28147$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.GOST3412_2015$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Grain128$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Grainv1$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.HC128$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.HC256$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Noekeon$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.OpenSSLPBKDF$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF1$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Poly1305$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.RC5$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.RC6$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Rijndael$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.SCRYPT$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.SEED$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.SM4$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Salsa20$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Serpent$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Shacal2$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.SipHash$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.SipHash128$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Skipjack$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.TEA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.TLSKDF$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Threefish$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.VMPC$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.VMPCKSA3$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.XSalsa20$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.XTEA$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.bouncycastle.jcajce.provider.symmetric.Zuc$Mappings",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.ExitCodeTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"successfulExecutionDoesNotTerminateJVM","parameterTypes":[] }, {"name":"testCommandWithUnknownOption_37","parameterTypes":[] }, {"name":"testUnknownCommand_69","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.TestUtils",
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.ArmorCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"armorAlreadyArmoredDataIsIdempotent","parameterTypes":[] }, {"name":"armorMessage","parameterTypes":[] }, {"name":"armorPublicKey","parameterTypes":[] }, {"name":"armorSecretKey","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.CLITest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"methods":[{"name":"cleanup","parameterTypes":[] }, {"name":"setup","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.DearmorCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"dearmorBrokenArmoredKeyFails","parameterTypes":[] }, {"name":"dearmorCertificate","parameterTypes":[] }, {"name":"dearmorGarbageEmitsEmpty","parameterTypes":[] }, {"name":"dearmorMessage","parameterTypes":[] }, {"name":"dearmorSecretKey","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.ExtractCertCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"extractCertFromGarbageFails","parameterTypes":[] }, {"name":"testExtractCert","parameterTypes":[] }, {"name":"testExtractCertFromCertFails","parameterTypes":[] }, {"name":"testExtractCertUnarmored","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.GenerateKeyCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"testGenerateBinaryKey","parameterTypes":[] }, {"name":"testGenerateKey","parameterTypes":[] }, {"name":"testGenerateKeyWithMultipleUserIds","parameterTypes":[] }, {"name":"testGeneratePasswordProtectedKey_missingPasswordFile","parameterTypes":[] }, {"name":"testPasswordProtectedKey","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.InlineDetachCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"detachInbandSignatureAndMessage","parameterTypes":[] }, {"name":"detachInbandSignatureAndMessageNoArmor","parameterTypes":[] }, {"name":"detachMissingSignaturesFromCleartextSignedMessageFails","parameterTypes":[] }, {"name":"detachNonOpenPgpDataFails","parameterTypes":[] }, {"name":"existingSignatureOutCausesException","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.ListProfilesCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"listProfileOfGenerateKey","parameterTypes":[] }, {"name":"listProfilesOfEncrypt","parameterTypes":[] }, {"name":"listProfilesWithoutCommand","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.RoundTripEncryptDecryptCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"decryptGarbageFails","parameterTypes":[] }, {"name":"decryptMalformedMessageYieldsBadData","parameterTypes":[] }, {"name":"decryptMessageWithSessionKey","parameterTypes":[] }, {"name":"decryptMessageWithWrongKeyFails","parameterTypes":[] }, {"name":"decryptWithPasswordWithPendingWhitespaceWorks","parameterTypes":[] }, {"name":"decryptWithWhitespacePasswordWorks","parameterTypes":[] }, {"name":"decrypt_verifyWithGarbageCertFails","parameterTypes":[] }, {"name":"decrypt_withGarbageKeyFails","parameterTypes":[] }, {"name":"encryptAndDecryptAMessage","parameterTypes":[] }, {"name":"encryptAndDecryptMessageWithPassphrase","parameterTypes":[] }, {"name":"encryptWithGarbageCertFails","parameterTypes":[] }, {"name":"encryptWithPasswordADecryptWithPasswordBFails","parameterTypes":[] }, {"name":"encryptWithProtectedKey_wrongPassphraseFails","parameterTypes":[] }, {"name":"encryptWithTrailingWhitespaceDecryptWithoutWorks","parameterTypes":[] }, {"name":"encrypt_signWithGarbageKeyFails","parameterTypes":[] }, {"name":"testDecryptVerifyOut_withoutVerifyWithFails","parameterTypes":[] }, {"name":"testDecryptWithSessionKeyVerifyWithYieldsExpectedVerifications","parameterTypes":[] }, {"name":"testDecryptWithoutDecryptionOptionFails","parameterTypes":[] }, {"name":"testEncryptDecryptRoundTripWithPasswordProtectedKey","parameterTypes":[] }, {"name":"testEncryptDecryptWithFreshRSAKey","parameterTypes":[] }, {"name":"testEncryptWithIncapableCert","parameterTypes":[] }, {"name":"testEncrypt_SignWithCertFails","parameterTypes":[] }, {"name":"testMissingArgumentsIfNoArgsSupplied","parameterTypes":[] }, {"name":"testSessionKeyOutWritesSessionKeyOut","parameterTypes":[] }, {"name":"testSignWithIncapableKey","parameterTypes":[] }, {"name":"testVerificationsOutAlreadyExistFails","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.RoundTripInlineSignInlineVerifyCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"cannotVerifyEncryptedMessage","parameterTypes":[] }, {"name":"cannotVerifyMalformedMessage","parameterTypes":[] }, {"name":"createAndVerifyCleartextSignedMessage","parameterTypes":[] }, {"name":"createAndVerifyMultiKeyBinarySignedMessage","parameterTypes":[] }, {"name":"createAndVerifyTextSignedMessage","parameterTypes":[] }, {"name":"createCleartextSignedMessage","parameterTypes":[] }, {"name":"createMalformedMessage","parameterTypes":[] }, {"name":"createSignedMessageWithKeyAAndVerifyWithKeyBFails","parameterTypes":[] }, {"name":"createTextSignedMessageInlineDetachAndDetachedVerify","parameterTypes":[] }, {"name":"signWithProtectedKeyWithWrongPassphraseFails","parameterTypes":[] }, {"name":"testInlineSignWithMissingSecretKeysFails","parameterTypes":[] }, {"name":"testUnlockKeyWithOneOfMultiplePasswords","parameterTypes":[] }, {"name":"verifyPrependedSignedMessage","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.RoundTripInlineSignVerifyCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"encryptAndDecryptAMessage","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.RoundTripSignVerifyCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"createArmoredSignature","parameterTypes":[] }, {"name":"createUnarmoredSignature","parameterTypes":[] }, {"name":"signWithProtectedKey","parameterTypes":[] }, {"name":"signWithProtectedKey_missingPassphraseFails","parameterTypes":[] }, {"name":"signWithProtectedKey_wrongPassphraseFails","parameterTypes":[] }, {"name":"testNotAfter","parameterTypes":[] }, {"name":"testNotBefore","parameterTypes":[] }, {"name":"testSignWithIncapableKey","parameterTypes":[] }, {"name":"testSignatureCreationAndVerification","parameterTypes":[] }, {"name":"unarmorArmoredSigAndVerify","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.commands.VersionCmdTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"testExtendedVersion","parameterTypes":[] }, {"name":"testGetBackendVersion","parameterTypes":[] }, {"name":"testSopSpecVersion","parameterTypes":[] }, {"name":"testVersion","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"org.pgpainless.cli.misc.SignUsingPublicKeyBehaviorTest",
|
||||
"allDeclaredFields":true,
|
||||
"allDeclaredClasses":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"queryAllPublicMethods":true,
|
||||
"queryAllDeclaredConstructors":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"testSignatureCreationAndVerification","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"picocli.AutoComplete$GenerateCompletion",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"picocli.CommandLine$AutoHelpMixin",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"picocli.CommandLine$HelpCommand",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.SopCLI",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.SopCLI$InitLocale",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.AbstractSopCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.ArmorCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.ChangeKeyPasswordCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.DearmorCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.DecryptCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.EncryptCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.ExtractCertCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.GenerateKeyCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.InlineDetachCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.InlineSignCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.InlineVerifyCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.ListProfilesCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.RevokeKeyCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.SignCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.VerifyCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.VersionCmd",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sop.cli.picocli.commands.VersionCmd$Exclusive",
|
||||
"allDeclaredFields":true,
|
||||
"queryAllDeclaredMethods":true,
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.NativePRNG",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }, {"name":"<init>","parameterTypes":["java.security.SecureRandomParameters"] }]
|
||||
},
|
||||
{
|
||||
"name":"sun.security.provider.SHA",
|
||||
"methods":[{"name":"<init>","parameterTypes":[] }]
|
||||
}
|
||||
]
|
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"resources":{
|
||||
"includes":[{
|
||||
"pattern":"\\QMETA-INF/services/ch.qos.logback.classic.spi.Configurator\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/java.lang.System$LoggerFinder\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/java.nio.channels.spi.SelectorProvider\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/java.time.zone.ZoneRulesProvider\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/java.util.spi.ResourceBundleControlProvider\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/javax.xml.parsers.SAXParserFactory\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/org.junit.platform.engine.TestEngine\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/org.junit.platform.launcher.LauncherDiscoveryListener\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/org.junit.platform.launcher.LauncherSessionListener\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/org.junit.platform.launcher.PostDiscoveryFilter\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/org.junit.platform.launcher.TestExecutionListener\\E"
|
||||
}, {
|
||||
"pattern":"\\QMETA-INF/services/org.slf4j.spi.SLF4JServiceProvider\\E"
|
||||
}, {
|
||||
"pattern":"\\Qjunit-platform.properties\\E"
|
||||
}, {
|
||||
"pattern":"\\Qlogback-test.scmo\\E"
|
||||
}, {
|
||||
"pattern":"\\Qlogback-test.xml\\E"
|
||||
}, {
|
||||
"pattern":"\\Qlogback.scmo\\E"
|
||||
}, {
|
||||
"pattern":"\\Qorg/slf4j/impl/StaticLoggerBinder.class\\E"
|
||||
}, {
|
||||
"pattern":"\\Qpgpainless-sop.properties\\E"
|
||||
}, {
|
||||
"pattern":"\\Qsop-java-version.properties\\E"
|
||||
}, {
|
||||
"pattern":"java.base:\\Qsun/text/resources/LineBreakIteratorData\\E"
|
||||
}]},
|
||||
"bundles":[{
|
||||
"name":"msg_armor",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_change-key-password",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_dearmor",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_decrypt",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_detached-sign",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_detached-verify",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_encrypt",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_extract-cert",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_generate-key",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_inline-detach",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_inline-sign",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_inline-verify",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_list-profiles",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_revoke-key",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_sop",
|
||||
"locales":["de", "und"]
|
||||
}, {
|
||||
"name":"msg_version",
|
||||
"locales":["de", "und"]
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"types":[
|
||||
{
|
||||
"name":"java.lang.Enum"
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Object[]"
|
||||
},
|
||||
{
|
||||
"name":"java.util.HashSet"
|
||||
},
|
||||
{
|
||||
"name":"java.util.LinkedHashSet"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.ArrayBlockingQueue"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.AbstractOwnableSynchronizer"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.AbstractQueuedSynchronizer"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.ReentrantLock"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.ReentrantLock$NonfairSync"
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.locks.ReentrantLock$Sync"
|
||||
}
|
||||
],
|
||||
"lambdaCapturingTypes":[
|
||||
],
|
||||
"proxies":[
|
||||
]
|
||||
}
|
|
@ -5,22 +5,5 @@ SPDX-License-Identifier: Apache-2.0
|
|||
-->
|
||||
|
||||
<configuration debug="false">
|
||||
<appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<target>System.err</target>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<target>System.out</target>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="error">
|
||||
<appender-ref ref="STDERR" />
|
||||
</root>
|
||||
|
||||
<statusListener class="ch.qos.logback.core.status.NopStatusListener" />
|
||||
</configuration>
|
|
@ -4,28 +4,35 @@
|
|||
|
||||
package org.pgpainless.cli;
|
||||
|
||||
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||
import com.ginsberg.junit.exit.FailOnSystemExit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.cli.commands.CLITest;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sop.exception.SOPGPException;
|
||||
|
||||
public class ExitCodeTest {
|
||||
import java.io.IOException;
|
||||
|
||||
@Test
|
||||
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedSubcommand.EXIT_CODE)
|
||||
public void testUnknownCommand_69() {
|
||||
PGPainlessCLI.main(new String[] {"generate-kex"});
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ExitCodeTest extends CLITest {
|
||||
|
||||
public ExitCodeTest() {
|
||||
super(LoggerFactory.getLogger(ExitCodeTest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE)
|
||||
public void testCommandWithUnknownOption_37() {
|
||||
PGPainlessCLI.main(new String[] {"generate-key", "-k", "\"k is unknown\""});
|
||||
public void testUnknownCommand_69() throws IOException {
|
||||
assertEquals(SOPGPException.UnsupportedSubcommand.EXIT_CODE,
|
||||
executeCommand("unsupported-subcommand"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void successfulExecutionDoesNotTerminateJVM() {
|
||||
PGPainlessCLI.main(new String[] {"version"});
|
||||
public void testCommandWithUnknownOption_37() throws IOException {
|
||||
assertEquals(SOPGPException.UnsupportedOption.EXIT_CODE,
|
||||
executeCommand("generate-key", "-k", "\"k is unknown\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void successfulExecutionDoesNotTerminateJVM() throws IOException {
|
||||
assertSuccess(executeCommand("version"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,6 @@ import java.io.IOException;
|
|||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import com.ginsberg.junit.exit.FailOnSystemExit;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
|
@ -83,7 +82,6 @@ public class RoundTripEncryptDecryptCmdTest extends CLITest {
|
|||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void encryptAndDecryptAMessage() throws IOException {
|
||||
// Juliets key and cert
|
||||
File julietKeyFile = pipeStdoutToFile("juliet.key");
|
||||
|
|
|
@ -138,6 +138,10 @@ public class RoundTripInlineSignInlineVerifyCmdTest extends CLITest {
|
|||
"\n" +
|
||||
"There is only one Lord of the Keys, only one who can bend them to his will. And he does not share power.";
|
||||
|
||||
private static final String MESSAGE_CRLF = "One does not simply use OpenPGP!\r\n" +
|
||||
"\r\n" +
|
||||
"There is only one Lord of the Keys, only one who can bend them to his will. And he does not share power.";
|
||||
|
||||
@Test
|
||||
public void createCleartextSignedMessage() throws IOException {
|
||||
File key = writeFile("key.asc", KEY_1);
|
||||
|
@ -153,7 +157,7 @@ public class RoundTripInlineSignInlineVerifyCmdTest extends CLITest {
|
|||
String cleartextSigned = ciphertextOut.toString();
|
||||
assertTrue(cleartextSigned.startsWith("-----BEGIN PGP SIGNED MESSAGE-----\n" +
|
||||
"Hash: "));
|
||||
assertTrue(cleartextSigned.contains(MESSAGE));
|
||||
assertTrue(cleartextSigned.contains(MESSAGE_CRLF));
|
||||
assertTrue(cleartextSigned.contains("\n-----BEGIN PGP SIGNATURE-----\n"));
|
||||
assertTrue(cleartextSigned.endsWith("-----END PGP SIGNATURE-----\n"));
|
||||
}
|
||||
|
@ -203,7 +207,7 @@ public class RoundTripInlineSignInlineVerifyCmdTest extends CLITest {
|
|||
"--verifications-out", verifications.getAbsolutePath(),
|
||||
cert.getAbsolutePath()));
|
||||
|
||||
assertEquals(MESSAGE, plaintextOut.toString());
|
||||
assertEquals(MESSAGE_CRLF, plaintextOut.toString());
|
||||
String verificationString = readStringFromFile(verifications);
|
||||
assertTrue(verificationString.contains(CERT_1_SIGNING_KEY));
|
||||
}
|
||||
|
|
|
@ -4,104 +4,49 @@
|
|||
|
||||
package org.pgpainless.cli.commands;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.ginsberg.junit.exit.FailOnSystemExit;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.cli.PGPainlessCLI;
|
||||
import org.pgpainless.cli.TestUtils;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class RoundTripInlineSignVerifyCmdTest {
|
||||
private static File tempDir;
|
||||
private static PrintStream originalSout;
|
||||
public class RoundTripInlineSignVerifyCmdTest extends CLITest {
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() throws IOException {
|
||||
tempDir = TestUtils.createTempDirectory();
|
||||
public RoundTripInlineSignVerifyCmdTest() {
|
||||
super(LoggerFactory.getLogger(RoundTripInlineSignVerifyCmdTest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void encryptAndDecryptAMessage() throws IOException {
|
||||
originalSout = System.out;
|
||||
File sigmundKeyFile = new File(tempDir, "sigmund.key");
|
||||
assertTrue(sigmundKeyFile.createNewFile());
|
||||
|
||||
File sigmundCertFile = new File(tempDir, "sigmund.cert");
|
||||
assertTrue(sigmundCertFile.createNewFile());
|
||||
|
||||
File msgFile = new File(tempDir, "signed.asc");
|
||||
assertTrue(msgFile.createNewFile());
|
||||
|
||||
File passwordFile = new File(tempDir, "password");
|
||||
assertTrue(passwordFile.createNewFile());
|
||||
|
||||
// write password file
|
||||
FileOutputStream passwordOut = new FileOutputStream(passwordFile);
|
||||
passwordOut.write("sw0rdf1sh".getBytes(StandardCharsets.UTF_8));
|
||||
passwordOut.close();
|
||||
File password = writeFile("password", "sw0rdf1sh");
|
||||
|
||||
// generate key
|
||||
OutputStream sigmundKeyOut = new FileOutputStream(sigmundKeyFile);
|
||||
System.setOut(new PrintStream(sigmundKeyOut));
|
||||
PGPainlessCLI.execute("generate-key",
|
||||
"--with-key-password=" + passwordFile.getAbsolutePath(),
|
||||
"Sigmund Freud <sigmund@pgpainless.org>");
|
||||
sigmundKeyOut.close();
|
||||
File sigmundKey = pipeStdoutToFile("sigmund.key");
|
||||
assertSuccess(executeCommand("generate-key", "--with-key-password=" + password.getAbsolutePath(),
|
||||
"Sigmund Freud <sigmund@pgpainless.org>"));
|
||||
|
||||
// extract cert
|
||||
FileInputStream sigmundKeyIn = new FileInputStream(sigmundKeyFile);
|
||||
System.setIn(sigmundKeyIn);
|
||||
OutputStream sigmundCertOut = new FileOutputStream(sigmundCertFile);
|
||||
System.setOut(new PrintStream(sigmundCertOut));
|
||||
PGPainlessCLI.execute("extract-cert");
|
||||
sigmundKeyIn.close();
|
||||
sigmundCertOut.close();
|
||||
File sigmundCert = pipeStdoutToFile("sigmund.cert");
|
||||
pipeFileToStdin(sigmundKey);
|
||||
assertSuccess(executeCommand("extract-cert"));
|
||||
|
||||
// sign message
|
||||
String msg = "Hello World!\n";
|
||||
ByteArrayInputStream msgIn = new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8));
|
||||
System.setIn(msgIn);
|
||||
OutputStream msgAscOut = new FileOutputStream(msgFile);
|
||||
System.setOut(new PrintStream(msgAscOut));
|
||||
PGPainlessCLI.execute("inline-sign",
|
||||
"--with-key-password=" + passwordFile.getAbsolutePath(),
|
||||
sigmundKeyFile.getAbsolutePath());
|
||||
msgAscOut.close();
|
||||
pipeBytesToStdin("Hello, World!\n".getBytes(StandardCharsets.UTF_8));
|
||||
File signedMsg = pipeStdoutToFile("signed.asc");
|
||||
assertSuccess(executeCommand("inline-sign", "--with-key-password=" + password.getAbsolutePath(),
|
||||
sigmundKey.getAbsolutePath()));
|
||||
|
||||
File verifyFile = new File(tempDir, "verify.txt");
|
||||
// verify message
|
||||
File verifyFile = nonExistentFile("verify.txt");
|
||||
pipeFileToStdin(signedMsg);
|
||||
assertSuccess(executeCommand("inline-verify", "--verifications-out", verifyFile.getAbsolutePath(),
|
||||
sigmundCert.getAbsolutePath()));
|
||||
|
||||
FileInputStream msgAscIn = new FileInputStream(msgFile);
|
||||
System.setIn(msgAscIn);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
PrintStream pOut = new PrintStream(out);
|
||||
System.setOut(pOut);
|
||||
PGPainlessCLI.execute("inline-verify",
|
||||
"--verifications-out", verifyFile.getAbsolutePath(),
|
||||
sigmundCertFile.getAbsolutePath());
|
||||
msgAscIn.close();
|
||||
|
||||
assertEquals(msg, out.toString());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
System.setOut(originalSout);
|
||||
// CHECKSTYLE:OFF
|
||||
System.out.println(tempDir.getAbsolutePath());
|
||||
// CHECKSTYLE:ON
|
||||
String verifications = readStringFromFile(verifyFile);
|
||||
assertFalse(verifications.trim().isEmpty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,28 +4,18 @@
|
|||
|
||||
package org.pgpainless.cli.misc;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.cli.PGPainlessCLI;
|
||||
import org.pgpainless.cli.TestUtils;
|
||||
import org.pgpainless.cli.commands.CLITest;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import sop.exception.SOPGPException;
|
||||
|
||||
public class SignUsingPublicKeyBehaviorTest {
|
||||
public class SignUsingPublicKeyBehaviorTest extends CLITest {
|
||||
|
||||
public static final String KEY_THAT_IS_A_CERT = "" +
|
||||
"-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||
|
@ -89,61 +79,24 @@ public class SignUsingPublicKeyBehaviorTest {
|
|||
"=oJQ2\n" +
|
||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||
|
||||
|
||||
private static File tempDir;
|
||||
private static PrintStream originalSout;
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() throws IOException {
|
||||
tempDir = TestUtils.createTempDirectory();
|
||||
public SignUsingPublicKeyBehaviorTest() {
|
||||
super(LoggerFactory.getLogger(SignUsingPublicKeyBehaviorTest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExpectSystemExitWithStatus(SOPGPException.KeyCannotSign.EXIT_CODE)
|
||||
public void testSignatureCreationAndVerification() throws IOException {
|
||||
originalSout = System.out;
|
||||
InputStream originalIn = System.in;
|
||||
|
||||
// Write alice key to disc
|
||||
File aliceKeyFile = new File(tempDir, "alice.key");
|
||||
assertTrue(aliceKeyFile.createNewFile());
|
||||
OutputStream aliceKeyOut = new FileOutputStream(aliceKeyFile);
|
||||
Streams.pipeAll(new ByteArrayInputStream(KEY_THAT_IS_A_CERT.getBytes(StandardCharsets.UTF_8)), aliceKeyOut);
|
||||
aliceKeyOut.close();
|
||||
|
||||
// Write alice pub key to disc
|
||||
File aliceCertFile = new File(tempDir, "alice.pub");
|
||||
assertTrue(aliceCertFile.createNewFile());
|
||||
OutputStream aliceCertOut = new FileOutputStream(aliceCertFile);
|
||||
Streams.pipeAll(new ByteArrayInputStream(KEY_THAT_IS_A_CERT.getBytes(StandardCharsets.UTF_8)), aliceCertOut);
|
||||
aliceCertOut.close();
|
||||
File aliceKeyFile = writeFile("alice.key", KEY_THAT_IS_A_CERT);
|
||||
|
||||
// Write test data to disc
|
||||
String data = "If privacy is outlawed, only outlaws will have privacy.\n";
|
||||
|
||||
File dataFile = new File(tempDir, "data");
|
||||
assertTrue(dataFile.createNewFile());
|
||||
FileOutputStream dataOut = new FileOutputStream(dataFile);
|
||||
Streams.pipeAll(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8)), dataOut);
|
||||
dataOut.close();
|
||||
File dataFile = writeFile("data", "If privacy is outlawed, only outlaws will have privacy.\n");
|
||||
|
||||
// Sign test data
|
||||
FileInputStream dataIn = new FileInputStream(dataFile);
|
||||
System.setIn(dataIn);
|
||||
File sigFile = new File(tempDir, "sig.asc");
|
||||
assertTrue(sigFile.createNewFile());
|
||||
FileOutputStream sigOut = new FileOutputStream(sigFile);
|
||||
System.setOut(new PrintStream(sigOut));
|
||||
PGPainlessCLI.main(new String[] {"sign", "--armor", aliceKeyFile.getAbsolutePath()});
|
||||
File sigFile = pipeStdoutToFile("sig.asc");
|
||||
pipeFileToStdin(dataFile);
|
||||
assertEquals(SOPGPException.KeyCannotSign.EXIT_CODE,
|
||||
executeCommand("sign", "--armor", aliceKeyFile.getAbsolutePath()));
|
||||
|
||||
System.setIn(originalIn);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
System.setOut(originalSout);
|
||||
// CHECKSTYLE:OFF
|
||||
System.out.println(tempDir.getAbsolutePath());
|
||||
// CHECKSTYLE:ON
|
||||
assertTrue(readStringFromFile(sigFile).trim().isEmpty());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ dependencies {
|
|||
// Bouncy Castle
|
||||
api "org.bouncycastle:bcprov-jdk18on:$bouncyCastleVersion"
|
||||
api "org.bouncycastle:bcpg-jdk18on:$bouncyPgVersion"
|
||||
api "org.bouncycastle:bcutil-jdk18on:$bouncyCastleVersion"
|
||||
// api(files("../libs/bcpg-jdk18on-1.70.jar"))
|
||||
|
||||
// @Nullable, @Nonnull annotations
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.io.ByteArrayInputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
import org.bouncycastle.bcpg.BCPGInputStream;
|
||||
import org.bouncycastle.openpgp.PGPCompressedData;
|
||||
|
@ -208,8 +209,8 @@ public class OpenPgpInputStream extends BufferedInputStream {
|
|||
}
|
||||
|
||||
try {
|
||||
SignatureType.valueOf(sigType);
|
||||
} catch (IllegalArgumentException e) {
|
||||
SignatureType.requireFromCode(sigType);
|
||||
} catch (NoSuchElementException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -236,8 +237,8 @@ public class OpenPgpInputStream extends BufferedInputStream {
|
|||
if (opsVersion == 3) {
|
||||
int opsSigType = bcpgIn.read();
|
||||
try {
|
||||
SignatureType.valueOf(opsSigType);
|
||||
} catch (IllegalArgumentException e) {
|
||||
SignatureType.requireFromCode(opsSigType);
|
||||
} catch (NoSuchElementException e) {
|
||||
return;
|
||||
}
|
||||
int opsHashAlg = bcpgIn.read();
|
||||
|
|
|
@ -28,7 +28,14 @@ public class SignatureValidationException extends PGPException {
|
|||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(rejections.size()).append(" rejected signatures:\n");
|
||||
for (PGPSignature signature : rejections.keySet()) {
|
||||
sb.append(SignatureType.valueOf(signature.getSignatureType())).append(' ')
|
||||
String typeString;
|
||||
SignatureType type = SignatureType.fromCode(signature.getSignatureType());
|
||||
if (type == null) {
|
||||
typeString = "0x" + Long.toHexString(signature.getSignatureType());
|
||||
} else {
|
||||
typeString = type.toString();
|
||||
}
|
||||
sb.append(typeString).append(' ')
|
||||
.append(signature.getCreationTime()).append(": ")
|
||||
.append(rejections.get(signature).getMessage()).append('\n');
|
||||
}
|
||||
|
|
|
@ -34,7 +34,11 @@ public final class OpenPgpKeyAttributeUtil {
|
|||
continue;
|
||||
}
|
||||
|
||||
SignatureType signatureType = SignatureType.valueOf(signature.getSignatureType());
|
||||
SignatureType signatureType = SignatureType.fromCode(signature.getSignatureType());
|
||||
if (signatureType == null) {
|
||||
// unknown signature type
|
||||
continue;
|
||||
}
|
||||
if (signatureType == SignatureType.POSITIVE_CERTIFICATION
|
||||
|| signatureType == SignatureType.GENERIC_CERTIFICATION) {
|
||||
int[] hashAlgos = signature.getHashedSubPackets().getPreferredHashAlgorithms();
|
||||
|
@ -71,8 +75,8 @@ public final class OpenPgpKeyAttributeUtil {
|
|||
continue;
|
||||
}
|
||||
|
||||
SignatureType signatureType = SignatureType.valueOf(signature.getSignatureType());
|
||||
if (signatureType != SignatureType.POSITIVE_CERTIFICATION
|
||||
SignatureType signatureType = SignatureType.fromCode(signature.getSignatureType());
|
||||
if (signatureType == null || signatureType != SignatureType.POSITIVE_CERTIFICATION
|
||||
&& signatureType != SignatureType.GENERIC_CERTIFICATION) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,8 @@ enum class SignatureType(val code: Int) {
|
|||
|
||||
@JvmStatic
|
||||
fun isRevocationSignature(signatureType: Int): Boolean {
|
||||
return isRevocationSignature(valueOf(signatureType))
|
||||
val sigType = fromCode(signatureType)
|
||||
return sigType?.let { isRevocationSignature(it) } ?: false
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
|
|
|
@ -77,7 +77,8 @@ fun PGPSignature.wasIssuedBy(key: PGPPublicKey): Boolean = wasIssuedBy(OpenPgpFi
|
|||
/** Return true, if this signature is a hard revocation. */
|
||||
val PGPSignature.isHardRevocation
|
||||
get() =
|
||||
when (SignatureType.requireFromCode(signatureType)) {
|
||||
when (SignatureType.fromCode(signatureType)) {
|
||||
null -> false
|
||||
SignatureType.KEY_REVOCATION,
|
||||
SignatureType.SUBKEY_REVOCATION,
|
||||
SignatureType.CERTIFICATION_REVOCATION -> {
|
||||
|
@ -104,4 +105,4 @@ val PGPSignature.signatureHashAlgorithm: HashAlgorithm
|
|||
get() = HashAlgorithm.requireFromId(hashAlgorithm)
|
||||
|
||||
fun PGPSignature.isOfType(type: SignatureType): Boolean =
|
||||
SignatureType.requireFromCode(signatureType) == type
|
||||
SignatureType.fromCode(signatureType) == type
|
||||
|
|
|
@ -4,7 +4,11 @@
|
|||
|
||||
package org.pgpainless.decryption_verification
|
||||
|
||||
import org.bouncycastle.bcpg.AEADEncDataPacket
|
||||
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey
|
||||
import org.bouncycastle.openpgp.PGPSessionKey
|
||||
import org.bouncycastle.openpgp.operator.PGPDataDecryptor
|
||||
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory
|
||||
import org.bouncycastle.util.encoders.Base64
|
||||
import org.pgpainless.key.SubkeyIdentifier
|
||||
|
@ -21,16 +25,34 @@ import org.pgpainless.key.SubkeyIdentifier
|
|||
class CachingBcPublicKeyDataDecryptorFactory(
|
||||
privateKey: PGPPrivateKey,
|
||||
override val subkeyIdentifier: SubkeyIdentifier
|
||||
) : BcPublicKeyDataDecryptorFactory(privateKey), CustomPublicKeyDataDecryptorFactory {
|
||||
) : CustomPublicKeyDataDecryptorFactory() {
|
||||
|
||||
private val decryptorFactory: BcPublicKeyDataDecryptorFactory =
|
||||
BcPublicKeyDataDecryptorFactory(privateKey)
|
||||
private val cachedSessions: MutableMap<String, ByteArray> = mutableMapOf()
|
||||
|
||||
override fun createDataDecryptor(p0: Boolean, p1: Int, p2: ByteArray?): PGPDataDecryptor {
|
||||
return decryptorFactory.createDataDecryptor(p0, p1, p2)
|
||||
}
|
||||
|
||||
override fun createDataDecryptor(p0: AEADEncDataPacket?, p1: PGPSessionKey?): PGPDataDecryptor {
|
||||
return decryptorFactory.createDataDecryptor(p0, p1)
|
||||
}
|
||||
|
||||
override fun createDataDecryptor(
|
||||
p0: SymmetricEncIntegrityPacket?,
|
||||
p1: PGPSessionKey?
|
||||
): PGPDataDecryptor {
|
||||
return decryptorFactory.createDataDecryptor(p0, p1)
|
||||
}
|
||||
|
||||
override fun recoverSessionData(
|
||||
keyAlgorithm: Int,
|
||||
secKeyData: Array<out ByteArray>
|
||||
secKeyData: Array<out ByteArray>,
|
||||
pkeskVersion: Int
|
||||
): ByteArray =
|
||||
lookupSessionKeyData(secKeyData)
|
||||
?: costlyRecoverSessionData(keyAlgorithm, secKeyData).also {
|
||||
?: costlyRecoverSessionData(keyAlgorithm, secKeyData, pkeskVersion).also {
|
||||
cacheSessionKeyData(secKeyData, it)
|
||||
}
|
||||
|
||||
|
@ -39,8 +61,9 @@ class CachingBcPublicKeyDataDecryptorFactory(
|
|||
|
||||
private fun costlyRecoverSessionData(
|
||||
keyAlgorithm: Int,
|
||||
secKeyData: Array<out ByteArray>
|
||||
): ByteArray = super.recoverSessionData(keyAlgorithm, secKeyData)
|
||||
secKeyData: Array<out ByteArray>,
|
||||
pkeskVersion: Int
|
||||
): ByteArray = decryptorFactory.recoverSessionData(keyAlgorithm, secKeyData, pkeskVersion)
|
||||
|
||||
private fun cacheSessionKeyData(secKeyData: Array<out ByteArray>, sessionKey: ByteArray) {
|
||||
cachedSessions[toKey(secKeyData)] = sessionKey.clone()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
package org.pgpainless.decryption_verification
|
||||
|
||||
import org.bouncycastle.openpgp.operator.AbstractPublicKeyDataDecryptorFactory
|
||||
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory
|
||||
import org.pgpainless.key.SubkeyIdentifier
|
||||
|
||||
|
@ -14,7 +15,7 @@ import org.pgpainless.key.SubkeyIdentifier
|
|||
*
|
||||
* @see [ConsumerOptions.addCustomDecryptorFactory]
|
||||
*/
|
||||
interface CustomPublicKeyDataDecryptorFactory : PublicKeyDataDecryptorFactory {
|
||||
abstract class CustomPublicKeyDataDecryptorFactory : AbstractPublicKeyDataDecryptorFactory() {
|
||||
|
||||
/**
|
||||
* Identifier for the subkey for which this particular [CustomPublicKeyDataDecryptorFactory] is
|
||||
|
@ -22,5 +23,5 @@ interface CustomPublicKeyDataDecryptorFactory : PublicKeyDataDecryptorFactory {
|
|||
*
|
||||
* @return subkey identifier
|
||||
*/
|
||||
val subkeyIdentifier: SubkeyIdentifier
|
||||
abstract val subkeyIdentifier: SubkeyIdentifier
|
||||
}
|
||||
|
|
|
@ -29,11 +29,17 @@ class HardwareSecurity {
|
|||
* @param keyId id of the key
|
||||
* @param keyAlgorithm algorithm
|
||||
* @param sessionKeyData encrypted session key
|
||||
* @param pkeskVersion version of the Public-Key-Encrypted-Session-Key packet (3 or 6)
|
||||
* @return decrypted session key
|
||||
* @throws HardwareSecurityException exception
|
||||
*/
|
||||
@Throws(HardwareSecurityException::class)
|
||||
fun decryptSessionKey(keyId: Long, keyAlgorithm: Int, sessionKeyData: ByteArray): ByteArray
|
||||
fun decryptSessionKey(
|
||||
keyId: Long,
|
||||
keyAlgorithm: Int,
|
||||
sessionKeyData: ByteArray,
|
||||
pkeskVersion: Int
|
||||
): ByteArray
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -44,7 +50,7 @@ class HardwareSecurity {
|
|||
class HardwareDataDecryptorFactory(
|
||||
override val subkeyIdentifier: SubkeyIdentifier,
|
||||
private val callback: DecryptionCallback,
|
||||
) : CustomPublicKeyDataDecryptorFactory {
|
||||
) : CustomPublicKeyDataDecryptorFactory() {
|
||||
|
||||
// luckily we can instantiate the BcPublicKeyDataDecryptorFactory with null as argument.
|
||||
private val factory: PublicKeyDataDecryptorFactory = BcPublicKeyDataDecryptorFactory(null)
|
||||
|
@ -73,10 +79,12 @@ class HardwareSecurity {
|
|||
|
||||
override fun recoverSessionData(
|
||||
keyAlgorithm: Int,
|
||||
secKeyData: Array<out ByteArray>
|
||||
secKeyData: Array<out ByteArray>,
|
||||
pkeskVersion: Int
|
||||
): ByteArray {
|
||||
return try {
|
||||
callback.decryptSessionKey(subkeyIdentifier.subkeyId, keyAlgorithm, secKeyData[0])
|
||||
callback.decryptSessionKey(
|
||||
subkeyIdentifier.subkeyId, keyAlgorithm, secKeyData[0], pkeskVersion)
|
||||
} catch (e: HardwareSecurityException) {
|
||||
throw PGPException("Hardware-backed decryption failed.", e)
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ class CRLFGeneratorStream(private val crlfOut: OutputStream, encoding: StreamEnc
|
|||
}
|
||||
|
||||
override fun close() {
|
||||
if (!isBinary && lastB == 'r'.code) {
|
||||
if (!isBinary && lastB == '\r'.code) {
|
||||
crlfOut.write('\n'.code)
|
||||
}
|
||||
crlfOut.close()
|
||||
|
|
|
@ -45,7 +45,7 @@ class KeyRingBuilder : KeyRingBuilderInterface<KeyRingBuilder> {
|
|||
}
|
||||
|
||||
override fun addUserId(userId: CharSequence): KeyRingBuilder = apply {
|
||||
userIds[userId.toString().trim()] = null
|
||||
userIds[userId.toString()] = null
|
||||
}
|
||||
|
||||
override fun addUserId(userId: ByteArray): KeyRingBuilder =
|
||||
|
|
|
@ -67,11 +67,9 @@ abstract class KeyAccessor(protected val info: KeyRingInfo, protected val key: S
|
|||
info.getLatestUserIdCertification(userId).let { if (it != null) return it }
|
||||
}
|
||||
|
||||
if (info.latestDirectKeySelfSignature != null) {
|
||||
return info.latestDirectKeySelfSignature
|
||||
}
|
||||
|
||||
return info.getCurrentSubkeyBindingSignature(key.subkeyId)!!
|
||||
return info.getCurrentSubkeyBindingSignature(key.subkeyId)
|
||||
?: throw NoSuchElementException(
|
||||
"Key does not carry acceptable self-signature signature.")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -172,11 +172,8 @@ class KeyRingInfo(
|
|||
primaryUserIdCertification?.let { getKeyExpirationTimeAsDate(it, publicKey) }
|
||||
|
||||
if (latestDirectKeySelfSignature == null && primaryUserIdCertification == null) {
|
||||
/*
|
||||
throw NoSuchElementException(
|
||||
"No direct-key signature and no user-id signature found.")
|
||||
*/
|
||||
return null
|
||||
}
|
||||
if (directKeyExpirationDate != null && userIdExpirationDate == null) {
|
||||
return directKeyExpirationDate
|
||||
|
@ -405,7 +402,7 @@ class KeyRingInfo(
|
|||
.plus(signatures.userIdRevocations.values)
|
||||
.plus(signatures.subkeyBindings.values)
|
||||
.plus(signatures.subkeyRevocations.values)
|
||||
.maxByOrNull { creationDate }
|
||||
.maxByOrNull { it.creationTime }
|
||||
/**
|
||||
* Return the creation time of the latest added subkey.
|
||||
*
|
||||
|
|
|
@ -478,7 +478,7 @@ class SecretKeyRingEditor(
|
|||
val prevBinding =
|
||||
inspectKeyRing(secretKeyRing).getCurrentSubkeyBindingSignature(keyId)
|
||||
?: throw NoSuchElementException(
|
||||
"Previous subkey binding signaure for ${keyId.openPgpKeyId()} MUST NOT be null.")
|
||||
"Previous subkey binding signature for ${keyId.openPgpKeyId()} MUST NOT be null.")
|
||||
val bindingSig = reissueSubkeyBindingSignature(subkey, expiration, protector, prevBinding)
|
||||
secretKeyRing = injectCertification(secretKeyRing, subkey, bindingSig)
|
||||
}
|
||||
|
@ -569,9 +569,10 @@ class SecretKeyRingEditor(
|
|||
}
|
||||
|
||||
private fun sanitizeUserId(userId: CharSequence): CharSequence =
|
||||
// TODO: Further research how to sanitize user IDs.
|
||||
// e.g. what about newlines?
|
||||
userId.toString().trim()
|
||||
// I'm not sure, what kind of sanitization is needed.
|
||||
// Newlines are allowed, they just need to be escaped when emitted in an ASCII armor header
|
||||
// Trailing/Leading whitespace is also fine.
|
||||
userId.toString()
|
||||
|
||||
private fun callbackFromRevocationAttributes(attributes: RevocationAttributes?) =
|
||||
object : RevocationSignatureSubpackets.Callback {
|
||||
|
|
|
@ -52,7 +52,7 @@ class RevocationSignatureBuilder : AbstractSignatureBuilder<RevocationSignatureB
|
|||
require(revokeeKey.isMasterKey) {
|
||||
"Signature type is KEY_REVOCATION, but provided revokee does not appear to be a primary key."
|
||||
}
|
||||
it.generateCertification(publicSigningKey)
|
||||
it.generateCertification(revokeeKey)
|
||||
} else {
|
||||
it.generateCertification(publicSigningKey, revokeeKey)
|
||||
}
|
||||
|
|
|
@ -235,7 +235,8 @@ abstract class SignatureValidator {
|
|||
signature: PGPSignature,
|
||||
policy: Policy
|
||||
): Policy.HashAlgorithmPolicy {
|
||||
return when (SignatureType.requireFromCode(signature.signatureType)) {
|
||||
return when (SignatureType.fromCode(signature.signatureType)) {
|
||||
null -> policy.certificationSignatureHashAlgorithmPolicy
|
||||
SignatureType.CERTIFICATION_REVOCATION,
|
||||
SignatureType.KEY_REVOCATION,
|
||||
SignatureType.SUBKEY_REVOCATION -> policy.revocationSignatureHashAlgorithmPolicy
|
||||
|
@ -598,7 +599,8 @@ abstract class SignatureValidator {
|
|||
if (signatureType.none { signature.isOfType(it) }) {
|
||||
throw SignatureValidationException(
|
||||
"Signature is of type" +
|
||||
" ${SignatureType.requireFromCode(signature.signatureType)}, " +
|
||||
" ${SignatureType.fromCode(signature.signatureType) ?:
|
||||
("0x" + signature.signatureType.toString(16))}, " +
|
||||
"while only ${signatureType.contentToString()} are allowed here.")
|
||||
}
|
||||
}
|
||||
|
@ -688,7 +690,7 @@ abstract class SignatureValidator {
|
|||
}
|
||||
if (notAfter != null && timestamp > notAfter) {
|
||||
throw SignatureValidationException(
|
||||
"Signature was made before the latest allowed signature creation time." +
|
||||
"Signature was made after the latest allowed signature creation time." +
|
||||
" Created: ${timestamp.formatUTC()}," +
|
||||
" latest allowed: ${notAfter.formatUTC()}")
|
||||
}
|
||||
|
|
|
@ -59,12 +59,13 @@ class SignatureVerifier {
|
|||
policy: Policy,
|
||||
referenceTime: Date
|
||||
): Boolean {
|
||||
val type = SignatureType.requireFromCode(signature.signatureType)
|
||||
val type = SignatureType.fromCode(signature.signatureType)
|
||||
return when (type) {
|
||||
SignatureType.GENERIC_CERTIFICATION,
|
||||
SignatureType.NO_CERTIFICATION,
|
||||
SignatureType.CASUAL_CERTIFICATION,
|
||||
SignatureType.POSITIVE_CERTIFICATION ->
|
||||
SignatureType.POSITIVE_CERTIFICATION,
|
||||
null ->
|
||||
verifyUserIdCertification(
|
||||
userId, signature, signingKey, keyWithUserId, policy, referenceTime)
|
||||
SignatureType.CERTIFICATION_REVOCATION ->
|
||||
|
|
|
@ -247,7 +247,9 @@ class ArmorUtils {
|
|||
.add(OpenPgpFingerprint.of(publicKey).prettyPrint())
|
||||
// Primary / First User ID
|
||||
(primary ?: first)?.let {
|
||||
headerMap.getOrPut(HEADER_COMMENT) { mutableSetOf() }.add(it)
|
||||
headerMap
|
||||
.getOrPut(HEADER_COMMENT) { mutableSetOf() }
|
||||
.add(it.replace("\n", "\\n").replace("\r", "\\r"))
|
||||
}
|
||||
// X-1 further identities
|
||||
when (userIds.size) {
|
||||
|
|
|
@ -11,14 +11,9 @@ import org.bouncycastle.util.Arrays
|
|||
*
|
||||
* @param chars may be null for empty passwords.
|
||||
*/
|
||||
class Passphrase(chars: CharArray?) {
|
||||
class Passphrase(private val chars: CharArray?) {
|
||||
private val lock = Any()
|
||||
private var valid = true
|
||||
private val chars: CharArray?
|
||||
|
||||
init {
|
||||
this.chars = trimWhitespace(chars)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of the underlying char array. A return value of null represents an empty
|
||||
|
@ -67,6 +62,13 @@ class Passphrase(chars: CharArray?) {
|
|||
|
||||
override fun hashCode(): Int = getChars()?.let { String(it) }.hashCode()
|
||||
|
||||
/**
|
||||
* Return a copy of this [Passphrase], but with whitespace characters trimmed off.
|
||||
*
|
||||
* @return copy with trimmed whitespace
|
||||
*/
|
||||
fun withTrimmedWhitespace(): Passphrase = Passphrase(trimWhitespace(chars))
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package org.pgpainless.algorithm;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -31,6 +30,6 @@ public class SignatureTypeTest {
|
|||
assertFalse(SignatureType.isRevocationSignature(SignatureType.STANDALONE.getCode()));
|
||||
assertFalse(SignatureType.isRevocationSignature(SignatureType.TIMESTAMP.getCode()));
|
||||
|
||||
assertThrows(IllegalArgumentException.class, () -> SignatureType.isRevocationSignature(-3));
|
||||
assertFalse(SignatureType.isRevocationSignature(-3));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.io.ByteArrayOutputStream;
|
|||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.bouncycastle.bcpg.ArmoredOutputStream;
|
||||
import org.bouncycastle.bcpg.CompressionAlgorithmTags;
|
||||
|
@ -30,6 +31,9 @@ import org.bouncycastle.openpgp.operator.bc.BcPGPContentSignerBuilder;
|
|||
import org.bouncycastle.util.io.Streams;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.algorithm.DocumentSignatureType;
|
||||
import org.pgpainless.algorithm.HashAlgorithm;
|
||||
|
@ -288,11 +292,9 @@ public class CanonicalizedDataEncryptionTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resultOfDecryptionIsCRLFEncoded() throws PGPException, IOException {
|
||||
String before = "Foo\nBar!\n";
|
||||
String after = "Foo\r\nBar!\r\n";
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("resultOfDecryptionIsCRLFEncodedArguments")
|
||||
public void resultOfDecryptionIsCRLFEncoded(String before, String after) throws PGPException, IOException {
|
||||
String encrypted = encryptAndSign(before, DocumentSignatureType.BINARY_DOCUMENT, StreamEncoding.TEXT, true);
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(encrypted.getBytes(StandardCharsets.UTF_8));
|
||||
|
@ -309,6 +311,16 @@ public class CanonicalizedDataEncryptionTest {
|
|||
assertArrayEquals(after.getBytes(StandardCharsets.UTF_8), decrypted.toByteArray());
|
||||
}
|
||||
|
||||
private static Stream<Arguments> resultOfDecryptionIsCRLFEncodedArguments() {
|
||||
return Stream.of(
|
||||
Arguments.of("foo", "foo"),
|
||||
Arguments.of("rrr", "rrr"),
|
||||
Arguments.of("Foo\nBar!\n", "Foo\r\nBar!\r\n"),
|
||||
Arguments.of("Foo\rBar!\r", "Foo\r\nBar!\r\n"),
|
||||
Arguments.of("Foo\r\nBar!\r\n", "Foo\r\nBar!\r\n")
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resultOfDecryptionIsNotCRLFEncoded() throws PGPException, IOException {
|
||||
String beforeAndAfter = "Foo\nBar!\n";
|
||||
|
|
|
@ -55,14 +55,14 @@ public class CustomPublicKeyDataDecryptorFactoryTest {
|
|||
|
||||
HardwareSecurity.DecryptionCallback hardwareDecryptionCallback = new HardwareSecurity.DecryptionCallback() {
|
||||
@Override
|
||||
public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData)
|
||||
public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData, int pkeskVersion)
|
||||
throws HardwareSecurity.HardwareSecurityException {
|
||||
// Emulate hardware decryption.
|
||||
try {
|
||||
PGPSecretKey decryptionKey = secretKey.getSecretKey(encryptionKey.getKeyID());
|
||||
PGPPrivateKey privateKey = UnlockSecretKey.unlockSecretKey(decryptionKey, Passphrase.emptyPassphrase());
|
||||
PublicKeyDataDecryptorFactory internal = new BcPublicKeyDataDecryptorFactory(privateKey);
|
||||
return internal.recoverSessionData(keyAlgorithm, new byte[][] {sessionKeyData});
|
||||
return internal.recoverSessionData(keyAlgorithm, new byte[][] {sessionKeyData}, pkeskVersion);
|
||||
} catch (PGPException e) {
|
||||
throw new HardwareSecurity.HardwareSecurityException();
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class MessageMetadataTest {
|
|||
@Test
|
||||
public void processTestMessage_COMP_ENC_ENC_LIT() {
|
||||
// Note: COMP of ENC does not make sense, since ENC is indistinguishable from randomness
|
||||
// and randomness cannot be encrypted.
|
||||
// and randomness cannot be compressed.
|
||||
// For the sake of testing though, this is okay.
|
||||
MessageMetadata.Message message = new MessageMetadata.Message();
|
||||
|
||||
|
|
|
@ -1,111 +0,0 @@
|
|||
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.key
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import org.bouncycastle.openpgp.PGPPublicKey
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||
import org.bouncycastle.util.io.Streams
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.KeyFlag
|
||||
import org.pgpainless.decryption_verification.ConsumerOptions
|
||||
import org.pgpainless.encryption_signing.EncryptionOptions
|
||||
import org.pgpainless.encryption_signing.ProducerOptions
|
||||
import org.pgpainless.encryption_signing.SigningOptions
|
||||
import org.pgpainless.key.generation.KeySpec
|
||||
import org.pgpainless.key.generation.type.KeyType
|
||||
import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve
|
||||
import org.pgpainless.key.generation.type.xdh_legacy.XDHLegacySpec
|
||||
import org.pgpainless.key.protection.SecretKeyRingProtector
|
||||
|
||||
class KeyWithoutSelfSigsTest {
|
||||
|
||||
@Test
|
||||
fun signAndVerify() {
|
||||
val key = PGPainless.readKeyRing().secretKeyRing(KEY)
|
||||
val cert = PGPainless.extractCertificate(key!!)
|
||||
|
||||
val ciphertextOut = ByteArrayOutputStream()
|
||||
val encryptionStream =
|
||||
PGPainless.encryptAndOrSign()
|
||||
.onOutputStream(ciphertextOut)
|
||||
.withOptions(
|
||||
ProducerOptions.signAndEncrypt(
|
||||
EncryptionOptions.encryptCommunications().addRecipient(cert),
|
||||
SigningOptions.get()
|
||||
.addSignature(SecretKeyRingProtector.unprotectedKeys(), key)))
|
||||
encryptionStream.write("Hello, World!\n".toByteArray())
|
||||
encryptionStream.close()
|
||||
|
||||
val plaintextOut = ByteArrayOutputStream()
|
||||
val decryptionStream =
|
||||
PGPainless.decryptAndOrVerify()
|
||||
.onInputStream(ciphertextOut.toByteArray().inputStream())
|
||||
.withOptions(
|
||||
ConsumerOptions.get()
|
||||
.addVerificationCert(cert)
|
||||
.addDecryptionKey(key, SecretKeyRingProtector.unprotectedKeys()))
|
||||
Streams.pipeAll(decryptionStream, plaintextOut)
|
||||
decryptionStream.close()
|
||||
}
|
||||
|
||||
fun generateKey() {
|
||||
val key =
|
||||
PGPainless.buildKeyRing()
|
||||
.setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519)))
|
||||
.addSubkey(
|
||||
KeySpec.getBuilder(
|
||||
KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA))
|
||||
.addSubkey(
|
||||
KeySpec.getBuilder(
|
||||
KeyType.XDH_LEGACY(XDHLegacySpec._X25519),
|
||||
KeyFlag.ENCRYPT_STORAGE,
|
||||
KeyFlag.ENCRYPT_COMMS))
|
||||
.build()
|
||||
.let {
|
||||
var cert = PGPainless.extractCertificate(it)
|
||||
cert =
|
||||
PGPPublicKeyRing(
|
||||
buildList {
|
||||
val iterator = cert.publicKeys
|
||||
val primaryKey = iterator.next()
|
||||
add(
|
||||
PGPPublicKey.removeCertification(
|
||||
primaryKey, primaryKey.signatures.next()))
|
||||
while (iterator.hasNext()) {
|
||||
add(iterator.next())
|
||||
}
|
||||
})
|
||||
PGPSecretKeyRing.replacePublicKeys(it, cert)
|
||||
}
|
||||
println(PGPainless.asciiArmor(key))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val KEY =
|
||||
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||
"Version: PGPainless\n" +
|
||||
"Comment: DA3E CC77 1CD6 46F0 C6C4 4FDA 86A3 7B22 7802 2FC7\n" +
|
||||
"\n" +
|
||||
"lFgEZUuWuhYJKwYBBAHaRw8BAQdAuXfarON/+UG1qwhVy4/VCYuEb9iLFLb8KGQt\n" +
|
||||
"KfX4Se0AAQDgqGHsb2M43F+6wK5Hla+oZzFkTUsBx8HMpRx2yeQT6hFAnFgEZUuW\n" +
|
||||
"uhYJKwYBBAHaRw8BAQdAx0OHISLtekltdUVGGrG/Gs3asc/jG/nqCkBEZ5uyELwA\n" +
|
||||
"AP0faf8bprP3fj248/NacfynKEVnjzc1gocfhGiWrnVgAxC1iNUEGBYKAH0FAmVL\n" +
|
||||
"lroCngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJlS5a6AAoJED9gFx9r\n" +
|
||||
"B25syqoA/0JR3Zcs6fHQ0jW7+u6330SD5h8WvG78IKsE6AfChBLXAP4hlXGidztq\n" +
|
||||
"5sOHEQvXD2KPCHEJ6MuQ+rbNSSf0fQhgDwAKCRCGo3sieAIvxzmIAP9+9vRoevUM\n" +
|
||||
"luQhZzQ7DgYqTCyNkeq2cpVgOfa0lyVDgwEApwrd5DlU3GorGHAQHFS6jhw1IOoG\n" +
|
||||
"FGQ3zpWaOXd7XwKcXQRlS5a6EgorBgEEAZdVAQUBAQdAZIY7ISyNzp0oMoK0dgb8\n" +
|
||||
"dX6t/i4Uh+l0jnxM0Z1dEB8DAQgHAAD/fhL5dzdJQ7hFhr78AmDEZKFE4txZFPvd\n" +
|
||||
"ZVFvIWTthFgQ5Ih1BBgWCgAdBQJlS5a6Ap4BApsMBRYCAwEABAsJCAcFFQoJCAsA\n" +
|
||||
"CgkQhqN7IngCL8cIGgEAzydjTfKvdrTvzXXu97j8TAoOxk89QnLqsM6BU0VsVmkA\n" +
|
||||
"/1IzH+PXgPPW9ff+elxTi2NWmK+P033P6i5b5Jdf41YD\n" +
|
||||
"=GBVS\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----"
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ To start using pgpainless-sop in your code, include the following lines in your
|
|||
...
|
||||
dependencies {
|
||||
...
|
||||
implementation "org.pgpainless:pgpainless-sop:1.7.0"
|
||||
implementation "org.pgpainless:pgpainless-sop:1.7.6"
|
||||
...
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ dependencies {
|
|||
<dependency>
|
||||
<groupId>org.pgpainless</groupId>
|
||||
<artifactId>pgpainless-sop</artifactId>
|
||||
<version>1.7.0</version>
|
||||
<version>1.7.6</version>
|
||||
</dependency>
|
||||
...
|
||||
</dependencies>
|
||||
|
@ -67,7 +67,7 @@ byte[] encrypted = sop.encrypt()
|
|||
|
||||
// Decrypt a message
|
||||
ByteArrayAndResult<DecryptionResult> messageAndVerifications = sop.decrypt()
|
||||
.verifyWith(cert)
|
||||
.verifyWithCert(cert)
|
||||
.withKey(key)
|
||||
.ciphertext(encrypted)
|
||||
.toByteArrayAndResult();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import org.apache.tools.ant.filters.*
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ dependencies {
|
|||
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
|
||||
|
||||
// Depend on "shared" sop-java test suite (fixtures are turned into tests by inheritance inside test sources)
|
||||
testImplementation(testFixtures("org.pgpainless:sop-java:$sopJavaVersion"))
|
||||
testImplementation "org.pgpainless:sop-java-testfixtures:$sopJavaVersion"
|
||||
|
||||
implementation(project(":pgpainless-core"))
|
||||
api "org.pgpainless:sop-java:$sopJavaVersion"
|
||||
|
@ -30,6 +30,12 @@ dependencies {
|
|||
implementation "com.google.code.findbugs:jsr305:3.0.2"
|
||||
}
|
||||
|
||||
processResources {
|
||||
filter ReplaceTokens, tokens: [
|
||||
"project.version": project.version.toString()
|
||||
]
|
||||
}
|
||||
|
||||
test {
|
||||
useJUnitPlatform()
|
||||
environment("test.implementation", "sop.testsuite.pgpainless.PGPainlessSopInstanceFactory")
|
||||
|
|
|
@ -12,7 +12,6 @@ import org.bouncycastle.util.io.Streams
|
|||
import org.pgpainless.decryption_verification.OpenPgpInputStream
|
||||
import org.pgpainless.util.ArmoredOutputStreamFactory
|
||||
import sop.Ready
|
||||
import sop.enums.ArmorLabel
|
||||
import sop.exception.SOPGPException
|
||||
import sop.operation.Armor
|
||||
|
||||
|
@ -46,9 +45,4 @@ class ArmorImpl : Armor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated("Setting custom labels is not supported.")
|
||||
override fun label(label: ArmorLabel): Armor {
|
||||
throw SOPGPException.UnsupportedOption("Setting custom Armor labels not supported.")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ class DecryptImpl : Decrypt {
|
|||
}
|
||||
|
||||
override fun verifyWithCert(cert: InputStream): Decrypt = apply {
|
||||
KeyReader.readPublicKeys(cert, true)?.let { consumerOptions.addVerificationCerts(it) }
|
||||
KeyReader.readPublicKeys(cert, true).let { consumerOptions.addVerificationCerts(it) }
|
||||
}
|
||||
|
||||
override fun withKey(key: InputStream): Decrypt = apply {
|
||||
|
@ -107,10 +107,10 @@ class DecryptImpl : Decrypt {
|
|||
}
|
||||
|
||||
override fun withPassword(password: String): Decrypt = apply {
|
||||
consumerOptions.addDecryptionPassphrase(Passphrase.fromPassword(password))
|
||||
consumerOptions.addMessagePassphrase(Passphrase.fromPassword(password))
|
||||
password.trimEnd().let {
|
||||
if (it != password) {
|
||||
consumerOptions.addDecryptionPassphrase(Passphrase.fromPassword(it))
|
||||
consumerOptions.addMessagePassphrase(Passphrase.fromPassword(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing
|
|||
import org.bouncycastle.openpgp.PGPSignature
|
||||
import org.bouncycastle.util.io.Streams
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||
import org.pgpainless.algorithm.DocumentSignatureType
|
||||
import org.pgpainless.algorithm.HashAlgorithm
|
||||
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
|
||||
|
@ -57,7 +58,10 @@ class DetachedSignImpl : DetachedSign {
|
|||
val signingStream =
|
||||
PGPainless.encryptAndOrSign()
|
||||
.discardOutput()
|
||||
.withOptions(ProducerOptions.sign(signingOptions).setAsciiArmor(armor))
|
||||
.withOptions(
|
||||
ProducerOptions.sign(signingOptions)
|
||||
.setAsciiArmor(armor)
|
||||
.overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED))
|
||||
|
||||
return object : ReadyWithResult<SigningResult>() {
|
||||
override fun writeTo(outputStream: OutputStream): SigningResult {
|
||||
|
|
|
@ -136,7 +136,7 @@ class EncryptImpl : Encrypt {
|
|||
}
|
||||
|
||||
override fun withPassword(password: String): Encrypt = apply {
|
||||
encryptionOptions.addPassphrase(Passphrase.fromPassword(password))
|
||||
encryptionOptions.addMessagePassphrase(Passphrase.fromPassword(password))
|
||||
}
|
||||
|
||||
private fun modeToStreamEncoding(mode: EncryptAs): StreamEncoding {
|
||||
|
|
|
@ -34,7 +34,7 @@ class InlineDetachImpl : InlineDetach {
|
|||
|
||||
private val sigOut = ByteArrayOutputStream()
|
||||
|
||||
override fun writeTo(messageOutputStream: OutputStream): Signatures {
|
||||
override fun writeTo(outputStream: OutputStream): Signatures {
|
||||
var pgpIn = OpenPgpInputStream(messageInputStream)
|
||||
if (pgpIn.isNonOpenPgp) {
|
||||
throw SOPGPException.BadData("Data appears to be non-OpenPGP.")
|
||||
|
@ -50,7 +50,7 @@ class InlineDetachImpl : InlineDetach {
|
|||
try {
|
||||
signatures =
|
||||
ClearsignedMessageUtil.detachSignaturesFromInbandClearsignedMessage(
|
||||
armorIn, messageOutputStream)
|
||||
armorIn, outputStream)
|
||||
if (signatures.isEmpty) {
|
||||
throw SOPGPException.BadData(
|
||||
"Data did not contain OpenPGP signatures.")
|
||||
|
@ -86,7 +86,7 @@ class InlineDetachImpl : InlineDetach {
|
|||
if (next is PGPLiteralData) {
|
||||
// Write out contents of Literal Data packet
|
||||
val literalIn = (next as PGPLiteralData).dataStream
|
||||
Streams.pipeAll(literalIn, messageOutputStream)
|
||||
Streams.pipeAll(literalIn, outputStream)
|
||||
literalIn.close()
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@ import org.bouncycastle.openpgp.PGPException
|
|||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||
import org.bouncycastle.util.io.Streams
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.CompressionAlgorithm
|
||||
import org.pgpainless.algorithm.DocumentSignatureType
|
||||
import org.pgpainless.algorithm.StreamEncoding
|
||||
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
|
||||
import org.pgpainless.encryption_signing.ProducerOptions
|
||||
import org.pgpainless.encryption_signing.SigningOptions
|
||||
|
@ -56,12 +58,22 @@ class InlineSignImpl : InlineSign {
|
|||
|
||||
val producerOptions =
|
||||
ProducerOptions.sign(signingOptions).apply {
|
||||
if (mode == InlineSignAs.clearsigned) {
|
||||
setCleartextSigned()
|
||||
setAsciiArmor(true) // CSF is always armored
|
||||
} else {
|
||||
setAsciiArmor(armor)
|
||||
when (mode) {
|
||||
InlineSignAs.clearsigned -> {
|
||||
setCleartextSigned()
|
||||
setAsciiArmor(true) // CSF is always armored
|
||||
setEncoding(StreamEncoding.TEXT)
|
||||
applyCRLFEncoding()
|
||||
}
|
||||
InlineSignAs.text -> {
|
||||
setEncoding(StreamEncoding.TEXT)
|
||||
applyCRLFEncoding()
|
||||
}
|
||||
else -> {
|
||||
setAsciiArmor(armor)
|
||||
}
|
||||
}
|
||||
overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED)
|
||||
}
|
||||
|
||||
return object : Ready() {
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.io.IOException
|
|||
import java.io.InputStream
|
||||
import java.util.*
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import sop.SOP
|
||||
import sop.operation.Version
|
||||
|
||||
/** Implementation of the `version` operation using PGPainless. */
|
||||
|
@ -25,14 +26,14 @@ class VersionImpl : Version {
|
|||
String.format(Locale.US, "Bouncy Castle %.2f", BouncyCastleProvider().version)
|
||||
val specVersion = String.format("%02d", SOP_VERSION)
|
||||
return """${getName()} ${getVersion()}
|
||||
https://codeberg.org/PGPainless/pgpainless/src/branch/master/pgpainless-sop
|
||||
https://codeberg.org/PGPainless/pgpainless/src/branch/main/pgpainless-sop
|
||||
|
||||
Implementation of the Stateless OpenPGP Protocol Version $specVersion
|
||||
https://datatracker.ietf.org/doc/html/draft-dkg-openpgp-stateless-cli-$specVersion
|
||||
|
||||
Based on pgpainless-core ${getVersion()}
|
||||
https://pgpainless.org
|
||||
|
||||
${formatSopJavaVersion()}
|
||||
Using $bcVersion
|
||||
https://www.bouncycastle.org/java.html"""
|
||||
}
|
||||
|
@ -49,15 +50,27 @@ https://www.bouncycastle.org/java.html"""
|
|||
// See https://stackoverflow.com/a/50119235
|
||||
return try {
|
||||
val resourceIn: InputStream =
|
||||
javaClass.getResourceAsStream("/version.properties")
|
||||
?: throw IOException("File version.properties not found.")
|
||||
SOP::class.java.getResourceAsStream("/pgpainless-sop.properties")
|
||||
?: throw IOException("File pgpainless-sop.properties not found.")
|
||||
|
||||
val properties = Properties().apply { load(resourceIn) }
|
||||
properties.getProperty("version")
|
||||
properties.getProperty("pgpainless-sop-version")
|
||||
} catch (e: IOException) {
|
||||
"DEVELOPMENT"
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatSopJavaVersion(): String {
|
||||
return getSopJavaVersion()?.let {
|
||||
"""
|
||||
|
||||
sop-java $it
|
||||
|
||||
"""
|
||||
.trimIndent()
|
||||
}
|
||||
?: ""
|
||||
}
|
||||
|
||||
override fun isSopSpecImplementationIncomplete(): Boolean = false
|
||||
}
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
# SPDX-FileCopyrightText: 2025 Paul Schaub <info@pgpainless.org>
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
pgpainless-sop-version=@project.version@
|
|
@ -100,4 +100,14 @@ public class GenerateKeyTest {
|
|||
assertThrows(SOPGPException.UnsupportedProfile.class, () ->
|
||||
sop.generateKey().profile("invalid"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generateKeyWithNewlinesInUserId() throws IOException {
|
||||
byte[] keyBytes = sop.generateKey()
|
||||
.userId("Foo\n\nBar")
|
||||
.generate()
|
||||
.getBytes();
|
||||
|
||||
assertTrue(new String(keyBytes).contains("Foo\\n\\nBar"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package org.pgpainless.sop;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.policy.Policy;
|
||||
import sop.ByteArrayAndResult;
|
||||
import sop.Verification;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
|
||||
public class VerifyLegacySignatureTest {
|
||||
|
||||
@Test
|
||||
public void verifyLegacySignature() throws IOException {
|
||||
// Key generated in 2012 using SHA1 for self sigs
|
||||
String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||
"Version: PGPainless\n" +
|
||||
"Comment: 21FA 6E60 D6C9 B7D1 0EAC 56A2 984B 91CF D303 214C\n" +
|
||||
"Comment: Legacy <legacy@example.com>\n" +
|
||||
"\n" +
|
||||
"lQVYBFDUVsABDADg6AuFsM0JckT7spS/1KNdobaZ1vrOFhGdyXbJ1jUkbMwi+f5o\n" +
|
||||
"UtQsfeFQRBHeQFfmtt4mo6lE6cAsQFJPFat/ReNxCwCqHi5QbennpbueHJ5N2KVj\n" +
|
||||
"YrIz6eeTsVKs16gS17zLOMkeBt0TK8+Vu7HHfqLqQ1jNNGujwPydUbO8M431XKeW\n" +
|
||||
"WhM9ziV9m/20nHYJGIM+aN9AicxtR+khFsNjpRlCMg+8kKUelP2FDWv/5QZwnSXc\n" +
|
||||
"nMFaCJiH1hx56027AB8PZrUW+ShRhqb0P3EhOt+Gs3IW39rGjc9iQVEWl7745BTZ\n" +
|
||||
"xEZ4FO84DQQtdKBp510VN8LfiZkO7K9JKOo+vqL4IvSBCJNRVvxDxInShHfVyht7\n" +
|
||||
"jJJvEC0mxv1Oi8rZ/g9iNd6/Ijthi3svNd3DwNFyMzhrbggynEyWr8nu17Zz0c6C\n" +
|
||||
"KT7XtFZWOUmio8G14KH6dFRCt7TGRw7mz059ViICMN56Ka5LJaQgGRbT+omY2CQJ\n" +
|
||||
"q5eSkZMXLndmjtUAEQEAAQAL+QFsyzhLl/oLPs0+63JrTaXPY9s5EpNEkHYTgN29\n" +
|
||||
"HTUELKdWFBaa7M9sBbCJmiODdEB0mfT+yGW9R6wPCXiaEj8ysMt0QvVzG03Qr6pX\n" +
|
||||
"kWCmHSuW5ZQHytJjDJMA0T+3K0fQWWFPC/bmX12+1Flw4qI9g6oigub1aF4eJFdV\n" +
|
||||
"XVq7vhadY9aSIiGtJnX+PqiRIIwPeRDfMjsvwA6H/1dwftltRnbLVr0vnUutRnPv\n" +
|
||||
"ZGbiOim35bWubLW55Ehycb4T4KyW70Xq0Lljr04/33d7S/SUNHXM/ci2kFDEkJb8\n" +
|
||||
"N+rssxaVjgPsn9+5wQFDEcrewdMLgaRHSrEf46GvcYMbM8lfnzrDyhYc5+vc24b5\n" +
|
||||
"85WCVYaYKFrJGEa1vHAMmDwXqDNETtDtaYXZpNsUqvjlG+lU4/p0zeqGfyIDLnzK\n" +
|
||||
"R5zAmWQkd4aSrgN4F6/7xQ1npnvBq/eZiHJx4sBsPMS10TFPPi3A9jEAiu0eljTq\n" +
|
||||
"E7eXqDObHD8xSjQ3gm9fBclTUQYA4vVChPT9SgJo2aY5ug+2nLWfv4hgK2LTRNkt\n" +
|
||||
"exEelaU3vrl83a/HEljg3DZ63P6odRIv0HGRl4YSOEC5CANDcDqjz34p7T6suRU5\n" +
|
||||
"GzrZHey33joLj9oAGF+2HefmHpvWc8ZzFaS14XiO4m9TMMLZwSokNyhccHl7FSYZ\n" +
|
||||
"XqxzXD2JnaM+m3XMGRVnASQ2gtmsv8dpXuto+gF/9W1b8kyPp1sjtgup2O4PjiQg\n" +
|
||||
"1uQMpx6H3OSC8tCH3f9/MvlVTpgtBgD9r5PnN5h6fQd6MQl7UEdTU3jIOcXrr1xh\n" +
|
||||
"0rQkTQx1WJ29f/tr/sGPb3HgPcpk+x6xctRVpW6yf6OLBP02CnJllBYE73tqIxxa\n" +
|
||||
"qK+3kDAqIa9n/Ds8SZTH/45JXDFLay5g7kFMpv6dxUUMtdJ8INmcChVPxKeUB5DZ\n" +
|
||||
"iGMzmCTsR0RxvEIc3ofht7mrMhH361xUZGbIMP6ykZZNlE4FmOW4zBATa8o4V3gl\n" +
|
||||
"mdbIYopEGPwAuj1gIy0G7fLL0cayEkkF/RI7uep4d2QY87mC+fswbiPWM3mp6/7i\n" +
|
||||
"e2JLmA2bdDju7SL6X4DMgV8RQakOlQf17JEGA4HrKi3odugiBjdXWv6ZmfcIIPgq\n" +
|
||||
"ns2Us6wCcr4uqCxEvYj2fUd/q03ui5aglLTqSSuNtnB9yww0EYrj9qjHFIi/ByrF\n" +
|
||||
"L6DVBrMDJ0BwHY5LkY1OWot4GyjLE43Uqu0ObZhFSMttGQkRxdae0R9+4NPR7Dlw\n" +
|
||||
"B8+zwytxGRs1NgTy7O+KRl9e3K05bgUXVNsJtBtMZWdhY3kgPGxlZ2FjeUBleGFt\n" +
|
||||
"cGxlLmNvbT6JAdAEEwECAEQJEJhLkc/TAyFMFiEEIfpuYNbJt9EOrFaimEuRz9MD\n" +
|
||||
"IUwFglDUVsACngECmwMFFgIDAQAECwkIBwIVAgWJH6AIMQKZAQAAWU0L/jUvlxt0\n" +
|
||||
"TLLFTcT1tQWvy1MBLJcdiXuoN0/w1Rcz54iSCgWeuNZ5BD6qwCMORmVG1fMuvtCt\n" +
|
||||
"Lq4NZizE63QfeFE8q22vrNDoZ5pAnjC7KlMMjq1ykQHN7cqH1FgxrS3PrBo1k8/s\n" +
|
||||
"0P6863Vlso02YYbWluJt4HbnX0vEap4/z05RLBCQyZyiaon5zad5rNd0z1nXfMC8\n" +
|
||||
"EPRK9MsjBX5/5zhx6RPwCrAlrk5dKZ3Nks6bquTCme8sayBgBHX0Tjeum+3sfwiE\n" +
|
||||
"Jn2xTYJU6cB7fWYREi9E9z7YrmpVCjDkh8U7p0MLC3dmIYUT3EDL5F0jxTReoX+B\n" +
|
||||
"7f8HrKUIOyvLlAJs4oxYG/g9QHzVFSAbekwf3Jnwm4Czd6qPx62gI6na11ku64Ua\n" +
|
||||
"RezZ3NkTInSXi1+Bi7mT4qVcV6Z6vl5YXe8T/Zihcv5/Wp4bNEJ2dHJlhwVAn8Ax\n" +
|
||||
"Ykl8S2ZVfQ5hN8gWLRW40wnCrbuNUdWI/el9D1arc8AQclXfF8/4kULTq50FWARQ\n" +
|
||||
"1FbAAQwAv/eK+LYwdkUoGfATB6wcmqaJFrjFIaKYbM1VEWckb4FYc0T1yc9MEq65\n" +
|
||||
"gz1/PUPt+XwQCa/gP5iCcVuze91ksJVkoeOjy/CQgMD1D1s0IVikVMvOKqdnVa4k\n" +
|
||||
"SxkLkOvVdzZ5QebDbE5QqfTupyr/SgWarm7TYb4HVFNG5xXVh8+uFMpLe897E+/K\n" +
|
||||
"mSQMZZ8vdKVvnEm+EOlm0ZzRml4kM8k1LyVxJdoLUJ0t5Ac7B1k/Xq0Fz1Pl3Yjr\n" +
|
||||
"xahxvz68gTph+uL0IlnxKIt+lI2YKTaZ/QZ6POzif0UHLH4akEoTLjzlzkgNYdiI\n" +
|
||||
"O3ZekqHViYtlX0brc7TYo3iip1LIvv3NMI7QskA2v9V1NWcf/cPBt0uwJ2wMDDDy\n" +
|
||||
"bckrrwwsfNn6qFxY3xFo1aexzgpG2C9ZVpIDLMd3F6SUoqrrmAHJLoP0dSYBVujO\n" +
|
||||
"EAJdPqvLC45KJFgXu6IrBqFrx+WTACJCvgoF8XLLhEba99CwmS8Rc2luS+G3iB8l\n" +
|
||||
"YQlj5QWXABEBAAEAC/wMe00lhe/f7ZGbIVYun4ahZfnWTyxyI9JPvYh62ZjJSNqD\n" +
|
||||
"B2IIo/PitLDXObGcpPgQl3wR3sYKT7sOuwZ2ihsFgd38yk8lVktVZwM7SZQGi9VT\n" +
|
||||
"gu59+eVPV6oaDLmimJ+7YQCNXZj2ewXmDXwe+Aq7ucjCIrtklY7m14Tt4MH1H9z5\n" +
|
||||
"X3xJw2A4GAiCRvfClV3oJbTJSRPH1Ouch9r3c7uPqm6zPBBmHg4Yr1k2hGNwKa6X\n" +
|
||||
"IOtJyb8ebzKogJ7n7zo4Cpst01PkdLPnXK3fTEBYjuBQa5F2sSvT89uK3seN3J7W\n" +
|
||||
"OP05lCcg1k9e4bnD9uGlba0fhsgUhqTEg3za6MNcVezPqRXGXlkWH5gjxbVQHu8B\n" +
|
||||
"Y8Ix9YvWhCwIA25bSE51bTq2vQuCTaRG5fXVWD8qZ043APcB99c9zW9OvmiJzH47\n" +
|
||||
"zYk+rB+lByK8/KiaXUqcKjyUniXc9LKda71xb4MwoBuBF9RdCsQvHwFRibdpMd0t\n" +
|
||||
"a9O7RoTFKPxhUewySoEGANTBWhstEUlsytFMSeNmCmpNR2/mKbuE+n78+zaPCmLF\n" +
|
||||
"TsLWxil+y3FrJCvffn9k5shtxLADtEvKJKWl/vjXxh9DXzFvMgRPsrETzAkg0zwr\n" +
|
||||
"+5P8d26x4xcnQaE59RQIhyiJPsT4fXqld+kaKDng0vYkVRGHSIC//NPMPA2KaTdC\n" +
|
||||
"4EQvEx702dF3/+tIDwXO/kjk6taEEOv0W5nj0aHm+JtEw+X0ja1VvUcDx50Ttwpc\n" +
|
||||
"LzojtWjFpBNFHLGZyWac4QYA5vx6WsovX9j3YXkYDHbN+r8rCfL/16+z+qEJ/pbw\n" +
|
||||
"2eevICtB4KLcqXlep4rSLhDJlYphxZfHhsVahwX1ga+fGDB/AuDozJhtfQp7evwN\n" +
|
||||
"NH5IIAT3o56iBUIO2CywWcdkY+HMo787MbITfvVOdOrGE8hRcCFdkZepaSwfbTRz\n" +
|
||||
"LZH+jKAU6xOgInuoPVLOOIIlLaTVb6TTRV9BXyRUdele0DqbZIMCwE8P53kFuGuM\n" +
|
||||
"sRZQ1RNha8H7WU2T2m7QxDl3Bf4+KYQ5AfFPkGZKMQcIJy4CR7hSP9gk3/4B06RM\n" +
|
||||
"DH3c4rmd50CPpQ5TTA0cGCthOnYVewUgJaxQjKAToX8xCQYFRO59YOc8PMVZ/xgf\n" +
|
||||
"kGrEkX4tlwECbjoWx2kWT4uZvYmnUzfDdXXr8E+9h2ziEKobF0/b9HQB5BKKLycr\n" +
|
||||
"KzoTKbV4En1602VltRInAfnjpmQ7VSYV/JyoHJ824d/7O+fLLZkmyibLiSMWPwYu\n" +
|
||||
"z9rt26lC3cT/HSMrG3L0jjdWH7bYaIkBsAQYAQIAGgWCUNRWwAKeAQKbDAUWAgMB\n" +
|
||||
"AAQLCQgHAhUCAAoJEJhLkc/TAyFMEn4MAKI6RC+VUJr+p2bMf5Pbfml/iy5QsRBG\n" +
|
||||
"J1iTyPzu8yJUzHs60y6YckGrIKSFE5x6a6utz/CdtpIlb9e/FJvl82zjxJkFjhre\n" +
|
||||
"fhHjcu6iIvLCCer6v1XtL4frx6Qoi6TGmlKXWvaLTuRINQFomLwScoHRW1QSQHTE\n" +
|
||||
"BNUmIo89nRU5PQ8LJBGZWzdkVqVmdbK8ek5ycuolwLUQizbeGIhJo/9IIC2i2RCJ\n" +
|
||||
"hMVsmbjHB1zdVbwPZuwtCH7ROr4xTLp9Gwq1XcIRYY5am/SyBLgkwKSyrXQs6Zsr\n" +
|
||||
"2qRd2+ccBF0UYFxvH9JOKmBS6QGwtnAYRqbeeCj8Lx3mgAIv15kGeKd72ezFi0ZT\n" +
|
||||
"smO3dpb6pSD44BSsdvjZdHENCxYIbBsroDZrZGShygluOCrFjG//PSSbrNE+Bz70\n" +
|
||||
"imnM2QH/XaS6rpbNPGfrn0Vw5M/ZFT/9PWrEg4ZdCI32ei5uyjYwL7aPAPS3MqkB\n" +
|
||||
"SV9g8CiU0cX7hiBYYpktcDVU3uRCR4Fkvw==\n" +
|
||||
"=n8qw\n" +
|
||||
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||
// Sig generated in 2012 using SHA1
|
||||
String oldSig = "-----BEGIN PGP MESSAGE-----\n" +
|
||||
"Version: PGPainless\n" +
|
||||
"\n" +
|
||||
"owEB2gEl/pANAwACAZhLkc/TAyFMAcsTYgAAAAAASGVsbG8sIFdvcmxkIYkBswQA\n" +
|
||||
"AQIAJwkQmEuRz9MDIUwWIQQh+m5g1sm30Q6sVqKYS5HP0wMhTAWCUNRWwAAALxEL\n" +
|
||||
"/2uhYsTLM8nUnYm2GJB6pkapX1kbQrqfAhK46IjxcPpRdl6CW4cFrG6iFegx4YLE\n" +
|
||||
"fu44VKG+XGy/RTZXIEJubi9zVyOGGJM9Bwwdcp/eekO16/kJ7BsbkaO+5AG/fNeg\n" +
|
||||
"bL5C8D2m6jV1seAt/+tRyM9jLkRi9odq8BsGA6ZcthAxh3MUoo1yw3QwwEcFFHg/\n" +
|
||||
"gBw4ZtL8KIQN1PKDz3sSV4GXPQAiz+/uADZ2lL6mbDEK/gXAK1KevIO3U8ZU9B6l\n" +
|
||||
"cOF9fJww31SCqFGDq50Lzwz7eySJB1TZ0IoehGDXoQ8JF88uTVfACkBATE0Zx7zg\n" +
|
||||
"TAYIgPSjWY4TEDZ9YjdxJ0hKTMncxVfZPB+J/mYCpVADYSEhLbUJ1ntjc0s35xJD\n" +
|
||||
"udLSwUWuboedVdEcaqnfgHoaaV+nKk+6F9y8NO56RK3Bfx5FmKmNZHbhfXO/qRt9\n" +
|
||||
"H43UktMUD6xWxxJv7mutThOp2aizBeboa5YSJ1mxtkPW0/lyK1jr438ETHUnCeu6\n" +
|
||||
"Vw==\n" +
|
||||
"=TtKx\n" +
|
||||
"-----END PGP MESSAGE-----";
|
||||
|
||||
SOPImpl sop = new SOPImpl();
|
||||
byte[] cert = sop.extractCert().key(KEY.getBytes(StandardCharsets.UTF_8))
|
||||
.getBytes();
|
||||
ByteArrayAndResult<List<Verification>> result = sop.inlineVerify()
|
||||
.cert(cert)
|
||||
.data(oldSig.getBytes(StandardCharsets.UTF_8))
|
||||
.toByteArrayAndResult();
|
||||
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
|
||||
// Adjust data signature hash policy to accept new SHA-1 sigs
|
||||
PGPainless.getPolicy().setDataSignatureHashAlgorithmPolicy(
|
||||
Policy.HashAlgorithmPolicy.static2022RevocationSignatureHashAlgorithmPolicy());
|
||||
|
||||
// Sig generated in 2024 using SHA1
|
||||
String newSig = "-----BEGIN PGP MESSAGE-----\n" +
|
||||
"Version: PGPainless\n" +
|
||||
"\n" +
|
||||
"owEB2gEl/pANAwACAZhLkc/TAyFMAcsTYgAAAAAASGVsbG8sIFdvcmxkIYkBswQA\n" +
|
||||
"AQIAJwWCZw5i2AkQmEuRz9MDIUwWIQQh+m5g1sm30Q6sVqKYS5HP0wMhTAAAhVML\n" +
|
||||
"+QGH+O2fEJoAY8ZxKz/mosg4it9IeSzMhBvDgZJE8Jc+VGk7EuXL0M8pfHL+Jgmv\n" +
|
||||
"FMzF3chzzLS7QA4K6hbxO31/M8TNSU12geuzQiBV7Kb1hjpvIObBgEqYsX50ZV8r\n" +
|
||||
"5DHcr7huABUOH6tCKmCA2OxOvr1QV8X39h856bz3WqqP9HW8kZ6H1Z6d7XWlRMtW\n" +
|
||||
"mAnSevvOJbb0Z3D97obYqytSLzi2Jyv+w2R9kYzMQff2Rl6Cv4F7zsRrF9JRC0m6\n" +
|
||||
"X/s+VSNuT2yG0/4F5y8vrxvNkfd8YfM8DM6irJV4yJyVuwIoZnM913XCA4F7Uo4t\n" +
|
||||
"Z8ER17SY4WOYvdja/7qPcOUjX5n1dDU0W7q2muqnZXREw2JXTULiDl0MET3K4kFu\n" +
|
||||
"a6FyyMGGQwFpAnZ4gDZKzw06abd95AgHx4QlkD89J7MnUBBV+AGHNAQlCPPEVPQq\n" +
|
||||
"dWTInYndt4GKCUxVkJeHD6ZPLdxEEvICmEap4FQzhqM8U7weoEsSinoVoc4JmSY9\n" +
|
||||
"dQ==\n" +
|
||||
"=XrzP\n" +
|
||||
"-----END PGP MESSAGE-----";
|
||||
result = sop.inlineVerify()
|
||||
.cert(cert)
|
||||
.data(newSig.getBytes(StandardCharsets.UTF_8))
|
||||
.toByteArrayAndResult();
|
||||
|
||||
assertFalse(result.getResult().isEmpty());
|
||||
}
|
||||
}
|
|
@ -4,16 +4,15 @@
|
|||
|
||||
allprojects {
|
||||
ext {
|
||||
shortVersion = '1.7.0'
|
||||
isSnapshot = false
|
||||
pgpainlessMinAndroidSdk = 10
|
||||
javaSourceCompatibility = 1.8
|
||||
bouncyCastleVersion = '1.78.1'
|
||||
shortVersion = '1.7.7'
|
||||
isSnapshot = true
|
||||
javaSourceCompatibility = 11
|
||||
bouncyCastleVersion = '1.81'
|
||||
bouncyPgVersion = bouncyCastleVersion
|
||||
junitVersion = '5.8.2'
|
||||
logbackVersion = '1.4.14'
|
||||
logbackVersion = '1.5.13'
|
||||
mockitoVersion = '4.5.1'
|
||||
slf4jVersion = '1.7.36'
|
||||
sopJavaVersion = '10.0.1'
|
||||
sopJavaVersion = '10.1.1'
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue