diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index d45b16a3..031ba56d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -36,7 +36,7 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'java-kotlin' ] + language: [ 'java' ] # 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@v3 + uses: github/codeql-action/init@v2 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@v3 + uses: github/codeql-action/autobuild@v2 # â„šī¸ 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@v3 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/gradle_push.yml b/.github/workflows/gradle_push.yml index 8c03a399..e4624726 100644 --- a/.github/workflows/gradle_push.yml +++ b/.github/workflows/gradle_push.yml @@ -28,13 +28,9 @@ jobs: with: java-version: '11' distribution: 'temurin' - - name: Build and Check - uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 - with: - arguments: check jacocoRootReport - - name: Coveralls + - name: Build, Check and Coverage uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1 env: COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} with: - arguments: coveralls + arguments: check jacocoRootReport coveralls \ No newline at end of file diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 00000000..7703aa47 --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,86 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: PGPainless +Upstream-Contact: Paul Schaub +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 +License: CC0-1.0 + +# Documentation +Files: docs/* +Copyright: 2022 Paul Schaub +License: CC-BY-3.0 + +Files: .readthedocs.yaml +Copyright: 2022 Paul Schaub +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 +License: CC-BY-3.0 + +Files: assets/pgpainless.svg +Copyright: 2021 Paul Schaub +License: CC-BY-3.0 + +Files: assets/logo.png +Copyright: 2022 Paul Schaub +License: CC-BY-3.0 + +Files: assets/test_vectors/* +Copyright: 2018 Paul Schaub +License: CC0-1.0 + +Files: pgpainless-core/src/test/resources/* +Copyright: 2020 Paul Schaub +License: CC0-1.0 + +Files: audit/* +Copyright: 2021 Paul Schaub +License: CC0-1.0 + +# GH Pages +Files: CNAME +Copyright: 2022 Paul Schaub +License: CC0-1.0 + +Files: _config.yml +Copyright: 2022 Paul Schaub +License: CC0-1.0 + +Files: _layouts/* +Copyright: 2022 Paul Schaub , 2017 Steve Smith +License: CC-BY-SA-3.0 + +# Man Pages +Files: pgpainless-cli/rewriteManPages.sh +Copyright: 2022 Paul Schaub +License: Apache-2.0 + +Files: pgpainless-cli/packaging/man/* +Copyright: 2022 Paul Schaub +License: Apache-2.0 + +# Github Issue Templates +Files: .github/ISSUE_TEMPLATE/* +Copyright: 2024 Paul Schaub +License: CC0-1.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 13c93c07..0f1af4ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,42 +5,6 @@ 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.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` @@ -71,11 +35,6 @@ 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) diff --git a/README.md b/README.md index e305e43a..3ba3b028 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ This behaviour can be modified though using the `Policy` class. DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() .onInputStream(encryptedInputStream) .withOptions(new ConsumerOptions() - .addDecryptionKey(bobSecKeys, secretKeyProtector) + .addMessagePassphrase(bobSecKeys, secretKeyProtector) .addVerificationCert(alicePubKeys) ); @@ -191,7 +191,7 @@ repositories { } dependencies { - implementation 'org.pgpainless:pgpainless-core:1.7.6' + implementation 'org.pgpainless:pgpainless-core:1.7.1' } ``` @@ -222,6 +222,9 @@ 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). [![NGI Assure Logo](https://blog.jabberhead.tk/wp-content/uploads/2022/05/NGIAssure_tag.svg)](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! +[![YourKit Logo](https://www.yourkit.com/images/yklogo.png)](https://www.yourkit.com/) + Big thank you also to those who decided to support the work by donating! Notably @msfjarvis diff --git a/REUSE.toml b/REUSE.toml deleted file mode 100644 index 66b5e867..00000000 --- a/REUSE.toml +++ /dev/null @@ -1,118 +0,0 @@ -version = 1 -SPDX-PackageName = "PGPainless" -SPDX-PackageSupplier = "Paul Schaub " -SPDX-PackageDownloadLocation = "https://pgpainless.org" - -[[annotations]] -path = "REUSE.toml" -precedence = "aggregate" -SPDX-FileCopyrightText = "2025 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" - -[[annotations]] -path = ".git-blame-ignore-revs" -precedence = "aggregate" -SPDX-FileCopyrightText = "2023 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" - -[[annotations]] -path = "docs/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub " -SPDX-License-Identifier = "CC-BY-3.0" - -[[annotations]] -path = ".readthedocs.yaml" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub " -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 " -SPDX-License-Identifier = "CC-BY-3.0" - -[[annotations]] -path = "assets/pgpainless.svg" -precedence = "aggregate" -SPDX-FileCopyrightText = "2021 Paul Schaub " -SPDX-License-Identifier = "CC-BY-3.0" - -[[annotations]] -path = "assets/logo.png" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub " -SPDX-License-Identifier = "CC-BY-3.0" - -[[annotations]] -path = "assets/test_vectors/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2018 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" - -[[annotations]] -path = "pgpainless-core/src/test/resources/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2020 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" - -[[annotations]] -path = "audit/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2021 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" - -[[annotations]] -path = "CNAME" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" - -[[annotations]] -path = "_config.yml" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" - -[[annotations]] -path = "_layouts/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub , 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 " -SPDX-License-Identifier = "Apache-2.0" - -[[annotations]] -path = "pgpainless-cli/rewriteManPages.sh" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub " -SPDX-License-Identifier = "Apache-2.0" - -[[annotations]] -path = "pgpainless-cli/packaging/man/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2022 Paul Schaub " -SPDX-License-Identifier = "Apache-2.0" - -[[annotations]] -path = ".github/ISSUE_TEMPLATE/**" -precedence = "aggregate" -SPDX-FileCopyrightText = "2024 Paul Schaub " -SPDX-License-Identifier = "CC0-1.0" diff --git a/build.gradle b/build.gradle index 93100f4d..04b8a0af 100644 --- a/build.gradle +++ b/build.gradle @@ -33,17 +33,24 @@ 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.25.0' + toolVersion = '10.12.1' } spotless { @@ -56,6 +63,8 @@ allprojects { description = "Simple to use OpenPGP API for Java based on Bouncycastle" version = shortVersion + sourceCompatibility = javaSourceCompatibility + repositories { mavenCentral() mavenLocal() @@ -70,10 +79,6 @@ 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 { @@ -114,7 +119,7 @@ allprojects { sourceDirectories.setFrom(project.files(sourceSets.main.allSource.srcDirs)) classDirectories.setFrom(project.files(sourceSets.main.output)) reports { - xml.required = true + xml.enabled true } } @@ -132,15 +137,15 @@ subprojects { apply plugin: 'signing' task sourcesJar(type: Jar, dependsOn: classes) { - archiveClassifier = 'sources' + classifier = 'sources' from sourceSets.main.allSource } task javadocJar(type: Jar, dependsOn: javadoc) { - archiveClassifier = 'javadoc' + classifier = 'javadoc' from javadoc.destinationDir } task testsJar(type: Jar, dependsOn: testClasses) { - archiveClassifier = 'tests' + classifier = 'tests' from sourceSets.test.output } @@ -237,7 +242,7 @@ task jacocoRootReport(type: JacocoReport) { classDirectories.setFrom(files(subprojects.sourceSets.main.output)) executionData.setFrom(files(subprojects.jacocoTestReport.executionData)) reports { - xml.required = true + xml.enabled true xml.destination file("${buildDir}/reports/jacoco/test/jacocoTestReport.xml") } // We could remove the following setOnlyIf line, but then @@ -248,6 +253,10 @@ 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') @@ -261,6 +270,18 @@ 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. * @@ -270,13 +291,34 @@ task mavenCentralChecksums() { description 'Fetch and display checksums for artifacts published to Maven Central' String ver = project.hasProperty('release') ? release : shortVersion doLast { - 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" - } + 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" } } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 0d184210..8049c684 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/pgpainless-cli/build.gradle b/pgpainless-cli/build.gradle index e4c3f060..3d9a6a09 100644 --- a/pgpainless-cli/build.gradle +++ b/pgpainless-cli/build.gradle @@ -4,13 +4,27 @@ plugins { id 'application' - id 'org.graalvm.buildtools.native' version '0.10.6' - id 'com.gradleup.shadow' version '8.3.6' + id "com.github.johnrengelman.shadow" version "6.1.0" +} +def generatedVersionDir = "${buildDir}/generated-version" + +sourceSets { + main { + output.dir(generatedVersionDir, builtBy: 'generateVersionProperties') + } } -graalvmNative { - toolchainDetection = true +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()) + } } +processResources.dependsOn generateVersionProperties dependencies { @@ -18,12 +32,13 @@ 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 "org.slf4j:slf4j-nop:$slf4jVersion" + implementation "ch.qos.logback:logback-classic:$logbackVersion" implementation(project(":pgpainless-sop")) implementation "org.pgpainless:sop-java-picocli:$sopJavaVersion" @@ -37,6 +52,22 @@ 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 @@ -46,3 +77,5 @@ run { args Eval.me(appArgs) } } + +// tasks."jar".dependsOn(":pgpainless-core:assemble", ":pgpainless-sop:assemble") diff --git a/pgpainless-cli/src/main/java/org/pgpainless/cli/PGPainlessCLI.java b/pgpainless-cli/src/main/java/org/pgpainless/cli/PGPainlessCLI.java index 7625dd17..938bf1aa 100644 --- a/pgpainless-cli/src/main/java/org/pgpainless/cli/PGPainlessCLI.java +++ b/pgpainless-cli/src/main/java/org/pgpainless/cli/PGPainlessCLI.java @@ -14,10 +14,6 @@ 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()); } diff --git a/pgpainless-cli/src/main/resources/META-INF/native-image/jni-config.json b/pgpainless-cli/src/main/resources/META-INF/native-image/jni-config.json deleted file mode 100644 index 32960f8c..00000000 --- a/pgpainless-cli/src/main/resources/META-INF/native-image/jni-config.json +++ /dev/null @@ -1,2 +0,0 @@ -[ -] \ No newline at end of file diff --git a/pgpainless-cli/src/main/resources/META-INF/native-image/predefined-classes-config.json b/pgpainless-cli/src/main/resources/META-INF/native-image/predefined-classes-config.json deleted file mode 100644 index 84789507..00000000 --- a/pgpainless-cli/src/main/resources/META-INF/native-image/predefined-classes-config.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "type":"agent-extracted", - "classes":[ - ] - } -] diff --git a/pgpainless-cli/src/main/resources/META-INF/native-image/proxy-config.json b/pgpainless-cli/src/main/resources/META-INF/native-image/proxy-config.json deleted file mode 100644 index 32960f8c..00000000 --- a/pgpainless-cli/src/main/resources/META-INF/native-image/proxy-config.json +++ /dev/null @@ -1,2 +0,0 @@ -[ -] \ No newline at end of file diff --git a/pgpainless-cli/src/main/resources/META-INF/native-image/reflect-config.json b/pgpainless-cli/src/main/resources/META-INF/native-image/reflect-config.json deleted file mode 100644 index 63bdf5f3..00000000 --- a/pgpainless-cli/src/main/resources/META-INF/native-image/reflect-config.json +++ /dev/null @@ -1,891 +0,0 @@ -[ -{ - "name":"[Ljava.lang.Object;" -}, -{ - "name":"ch.qos.logback.classic.encoder.PatternLayoutEncoder", - "queryAllPublicMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"ch.qos.logback.classic.joran.SerializedModelConfigurator", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"ch.qos.logback.classic.util.DefaultJoranConfigurator", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"ch.qos.logback.core.ConsoleAppender", - "queryAllPublicMethods":true, - "methods":[{"name":"","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":"","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":"","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":"","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":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.CONTEXT$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.CompositeSignatures$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.DH$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.DSA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.DSTU4145$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.Dilithium$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.EC$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.ECGOST$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.EXTERNAL$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.EdEC$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.ElGamal$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.Falcon$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.GM$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.GOST$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.IES$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.LMS$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.MLDSA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.MLKEM$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.NTRU$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.NoSig$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.RSA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.SLHDSA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.SPHINCSPlus$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.X509$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi$EdDSA", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.edec.KeyPairGeneratorSpi$XDH", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyPairGeneratorSpi", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Blake2b$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Blake2s$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Blake3$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.DSTU7564$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.GOST3411$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Haraka$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Keccak$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.MD2$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.MD4$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.MD5$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD128$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD160$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD256$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.RIPEMD320$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.SHA1$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.SHA224$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.SHA256$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.SHA3$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.SHA384$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.SHA512$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.SM3$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Skein$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Tiger$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.digest.Whirlpool$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.drbg.DRBG$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.keystore.BC$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.keystore.BCFKS$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.keystore.PKCS12$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.AES$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.ARC4$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.ARIA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Blowfish$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.CAST5$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.CAST6$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Camellia$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.ChaCha$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.DES$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.DESede$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.DSTU7624$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.GOST28147$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.GOST3412_2015$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Grain128$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Grainv1$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.HC128$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.HC256$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.IDEA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Noekeon$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.OpenSSLPBKDF$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF1$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPBKDF2$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.PBEPKCS12$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Poly1305$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.RC2$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.RC5$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.RC6$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Rijndael$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.SCRYPT$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.SEED$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.SM4$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Salsa20$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Serpent$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Shacal2$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.SipHash$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.SipHash128$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Skipjack$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.TEA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.TLSKDF$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Threefish$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Twofish$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.VMPC$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.VMPCKSA3$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.XSalsa20$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.XTEA$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.bouncycastle.jcajce.provider.symmetric.Zuc$Mappings", - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"org.pgpainless.cli.ExitCodeTest", - "allDeclaredFields":true, - "allDeclaredClasses":true, - "queryAllDeclaredMethods":true, - "queryAllPublicMethods":true, - "queryAllDeclaredConstructors":true, - "methods":[{"name":"","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":"","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":"","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":"","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":"","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":"","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":"","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":"","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":"","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":"","parameterTypes":[] }, {"name":"encryptAndDecryptAMessage","parameterTypes":[] }] -}, -{ - "name":"org.pgpainless.cli.commands.RoundTripSignVerifyCmdTest", - "allDeclaredFields":true, - "allDeclaredClasses":true, - "queryAllDeclaredMethods":true, - "queryAllPublicMethods":true, - "queryAllDeclaredConstructors":true, - "methods":[{"name":"","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":"","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":"","parameterTypes":[] }, {"name":"testSignatureCreationAndVerification","parameterTypes":[] }] -}, -{ - "name":"picocli.AutoComplete$GenerateCompletion", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","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":"","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":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.ChangeKeyPasswordCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true -}, -{ - "name":"sop.cli.picocli.commands.DearmorCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.DecryptCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.EncryptCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.ExtractCertCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.GenerateKeyCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.InlineDetachCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.InlineSignCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.InlineVerifyCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.ListProfilesCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.RevokeKeyCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true -}, -{ - "name":"sop.cli.picocli.commands.SignCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.VerifyCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.VersionCmd", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sop.cli.picocli.commands.VersionCmd$Exclusive", - "allDeclaredFields":true, - "queryAllDeclaredMethods":true, - "methods":[{"name":"","parameterTypes":[] }] -}, -{ - "name":"sun.security.provider.NativePRNG", - "methods":[{"name":"","parameterTypes":[] }, {"name":"","parameterTypes":["java.security.SecureRandomParameters"] }] -}, -{ - "name":"sun.security.provider.SHA", - "methods":[{"name":"","parameterTypes":[] }] -} -] \ No newline at end of file diff --git a/pgpainless-cli/src/main/resources/META-INF/native-image/resource-config.json b/pgpainless-cli/src/main/resources/META-INF/native-image/resource-config.json deleted file mode 100644 index 3c66a520..00000000 --- a/pgpainless-cli/src/main/resources/META-INF/native-image/resource-config.json +++ /dev/null @@ -1,93 +0,0 @@ -{ - "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"] - }] -} \ No newline at end of file diff --git a/pgpainless-cli/src/main/resources/META-INF/native-image/serialization-config.json b/pgpainless-cli/src/main/resources/META-INF/native-image/serialization-config.json deleted file mode 100644 index 3f06d9a8..00000000 --- a/pgpainless-cli/src/main/resources/META-INF/native-image/serialization-config.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "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":[ - ] -} \ No newline at end of file diff --git a/pgpainless-cli/src/main/resources/logback.xml b/pgpainless-cli/src/main/resources/logback.xml index 8451d6a4..559589ef 100644 --- a/pgpainless-cli/src/main/resources/logback.xml +++ b/pgpainless-cli/src/main/resources/logback.xml @@ -5,5 +5,22 @@ SPDX-License-Identifier: Apache-2.0 --> - + + System.err + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + System.out + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + \ No newline at end of file diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/ExitCodeTest.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/ExitCodeTest.java index b1ca143a..07c9bf68 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/ExitCodeTest.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/ExitCodeTest.java @@ -4,35 +4,28 @@ 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; -import java.io.IOException; +public class ExitCodeTest { -import static org.junit.jupiter.api.Assertions.assertEquals; - -public class ExitCodeTest extends CLITest { - - public ExitCodeTest() { - super(LoggerFactory.getLogger(ExitCodeTest.class)); + @Test + @ExpectSystemExitWithStatus(SOPGPException.UnsupportedSubcommand.EXIT_CODE) + public void testUnknownCommand_69() { + PGPainlessCLI.main(new String[] {"generate-kex"}); } @Test - public void testUnknownCommand_69() throws IOException { - assertEquals(SOPGPException.UnsupportedSubcommand.EXIT_CODE, - executeCommand("unsupported-subcommand")); + @ExpectSystemExitWithStatus(SOPGPException.UnsupportedOption.EXIT_CODE) + public void testCommandWithUnknownOption_37() { + PGPainlessCLI.main(new String[] {"generate-key", "-k", "\"k is unknown\""}); } @Test - 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")); + @FailOnSystemExit + public void successfulExecutionDoesNotTerminateJVM() { + PGPainlessCLI.main(new String[] {"version"}); } } diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java index f8d56bc3..9969298a 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripEncryptDecryptCmdTest.java @@ -14,6 +14,7 @@ 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; @@ -82,6 +83,7 @@ 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"); diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignInlineVerifyCmdTest.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignInlineVerifyCmdTest.java index 057cec98..0676f213 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignInlineVerifyCmdTest.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignInlineVerifyCmdTest.java @@ -138,10 +138,6 @@ 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); @@ -157,7 +153,7 @@ public class RoundTripInlineSignInlineVerifyCmdTest extends CLITest { String cleartextSigned = ciphertextOut.toString(); assertTrue(cleartextSigned.startsWith("-----BEGIN PGP SIGNED MESSAGE-----\n" + "Hash: ")); - assertTrue(cleartextSigned.contains(MESSAGE_CRLF)); + assertTrue(cleartextSigned.contains(MESSAGE)); assertTrue(cleartextSigned.contains("\n-----BEGIN PGP SIGNATURE-----\n")); assertTrue(cleartextSigned.endsWith("-----END PGP SIGNATURE-----\n")); } @@ -207,7 +203,7 @@ public class RoundTripInlineSignInlineVerifyCmdTest extends CLITest { "--verifications-out", verifications.getAbsolutePath(), cert.getAbsolutePath())); - assertEquals(MESSAGE_CRLF, plaintextOut.toString()); + assertEquals(MESSAGE, plaintextOut.toString()); String verificationString = readStringFromFile(verifications); assertTrue(verificationString.contains(CERT_1_SIGNING_KEY)); } diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignVerifyCmdTest.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignVerifyCmdTest.java index cf350e66..82fda430 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignVerifyCmdTest.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/commands/RoundTripInlineSignVerifyCmdTest.java @@ -4,49 +4,104 @@ package org.pgpainless.cli.commands; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +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.slf4j.LoggerFactory; +import org.pgpainless.cli.PGPainlessCLI; +import org.pgpainless.cli.TestUtils; -public class RoundTripInlineSignVerifyCmdTest extends CLITest { +public class RoundTripInlineSignVerifyCmdTest { + private static File tempDir; + private static PrintStream originalSout; - public RoundTripInlineSignVerifyCmdTest() { - super(LoggerFactory.getLogger(RoundTripInlineSignVerifyCmdTest.class)); + @BeforeAll + public static void prepare() throws IOException { + tempDir = TestUtils.createTempDirectory(); } @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 - File password = writeFile("password", "sw0rdf1sh"); + FileOutputStream passwordOut = new FileOutputStream(passwordFile); + passwordOut.write("sw0rdf1sh".getBytes(StandardCharsets.UTF_8)); + passwordOut.close(); // generate key - File sigmundKey = pipeStdoutToFile("sigmund.key"); - assertSuccess(executeCommand("generate-key", "--with-key-password=" + password.getAbsolutePath(), - "Sigmund Freud ")); + OutputStream sigmundKeyOut = new FileOutputStream(sigmundKeyFile); + System.setOut(new PrintStream(sigmundKeyOut)); + PGPainlessCLI.execute("generate-key", + "--with-key-password=" + passwordFile.getAbsolutePath(), + "Sigmund Freud "); + sigmundKeyOut.close(); // extract cert - File sigmundCert = pipeStdoutToFile("sigmund.cert"); - pipeFileToStdin(sigmundKey); - assertSuccess(executeCommand("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(); // sign message - pipeBytesToStdin("Hello, World!\n".getBytes(StandardCharsets.UTF_8)); - File signedMsg = pipeStdoutToFile("signed.asc"); - assertSuccess(executeCommand("inline-sign", "--with-key-password=" + password.getAbsolutePath(), - sigmundKey.getAbsolutePath())); + 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(); - // verify message - File verifyFile = nonExistentFile("verify.txt"); - pipeFileToStdin(signedMsg); - assertSuccess(executeCommand("inline-verify", "--verifications-out", verifyFile.getAbsolutePath(), - sigmundCert.getAbsolutePath())); + File verifyFile = new File(tempDir, "verify.txt"); - String verifications = readStringFromFile(verifyFile); - assertFalse(verifications.trim().isEmpty()); + 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 } } diff --git a/pgpainless-cli/src/test/java/org/pgpainless/cli/misc/SignUsingPublicKeyBehaviorTest.java b/pgpainless-cli/src/test/java/org/pgpainless/cli/misc/SignUsingPublicKeyBehaviorTest.java index d6065b82..affe621e 100644 --- a/pgpainless-cli/src/test/java/org/pgpainless/cli/misc/SignUsingPublicKeyBehaviorTest.java +++ b/pgpainless-cli/src/test/java/org/pgpainless/cli/misc/SignUsingPublicKeyBehaviorTest.java @@ -4,18 +4,28 @@ 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.commands.CLITest; -import org.slf4j.LoggerFactory; +import org.pgpainless.cli.PGPainlessCLI; +import org.pgpainless.cli.TestUtils; import sop.exception.SOPGPException; -public class SignUsingPublicKeyBehaviorTest extends CLITest { +public class SignUsingPublicKeyBehaviorTest { public static final String KEY_THAT_IS_A_CERT = "" + "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + @@ -79,24 +89,61 @@ public class SignUsingPublicKeyBehaviorTest extends CLITest { "=oJQ2\n" + "-----END PGP PUBLIC KEY BLOCK-----"; - public SignUsingPublicKeyBehaviorTest() { - super(LoggerFactory.getLogger(SignUsingPublicKeyBehaviorTest.class)); + + private static File tempDir; + private static PrintStream originalSout; + + @BeforeAll + public static void prepare() throws IOException { + tempDir = TestUtils.createTempDirectory(); } @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 = writeFile("alice.key", KEY_THAT_IS_A_CERT); + 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(); // Write test data to disc - File dataFile = writeFile("data", "If privacy is outlawed, only outlaws will have privacy.\n"); + 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(); // Sign test data - File sigFile = pipeStdoutToFile("sig.asc"); - pipeFileToStdin(dataFile); - assertEquals(SOPGPException.KeyCannotSign.EXIT_CODE, - executeCommand("sign", "--armor", aliceKeyFile.getAbsolutePath())); + 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()}); - assertTrue(readStringFromFile(sigFile).trim().isEmpty()); + System.setIn(originalIn); + } + + @AfterAll + public static void after() { + System.setOut(originalSout); + // CHECKSTYLE:OFF + System.out.println(tempDir.getAbsolutePath()); + // CHECKSTYLE:ON } } diff --git a/pgpainless-core/build.gradle b/pgpainless-core/build.gradle index 64d538d5..bab6ecf1 100644 --- a/pgpainless-core/build.gradle +++ b/pgpainless-core/build.gradle @@ -22,7 +22,6 @@ 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 diff --git a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpInputStream.java b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpInputStream.java index 3522f509..ff020a7b 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpInputStream.java +++ b/pgpainless-core/src/main/java/org/pgpainless/decryption_verification/OpenPgpInputStream.java @@ -32,7 +32,6 @@ 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; @@ -209,8 +208,8 @@ public class OpenPgpInputStream extends BufferedInputStream { } try { - SignatureType.requireFromCode(sigType); - } catch (NoSuchElementException e) { + SignatureType.valueOf(sigType); + } catch (IllegalArgumentException e) { return; } @@ -237,8 +236,8 @@ public class OpenPgpInputStream extends BufferedInputStream { if (opsVersion == 3) { int opsSigType = bcpgIn.read(); try { - SignatureType.requireFromCode(opsSigType); - } catch (NoSuchElementException e) { + SignatureType.valueOf(opsSigType); + } catch (IllegalArgumentException e) { return; } int opsHashAlg = bcpgIn.read(); diff --git a/pgpainless-core/src/main/java/org/pgpainless/exception/SignatureValidationException.java b/pgpainless-core/src/main/java/org/pgpainless/exception/SignatureValidationException.java index 2141ec5c..b5b8941d 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/exception/SignatureValidationException.java +++ b/pgpainless-core/src/main/java/org/pgpainless/exception/SignatureValidationException.java @@ -28,14 +28,7 @@ public class SignatureValidationException extends PGPException { StringBuilder sb = new StringBuilder(); sb.append(rejections.size()).append(" rejected signatures:\n"); for (PGPSignature signature : rejections.keySet()) { - 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(' ') + sb.append(SignatureType.valueOf(signature.getSignatureType())).append(' ') .append(signature.getCreationTime()).append(": ") .append(rejections.get(signature).getMessage()).append('\n'); } diff --git a/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java b/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java index f7a78404..e97a2d7a 100644 --- a/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java +++ b/pgpainless-core/src/main/java/org/pgpainless/key/util/OpenPgpKeyAttributeUtil.java @@ -34,11 +34,7 @@ public final class OpenPgpKeyAttributeUtil { continue; } - SignatureType signatureType = SignatureType.fromCode(signature.getSignatureType()); - if (signatureType == null) { - // unknown signature type - continue; - } + SignatureType signatureType = SignatureType.valueOf(signature.getSignatureType()); if (signatureType == SignatureType.POSITIVE_CERTIFICATION || signatureType == SignatureType.GENERIC_CERTIFICATION) { int[] hashAlgos = signature.getHashedSubPackets().getPreferredHashAlgorithms(); @@ -75,8 +71,8 @@ public final class OpenPgpKeyAttributeUtil { continue; } - SignatureType signatureType = SignatureType.fromCode(signature.getSignatureType()); - if (signatureType == null || signatureType != SignatureType.POSITIVE_CERTIFICATION + SignatureType signatureType = SignatureType.valueOf(signature.getSignatureType()); + if (signatureType != SignatureType.POSITIVE_CERTIFICATION && signatureType != SignatureType.GENERIC_CERTIFICATION) { continue; } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureType.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureType.kt index be6917df..e6b2299f 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureType.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/algorithm/SignatureType.kt @@ -170,8 +170,7 @@ enum class SignatureType(val code: Int) { @JvmStatic fun isRevocationSignature(signatureType: Int): Boolean { - val sigType = fromCode(signatureType) - return sigType?.let { isRevocationSignature(it) } ?: false + return isRevocationSignature(valueOf(signatureType)) } @JvmStatic diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSignatureExtensions.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSignatureExtensions.kt index 1393883c..df40c461 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSignatureExtensions.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/bouncycastle/extensions/PGPSignatureExtensions.kt @@ -77,8 +77,7 @@ fun PGPSignature.wasIssuedBy(key: PGPPublicKey): Boolean = wasIssuedBy(OpenPgpFi /** Return true, if this signature is a hard revocation. */ val PGPSignature.isHardRevocation get() = - when (SignatureType.fromCode(signatureType)) { - null -> false + when (SignatureType.requireFromCode(signatureType)) { SignatureType.KEY_REVOCATION, SignatureType.SUBKEY_REVOCATION, SignatureType.CERTIFICATION_REVOCATION -> { @@ -105,4 +104,4 @@ val PGPSignature.signatureHashAlgorithm: HashAlgorithm get() = HashAlgorithm.requireFromId(hashAlgorithm) fun PGPSignature.isOfType(type: SignatureType): Boolean = - SignatureType.fromCode(signatureType) == type + SignatureType.requireFromCode(signatureType) == type diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.kt index 9bafa6da..3d07065e 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CachingBcPublicKeyDataDecryptorFactory.kt @@ -4,11 +4,7 @@ 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 @@ -25,34 +21,16 @@ import org.pgpainless.key.SubkeyIdentifier class CachingBcPublicKeyDataDecryptorFactory( privateKey: PGPPrivateKey, override val subkeyIdentifier: SubkeyIdentifier -) : CustomPublicKeyDataDecryptorFactory() { +) : BcPublicKeyDataDecryptorFactory(privateKey), CustomPublicKeyDataDecryptorFactory { - private val decryptorFactory: BcPublicKeyDataDecryptorFactory = - BcPublicKeyDataDecryptorFactory(privateKey) private val cachedSessions: MutableMap = 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, - pkeskVersion: Int + secKeyData: Array ): ByteArray = lookupSessionKeyData(secKeyData) - ?: costlyRecoverSessionData(keyAlgorithm, secKeyData, pkeskVersion).also { + ?: costlyRecoverSessionData(keyAlgorithm, secKeyData).also { cacheSessionKeyData(secKeyData, it) } @@ -61,9 +39,8 @@ class CachingBcPublicKeyDataDecryptorFactory( private fun costlyRecoverSessionData( keyAlgorithm: Int, - secKeyData: Array, - pkeskVersion: Int - ): ByteArray = decryptorFactory.recoverSessionData(keyAlgorithm, secKeyData, pkeskVersion) + secKeyData: Array + ): ByteArray = super.recoverSessionData(keyAlgorithm, secKeyData) private fun cacheSessionKeyData(secKeyData: Array, sessionKey: ByteArray) { cachedSessions[toKey(secKeyData)] = sessionKey.clone() diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.kt index cb6254dc..4a0dbeba 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactory.kt @@ -4,7 +4,6 @@ package org.pgpainless.decryption_verification -import org.bouncycastle.openpgp.operator.AbstractPublicKeyDataDecryptorFactory import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory import org.pgpainless.key.SubkeyIdentifier @@ -15,7 +14,7 @@ import org.pgpainless.key.SubkeyIdentifier * * @see [ConsumerOptions.addCustomDecryptorFactory] */ -abstract class CustomPublicKeyDataDecryptorFactory : AbstractPublicKeyDataDecryptorFactory() { +interface CustomPublicKeyDataDecryptorFactory : PublicKeyDataDecryptorFactory { /** * Identifier for the subkey for which this particular [CustomPublicKeyDataDecryptorFactory] is @@ -23,5 +22,5 @@ abstract class CustomPublicKeyDataDecryptorFactory : AbstractPublicKeyDataDecryp * * @return subkey identifier */ - abstract val subkeyIdentifier: SubkeyIdentifier + val subkeyIdentifier: SubkeyIdentifier } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/HardwareSecurity.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/HardwareSecurity.kt index 50ef3e02..1974e290 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/HardwareSecurity.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/decryption_verification/HardwareSecurity.kt @@ -29,17 +29,11 @@ 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, - pkeskVersion: Int - ): ByteArray + fun decryptSessionKey(keyId: Long, keyAlgorithm: Int, sessionKeyData: ByteArray): ByteArray } /** @@ -50,7 +44,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) @@ -79,12 +73,10 @@ class HardwareSecurity { override fun recoverSessionData( keyAlgorithm: Int, - secKeyData: Array, - pkeskVersion: Int + secKeyData: Array ): ByteArray { return try { - callback.decryptSessionKey( - subkeyIdentifier.subkeyId, keyAlgorithm, secKeyData[0], pkeskVersion) + callback.decryptSessionKey(subkeyIdentifier.subkeyId, keyAlgorithm, secKeyData[0]) } catch (e: HardwareSecurityException) { throw PGPException("Hardware-backed decryption failed.", e) } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/CRLFGeneratorStream.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/CRLFGeneratorStream.kt index 76d747e0..badc8b48 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/CRLFGeneratorStream.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/encryption_signing/CRLFGeneratorStream.kt @@ -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() diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt index aacfcceb..05adf7d9 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/generation/KeyRingBuilder.kt @@ -45,7 +45,7 @@ class KeyRingBuilder : KeyRingBuilderInterface { } override fun addUserId(userId: CharSequence): KeyRingBuilder = apply { - userIds[userId.toString()] = null + userIds[userId.toString().trim()] = null } override fun addUserId(userId: ByteArray): KeyRingBuilder = diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyAccessor.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyAccessor.kt index 935c4f48..11fe1643 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyAccessor.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyAccessor.kt @@ -67,9 +67,11 @@ abstract class KeyAccessor(protected val info: KeyRingInfo, protected val key: S info.getLatestUserIdCertification(userId).let { if (it != null) return it } } - return info.getCurrentSubkeyBindingSignature(key.subkeyId) - ?: throw NoSuchElementException( - "Key does not carry acceptable self-signature signature.") + if (info.latestDirectKeySelfSignature != null) { + return info.latestDirectKeySelfSignature + } + + return info.getCurrentSubkeyBindingSignature(key.subkeyId)!! } } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt index ce4fbe56..f4305225 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/info/KeyRingInfo.kt @@ -172,8 +172,11 @@ 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 @@ -402,7 +405,7 @@ class KeyRingInfo( .plus(signatures.userIdRevocations.values) .plus(signatures.subkeyBindings.values) .plus(signatures.subkeyRevocations.values) - .maxByOrNull { it.creationTime } + .maxByOrNull { creationDate } /** * Return the creation time of the latest added subkey. * diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt index 5480442d..ec93c6d6 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/key/modification/secretkeyring/SecretKeyRingEditor.kt @@ -478,7 +478,7 @@ class SecretKeyRingEditor( val prevBinding = inspectKeyRing(secretKeyRing).getCurrentSubkeyBindingSignature(keyId) ?: throw NoSuchElementException( - "Previous subkey binding signature for ${keyId.openPgpKeyId()} MUST NOT be null.") + "Previous subkey binding signaure for ${keyId.openPgpKeyId()} MUST NOT be null.") val bindingSig = reissueSubkeyBindingSignature(subkey, expiration, protector, prevBinding) secretKeyRing = injectCertification(secretKeyRing, subkey, bindingSig) } @@ -569,10 +569,9 @@ class SecretKeyRingEditor( } private fun sanitizeUserId(userId: CharSequence): CharSequence = - // 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() + // TODO: Further research how to sanitize user IDs. + // e.g. what about newlines? + userId.toString().trim() private fun callbackFromRevocationAttributes(attributes: RevocationAttributes?) = object : RevocationSignatureSubpackets.Callback { diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/builder/RevocationSignatureBuilder.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/builder/RevocationSignatureBuilder.kt index 36589613..d8c594fe 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/builder/RevocationSignatureBuilder.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/builder/RevocationSignatureBuilder.kt @@ -52,7 +52,7 @@ class RevocationSignatureBuilder : AbstractSignatureBuilder policy.certificationSignatureHashAlgorithmPolicy + return when (SignatureType.requireFromCode(signature.signatureType)) { SignatureType.CERTIFICATION_REVOCATION, SignatureType.KEY_REVOCATION, SignatureType.SUBKEY_REVOCATION -> policy.revocationSignatureHashAlgorithmPolicy @@ -599,8 +598,7 @@ abstract class SignatureValidator { if (signatureType.none { signature.isOfType(it) }) { throw SignatureValidationException( "Signature is of type" + - " ${SignatureType.fromCode(signature.signatureType) ?: - ("0x" + signature.signatureType.toString(16))}, " + + " ${SignatureType.requireFromCode(signature.signatureType)}, " + "while only ${signatureType.contentToString()} are allowed here.") } } @@ -690,7 +688,7 @@ abstract class SignatureValidator { } if (notAfter != null && timestamp > notAfter) { throw SignatureValidationException( - "Signature was made after the latest allowed signature creation time." + + "Signature was made before the latest allowed signature creation time." + " Created: ${timestamp.formatUTC()}," + " latest allowed: ${notAfter.formatUTC()}") } diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignatureVerifier.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignatureVerifier.kt index d51b2379..77793c90 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignatureVerifier.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/signature/consumer/SignatureVerifier.kt @@ -59,13 +59,12 @@ class SignatureVerifier { policy: Policy, referenceTime: Date ): Boolean { - val type = SignatureType.fromCode(signature.signatureType) + val type = SignatureType.requireFromCode(signature.signatureType) return when (type) { SignatureType.GENERIC_CERTIFICATION, SignatureType.NO_CERTIFICATION, SignatureType.CASUAL_CERTIFICATION, - SignatureType.POSITIVE_CERTIFICATION, - null -> + SignatureType.POSITIVE_CERTIFICATION -> verifyUserIdCertification( userId, signature, signingKey, keyWithUserId, policy, referenceTime) SignatureType.CERTIFICATION_REVOCATION -> diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt index db1cb54d..b5d5b839 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/util/ArmorUtils.kt @@ -247,9 +247,7 @@ class ArmorUtils { .add(OpenPgpFingerprint.of(publicKey).prettyPrint()) // Primary / First User ID (primary ?: first)?.let { - headerMap - .getOrPut(HEADER_COMMENT) { mutableSetOf() } - .add(it.replace("\n", "\\n").replace("\r", "\\r")) + headerMap.getOrPut(HEADER_COMMENT) { mutableSetOf() }.add(it) } // X-1 further identities when (userIds.size) { diff --git a/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt b/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt index bd25f2b9..4d1e49d2 100644 --- a/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt +++ b/pgpainless-core/src/main/kotlin/org/pgpainless/util/Passphrase.kt @@ -11,9 +11,14 @@ import org.bouncycastle.util.Arrays * * @param chars may be null for empty passwords. */ -class Passphrase(private val chars: CharArray?) { +class Passphrase(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 @@ -62,13 +67,6 @@ class Passphrase(private val 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 { /** diff --git a/pgpainless-core/src/test/java/org/pgpainless/algorithm/SignatureTypeTest.java b/pgpainless-core/src/test/java/org/pgpainless/algorithm/SignatureTypeTest.java index 7f2bc2a6..1bf78776 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/algorithm/SignatureTypeTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/algorithm/SignatureTypeTest.java @@ -5,6 +5,7 @@ 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; @@ -30,6 +31,6 @@ public class SignatureTypeTest { assertFalse(SignatureType.isRevocationSignature(SignatureType.STANDALONE.getCode())); assertFalse(SignatureType.isRevocationSignature(SignatureType.TIMESTAMP.getCode())); - assertFalse(SignatureType.isRevocationSignature(-3)); + assertThrows(IllegalArgumentException.class, () -> SignatureType.isRevocationSignature(-3)); } } diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CanonicalizedDataEncryptionTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CanonicalizedDataEncryptionTest.java index f9936db0..36e473ac 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CanonicalizedDataEncryptionTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CanonicalizedDataEncryptionTest.java @@ -13,7 +13,6 @@ 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; @@ -31,9 +30,6 @@ 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; @@ -292,9 +288,11 @@ public class CanonicalizedDataEncryptionTest { } } - @ParameterizedTest - @MethodSource("resultOfDecryptionIsCRLFEncodedArguments") - public void resultOfDecryptionIsCRLFEncoded(String before, String after) throws PGPException, IOException { + @Test + public void resultOfDecryptionIsCRLFEncoded() throws PGPException, IOException { + String before = "Foo\nBar!\n"; + String after = "Foo\r\nBar!\r\n"; + String encrypted = encryptAndSign(before, DocumentSignatureType.BINARY_DOCUMENT, StreamEncoding.TEXT, true); ByteArrayInputStream in = new ByteArrayInputStream(encrypted.getBytes(StandardCharsets.UTF_8)); @@ -311,16 +309,6 @@ public class CanonicalizedDataEncryptionTest { assertArrayEquals(after.getBytes(StandardCharsets.UTF_8), decrypted.toByteArray()); } - private static Stream 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"; diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java index 71fbf9be..73c3bf56 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/CustomPublicKeyDataDecryptorFactoryTest.java @@ -55,14 +55,14 @@ public class CustomPublicKeyDataDecryptorFactoryTest { HardwareSecurity.DecryptionCallback hardwareDecryptionCallback = new HardwareSecurity.DecryptionCallback() { @Override - public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData, int pkeskVersion) + public byte[] decryptSessionKey(long keyId, int keyAlgorithm, byte[] sessionKeyData) 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}, pkeskVersion); + return internal.recoverSessionData(keyAlgorithm, new byte[][] {sessionKeyData}); } catch (PGPException e) { throw new HardwareSecurity.HardwareSecurityException(); } diff --git a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MessageMetadataTest.java b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MessageMetadataTest.java index 7c443829..2c29d62a 100644 --- a/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MessageMetadataTest.java +++ b/pgpainless-core/src/test/java/org/pgpainless/decryption_verification/MessageMetadataTest.java @@ -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 compressed. + // and randomness cannot be encrypted. // For the sake of testing though, this is okay. MessageMetadata.Message message = new MessageMetadata.Message(); diff --git a/pgpainless-core/src/test/kotlin/org/pgpainless/key/KeyWithoutSelfSigsTest.kt b/pgpainless-core/src/test/kotlin/org/pgpainless/key/KeyWithoutSelfSigsTest.kt new file mode 100644 index 00000000..c7879483 --- /dev/null +++ b/pgpainless-core/src/test/kotlin/org/pgpainless/key/KeyWithoutSelfSigsTest.kt @@ -0,0 +1,111 @@ +// SPDX-FileCopyrightText: 2023 Paul Schaub +// +// 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-----" + } +} diff --git a/pgpainless-sop/README.md b/pgpainless-sop/README.md index 7f7267cd..0b79941d 100644 --- a/pgpainless-sop/README.md +++ b/pgpainless-sop/README.md @@ -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.6" + implementation "org.pgpainless:pgpainless-sop:1.7.1" ... } @@ -34,7 +34,7 @@ dependencies { org.pgpainless pgpainless-sop - 1.7.6 + 1.7.1 ... @@ -67,7 +67,7 @@ byte[] encrypted = sop.encrypt() // Decrypt a message ByteArrayAndResult messageAndVerifications = sop.decrypt() - .verifyWithCert(cert) + .verifyWith(cert) .withKey(key) .ciphertext(encrypted) .toByteArrayAndResult(); diff --git a/pgpainless-sop/build.gradle b/pgpainless-sop/build.gradle index 53b499c6..26beec67 100644 --- a/pgpainless-sop/build.gradle +++ b/pgpainless-sop/build.gradle @@ -1,7 +1,7 @@ // SPDX-FileCopyrightText: 2021 Paul Schaub // // 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 "org.pgpainless:sop-java-testfixtures:$sopJavaVersion" + testImplementation(testFixtures("org.pgpainless:sop-java:$sopJavaVersion")) implementation(project(":pgpainless-core")) api "org.pgpainless:sop-java:$sopJavaVersion" @@ -30,12 +30,6 @@ 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") diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/ArmorImpl.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/ArmorImpl.kt index 40ac811d..bf7e63f1 100644 --- a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/ArmorImpl.kt +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/ArmorImpl.kt @@ -12,6 +12,7 @@ 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 @@ -45,4 +46,9 @@ 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.") + } } diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/DetachedSignImpl.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/DetachedSignImpl.kt index 19bc782b..a84ed6ef 100644 --- a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/DetachedSignImpl.kt +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/DetachedSignImpl.kt @@ -11,7 +11,6 @@ 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 @@ -58,10 +57,7 @@ class DetachedSignImpl : DetachedSign { val signingStream = PGPainless.encryptAndOrSign() .discardOutput() - .withOptions( - ProducerOptions.sign(signingOptions) - .setAsciiArmor(armor) - .overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED)) + .withOptions(ProducerOptions.sign(signingOptions).setAsciiArmor(armor)) return object : ReadyWithResult() { override fun writeTo(outputStream: OutputStream): SigningResult { diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/InlineSignImpl.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/InlineSignImpl.kt index bd77b553..6fdf59a1 100644 --- a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/InlineSignImpl.kt +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/InlineSignImpl.kt @@ -11,9 +11,7 @@ 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 @@ -58,22 +56,12 @@ class InlineSignImpl : InlineSign { val producerOptions = ProducerOptions.sign(signingOptions).apply { - when (mode) { - InlineSignAs.clearsigned -> { - setCleartextSigned() - setAsciiArmor(true) // CSF is always armored - setEncoding(StreamEncoding.TEXT) - applyCRLFEncoding() - } - InlineSignAs.text -> { - setEncoding(StreamEncoding.TEXT) - applyCRLFEncoding() - } - else -> { - setAsciiArmor(armor) - } + if (mode == InlineSignAs.clearsigned) { + setCleartextSigned() + setAsciiArmor(true) // CSF is always armored + } else { + setAsciiArmor(armor) } - overrideCompressionAlgorithm(CompressionAlgorithm.UNCOMPRESSED) } return object : Ready() { diff --git a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/VersionImpl.kt b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/VersionImpl.kt index 94b9c016..7ebdade9 100644 --- a/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/VersionImpl.kt +++ b/pgpainless-sop/src/main/kotlin/org/pgpainless/sop/VersionImpl.kt @@ -8,7 +8,6 @@ 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. */ @@ -26,14 +25,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/main/pgpainless-sop +https://codeberg.org/PGPainless/pgpainless/src/branch/master/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""" } @@ -50,27 +49,15 @@ https://www.bouncycastle.org/java.html""" // See https://stackoverflow.com/a/50119235 return try { val resourceIn: InputStream = - SOP::class.java.getResourceAsStream("/pgpainless-sop.properties") - ?: throw IOException("File pgpainless-sop.properties not found.") + javaClass.getResourceAsStream("/version.properties") + ?: throw IOException("File version.properties not found.") val properties = Properties().apply { load(resourceIn) } - properties.getProperty("pgpainless-sop-version") + properties.getProperty("version") } catch (e: IOException) { "DEVELOPMENT" } } - private fun formatSopJavaVersion(): String { - return getSopJavaVersion()?.let { - """ - - sop-java $it - - """ - .trimIndent() - } - ?: "" - } - override fun isSopSpecImplementationIncomplete(): Boolean = false } diff --git a/pgpainless-sop/src/main/resources/pgpainless-sop.properties b/pgpainless-sop/src/main/resources/pgpainless-sop.properties deleted file mode 100644 index d0f47796..00000000 --- a/pgpainless-sop/src/main/resources/pgpainless-sop.properties +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-FileCopyrightText: 2025 Paul Schaub -# -# SPDX-License-Identifier: Apache-2.0 -pgpainless-sop-version=@project.version@ \ No newline at end of file diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java index 521cdfe0..ca6df790 100644 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java +++ b/pgpainless-sop/src/test/java/org/pgpainless/sop/GenerateKeyTest.java @@ -100,14 +100,4 @@ 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")); - } } diff --git a/pgpainless-sop/src/test/java/org/pgpainless/sop/VerifyLegacySignatureTest.java b/pgpainless-sop/src/test/java/org/pgpainless/sop/VerifyLegacySignatureTest.java deleted file mode 100644 index 23fd9840..00000000 --- a/pgpainless-sop/src/test/java/org/pgpainless/sop/VerifyLegacySignatureTest.java +++ /dev/null @@ -1,164 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Paul Schaub -// -// 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 \n" + - "\n" + - "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\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> 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()); - } -} diff --git a/version.gradle b/version.gradle index bc2515a4..69a8b0e1 100644 --- a/version.gradle +++ b/version.gradle @@ -4,15 +4,16 @@ allprojects { ext { - shortVersion = '1.7.7' - isSnapshot = true - javaSourceCompatibility = 11 - bouncyCastleVersion = '1.81' + shortVersion = '1.7.1' + isSnapshot = false + pgpainlessMinAndroidSdk = 10 + javaSourceCompatibility = 1.8 + bouncyCastleVersion = '1.78.1' bouncyPgVersion = bouncyCastleVersion junitVersion = '5.8.2' - logbackVersion = '1.5.13' + logbackVersion = '1.2.13' // 1.4+ cause CLI spam :/ mockitoVersion = '4.5.1' slf4jVersion = '1.7.36' - sopJavaVersion = '10.1.1' + sopJavaVersion = '10.0.2' } }