Merge pull request #21 from pgpainless/kotlin

Rewrite sop-java in Kotlin
This commit is contained in:
Paul Schaub 2023-10-31 15:59:36 +01:00 committed by GitHub
commit a8829350a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
90 changed files with 2397 additions and 3230 deletions

View file

@ -19,6 +19,8 @@ buildscript {
plugins {
id 'ru.vyarus.animalsniffer' version '1.5.3'
id 'org.jetbrains.kotlin.jvm' version "1.8.10"
id 'com.diffplug.spotless' version '6.22.0' apply false
}
apply from: 'version.gradle'
@ -29,6 +31,8 @@ allprojects {
apply plugin: 'eclipse'
apply plugin: 'jacoco'
apply plugin: 'checkstyle'
apply plugin: 'kotlin'
apply plugin: 'com.diffplug.spotless'
// For non-cli modules enable android api compatibility check
if (it.name.equals('sop-java')) {
@ -53,6 +57,12 @@ allprojects {
toolVersion = '8.18'
}
spotless {
kotlin {
ktfmt().dropboxStyle()
}
}
group 'org.pgpainless'
description = "Stateless OpenPGP Protocol API for Java"
version = shortVersion
@ -69,6 +79,13 @@ allprojects {
reproducibleFileOrder = true
}
// Compatibility of default implementations in kotlin interfaces with Java implementations.
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
freeCompilerArgs += ["-Xjvm-default=all-compatibility"]
}
}
project.ext {
rootConfigDir = new File(rootDir, 'config')
gitCommit = getGitCommit()

View file

@ -38,6 +38,7 @@ application {
jar {
dependsOn(":sop-java:jar")
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
manifest {
attributes 'Main-Class': "$mainClassName"

View file

@ -1,50 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
/**
* Tuple of a byte array and associated result object.
* @param <T> type of result
*/
public class ByteArrayAndResult<T> {
private final byte[] bytes;
private final T result;
public ByteArrayAndResult(byte[] bytes, T result) {
this.bytes = bytes;
this.result = result;
}
/**
* Return the byte array part.
*
* @return bytes
*/
public byte[] getBytes() {
return bytes;
}
/**
* Return the result part.
*
* @return result
*/
public T getResult() {
return result;
}
/**
* Return the byte array part as an {@link InputStream}.
*
* @return input stream
*/
public InputStream getInputStream() {
return new ByteArrayInputStream(getBytes());
}
}

View file

@ -1,29 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import sop.util.Optional;
public class DecryptionResult {
private final Optional<SessionKey> sessionKey;
private final List<Verification> verifications;
public DecryptionResult(SessionKey sessionKey, List<Verification> verifications) {
this.sessionKey = Optional.ofNullable(sessionKey);
this.verifications = Collections.unmodifiableList(verifications);
}
public Optional<SessionKey> getSessionKey() {
return sessionKey;
}
public List<Verification> getVerifications() {
return new ArrayList<>(verifications);
}
}

View file

@ -1,55 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.io.OutputStream;
import java.io.PrintWriter;
public class MicAlg {
private final String micAlg;
public MicAlg(String micAlg) {
if (micAlg == null) {
throw new IllegalArgumentException("MicAlg String cannot be null.");
}
this.micAlg = micAlg;
}
public static MicAlg empty() {
return new MicAlg("");
}
public static MicAlg fromHashAlgorithmId(int id) {
switch (id) {
case 1:
return new MicAlg("pgp-md5");
case 2:
return new MicAlg("pgp-sha1");
case 3:
return new MicAlg("pgp-ripemd160");
case 8:
return new MicAlg("pgp-sha256");
case 9:
return new MicAlg("pgp-sha384");
case 10:
return new MicAlg("pgp-sha512");
case 11:
return new MicAlg("pgp-sha224");
default:
throw new IllegalArgumentException("Unsupported hash algorithm ID: " + id);
}
}
public String getMicAlg() {
return micAlg;
}
public void writeTo(OutputStream outputStream) {
PrintWriter pw = new PrintWriter(outputStream);
pw.write(getMicAlg());
pw.close();
}
}

View file

@ -1,143 +0,0 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import sop.util.Optional;
import sop.util.UTF8Util;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Tuple class bundling a profile name and description.
*
* @see <a href="https://www.ietf.org/archive/id/draft-dkg-openpgp-stateless-cli-05.html#name-profile">
* SOP Spec - Profile</a>
*/
public class Profile {
private final String name;
private final Optional<String> description;
/**
* Create a new {@link Profile} object.
* The {@link #toString()} representation MUST NOT exceed a length of 1000 bytes.
*
* @param name profile name
* @param description profile description
*/
public Profile(@Nonnull String name, @Nullable String description) {
if (name.trim().isEmpty()) {
throw new IllegalArgumentException("Name cannot be empty.");
}
if (name.contains(":")) {
throw new IllegalArgumentException("Name cannot contain ':'.");
}
if (name.contains(" ") || name.contains("\n") || name.contains("\t") || name.contains("\r")) {
throw new IllegalArgumentException("Name cannot contain whitespace characters.");
}
this.name = name;
if (description == null) {
this.description = Optional.ofEmpty();
} else {
String trimmedDescription = description.trim();
if (trimmedDescription.isEmpty()) {
this.description = Optional.ofEmpty();
} else {
this.description = Optional.of(trimmedDescription);
}
}
if (exceeds1000CharLineLimit(this)) {
throw new IllegalArgumentException("The line representation of a profile MUST NOT exceed 1000 bytes.");
}
}
public Profile(String name) {
this(name, null);
}
/**
* Parse a {@link Profile} from its string representation.
*
* @param string string representation
* @return profile
*/
public static Profile parse(String string) {
if (string.contains(": ")) {
// description after colon, e.g. "default: Use implementers recommendations."
String name = string.substring(0, string.indexOf(": "));
String description = string.substring(string.indexOf(": ") + 2);
return new Profile(name, description.trim());
}
if (string.endsWith(":")) {
// empty description, e.g. "default:"
return new Profile(string.substring(0, string.length() - 1));
}
// no description
return new Profile(string.trim());
}
/**
* Return the name (also known as identifier) of the profile.
* A profile name is a UTF-8 string that has no whitespace in it.
* Similar to OpenPGP Notation names, profile names are divided into two namespaces:
* The IETF namespace and the user namespace.
* A profile name in the user namespace ends with the <pre>@</pre> character (0x40) followed by a DNS domain name.
* A profile name in the IETF namespace does not have an <pre>@</pre> character.
* A profile name in the user space is owned and controlled by the owner of the domain in the suffix.
* A profile name in the IETF namespace that begins with the string <pre>rfc</pre> should have semantics that hew as
* closely as possible to the referenced RFC.
* Similarly, a profile name in the IETF namespace that begins with the string <pre>draft-</pre> should have
* semantics that hew as closely as possible to the referenced Internet Draft.
*
* @return name
*/
@Nonnull
public String getName() {
return name;
}
/**
* Return a free-form description of the profile.
*
* @return description
*/
@Nonnull
public Optional<String> getDescription() {
return description;
}
public boolean hasDescription() {
return description.isPresent();
}
/**
* Convert the profile into a String for displaying.
*
* @return string
*/
@Override
public String toString() {
if (getDescription().isEmpty()) {
return getName();
}
return getName() + ": " + getDescription().get();
}
/**
* Test if the string representation of the profile exceeds the limit of 1000 bytes length.
* @param profile profile
* @return <pre>true</pre> if the profile exceeds 1000 bytes, <pre>false</pre> otherwise.
*/
private static boolean exceeds1000CharLineLimit(Profile profile) {
String line = profile.toString();
return line.getBytes(UTF8Util.UTF8).length > 1000;
}
}

View file

@ -1,45 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public abstract class Ready {
/**
* Write the data to the provided output stream.
*
* @param outputStream output stream
* @throws IOException in case of an IO error
*/
public abstract void writeTo(OutputStream outputStream) throws IOException;
/**
* Return the data as a byte array by writing it to a {@link ByteArrayOutputStream} first and then returning
* the array.
*
* @return data as byte array
* @throws IOException in case of an IO error
*/
public byte[] getBytes() throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
writeTo(bytes);
return bytes.toByteArray();
}
/**
* Return an input stream containing the data.
*
* @return input stream
* @throws IOException in case of an IO error
*/
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(getBytes());
}
}

View file

@ -1,41 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import sop.exception.SOPGPException;
public abstract class ReadyWithResult<T> {
/**
* Write the data e.g. decrypted plaintext to the provided output stream and return the result of the
* processing operation.
*
* @param outputStream output stream
* @return result, eg. signatures
*
* @throws IOException in case of an IO error
* @throws SOPGPException.NoSignature if there are no valid signatures found
*/
public abstract T writeTo(OutputStream outputStream) throws IOException, SOPGPException.NoSignature;
/**
* Return the data as a {@link ByteArrayAndResult}.
* Calling {@link ByteArrayAndResult#getBytes()} will give you access to the data as byte array, while
* {@link ByteArrayAndResult#getResult()} will grant access to the appended result.
*
* @return byte array and result
* @throws IOException in case of an IO error
* @throws SOPGPException.NoSignature if there are no valid signatures found
*/
public ByteArrayAndResult<T> toByteArrayAndResult() throws IOException, SOPGPException.NoSignature {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
T result = writeTo(bytes);
return new ByteArrayAndResult<>(bytes.toByteArray(), result);
}
}

View file

@ -1,177 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import sop.operation.Armor;
import sop.operation.ChangeKeyPassword;
import sop.operation.Dearmor;
import sop.operation.Decrypt;
import sop.operation.Encrypt;
import sop.operation.ExtractCert;
import sop.operation.GenerateKey;
import sop.operation.InlineDetach;
import sop.operation.InlineSign;
import sop.operation.InlineVerify;
import sop.operation.DetachedSign;
import sop.operation.DetachedVerify;
import sop.operation.ListProfiles;
import sop.operation.RevokeKey;
import sop.operation.Version;
/**
* Stateless OpenPGP Interface.
* This class provides a stateless interface to various OpenPGP related operations.
* <br>
* Note: Subcommand objects acquired by calling any method of this interface are not intended for reuse.
* If you for example need to generate multiple keys, make a dedicated call to {@link #generateKey()} once per
* key generation.
*/
public interface SOP {
/**
* Get information about the implementations name and version.
*
* @return version
*/
Version version();
/**
* Generate a secret key.
* Customize the operation using the builder {@link GenerateKey}.
*
* @return builder instance
*/
GenerateKey generateKey();
/**
* Extract a certificate (public key) from a secret key.
* Customize the operation using the builder {@link ExtractCert}.
*
* @return builder instance
*/
ExtractCert extractCert();
/**
* Create detached signatures.
* Customize the operation using the builder {@link DetachedSign}.
* <p>
* If you want to sign a message inline, use {@link #inlineSign()} instead.
*
* @return builder instance
*/
default DetachedSign sign() {
return detachedSign();
}
/**
* Create detached signatures.
* Customize the operation using the builder {@link DetachedSign}.
* <p>
* If you want to sign a message inline, use {@link #inlineSign()} instead.
*
* @return builder instance
*/
DetachedSign detachedSign();
/**
* Sign a message using inline signatures.
* <p>
* If you need to create detached signatures, use {@link #detachedSign()} instead.
*
* @return builder instance
*/
InlineSign inlineSign();
/**
* Verify detached signatures.
* Customize the operation using the builder {@link DetachedVerify}.
* <p>
* If you need to verify an inline-signed message, use {@link #inlineVerify()} instead.
*
* @return builder instance
*/
default DetachedVerify verify() {
return detachedVerify();
}
/**
* Verify detached signatures.
* Customize the operation using the builder {@link DetachedVerify}.
* <p>
* If you need to verify an inline-signed message, use {@link #inlineVerify()} instead.
*
* @return builder instance
*/
DetachedVerify detachedVerify();
/**
* Verify signatures of an inline-signed message.
* <p>
* If you need to verify detached signatures over a message, use {@link #detachedVerify()} instead.
*
* @return builder instance
*/
InlineVerify inlineVerify();
/**
* Detach signatures from an inline signed message.
*
* @return builder instance
*/
InlineDetach inlineDetach();
/**
* Encrypt a message.
* Customize the operation using the builder {@link Encrypt}.
*
* @return builder instance
*/
Encrypt encrypt();
/**
* Decrypt a message.
* Customize the operation using the builder {@link Decrypt}.
*
* @return builder instance
*/
Decrypt decrypt();
/**
* Convert binary OpenPGP data to ASCII.
* Customize the operation using the builder {@link Armor}.
*
* @return builder instance
*/
Armor armor();
/**
* Converts ASCII armored OpenPGP data to binary.
* Customize the operation using the builder {@link Dearmor}.
*
* @return builder instance
*/
Dearmor dearmor();
/**
* List supported {@link Profile Profiles} of a subcommand.
*
* @return builder instance
*/
ListProfiles listProfiles();
/**
* Revoke one or more secret keys.
*
* @return builder instance
*/
RevokeKey revokeKey();
/**
* Update a key's password.
*
* @return builder instance
*/
ChangeKeyPassword changeKeyPassword();
}

View file

@ -1,80 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import sop.util.HexUtil;
public class SessionKey {
private static final Pattern PATTERN = Pattern.compile("^(\\d):([0-9A-F]+)$");
private final byte algorithm;
private final byte[] sessionKey;
public SessionKey(byte algorithm, byte[] sessionKey) {
this.algorithm = algorithm;
this.sessionKey = sessionKey;
}
/**
* Return the symmetric algorithm octet.
*
* @return algorithm id
*/
public byte getAlgorithm() {
return algorithm;
}
/**
* Return the session key.
*
* @return session key
*/
public byte[] getKey() {
return sessionKey;
}
@Override
public int hashCode() {
return getAlgorithm() * 17 + Arrays.hashCode(getKey());
}
@Override
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (this == other) {
return true;
}
if (!(other instanceof SessionKey)) {
return false;
}
SessionKey otherKey = (SessionKey) other;
return getAlgorithm() == otherKey.getAlgorithm() && Arrays.equals(getKey(), otherKey.getKey());
}
public static SessionKey fromString(String string) {
string = string.trim().toUpperCase().replace("\n", "");
Matcher matcher = PATTERN.matcher(string);
if (!matcher.matches()) {
throw new IllegalArgumentException("Provided session key does not match expected format.");
}
byte algorithm = Byte.parseByte(matcher.group(1));
String key = matcher.group(2);
return new SessionKey(algorithm, HexUtil.hexToBytes(key));
}
@Override
public String toString() {
return Integer.toString(getAlgorithm()) + ':' + HexUtil.bytesToHex(sessionKey);
}
}

View file

@ -1,21 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import java.io.IOException;
import java.io.OutputStream;
public abstract class Signatures extends Ready {
/**
* Write OpenPGP signatures to the provided output stream.
*
* @param signatureOutputStream output stream
* @throws IOException in case of an IO error
*/
@Override
public abstract void writeTo(OutputStream signatureOutputStream) throws IOException;
}

View file

@ -1,50 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
/**
* This class contains various information about a signed message.
*/
public final class SigningResult {
private final MicAlg micAlg;
private SigningResult(MicAlg micAlg) {
this.micAlg = micAlg;
}
/**
* Return a string identifying the digest mechanism used to create the signed message.
* This is useful for setting the micalg= parameter for the multipart/signed
* content type of a PGP/MIME object as described in section 5 of [RFC3156].
* <p>
* If more than one signature was generated and different digest mechanisms were used,
* the value of the micalg object is an empty string.
*
* @return micalg
*/
public MicAlg getMicAlg() {
return micAlg;
}
public static Builder builder() {
return new Builder();
}
public static class Builder {
private MicAlg micAlg;
public Builder setMicAlg(MicAlg micAlg) {
this.micAlg = micAlg;
return this;
}
public SigningResult build() {
SigningResult signingResult = new SigningResult(micAlg);
return signingResult;
}
}
}

View file

@ -1,222 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop;
import sop.enums.SignatureMode;
import sop.util.Optional;
import sop.util.UTCUtil;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.text.ParseException;
import java.util.Date;
/**
* Class bundling information about a verified signature.
*/
public class Verification {
private final Date creationTime;
private final String signingKeyFingerprint;
private final String signingCertFingerprint;
private final Optional<SignatureMode> signatureMode;
private final Optional<String> description;
private static final String MODE = "mode:";
/**
* Create a new {@link Verification} without mode and description.
*
* @param creationTime signature creation time
* @param signingKeyFingerprint fingerprint of the signing (sub-) key
* @param signingCertFingerprint fingerprint of the certificate
*/
public Verification(@Nonnull Date creationTime,
@Nonnull String signingKeyFingerprint,
@Nonnull String signingCertFingerprint) {
this(creationTime, signingKeyFingerprint, signingCertFingerprint, Optional.ofEmpty(), Optional.ofEmpty());
}
/**
* Create a new {@link Verification}.
*
* @param creationTime signature creation time
* @param signingKeyFingerprint fingerprint of the signing (sub-) key
* @param signingCertFingerprint fingerprint of the certificate
* @param signatureMode signature mode (optional, may be <pre>null</pre>)
* @param description free-form description, e.g. <pre>certificate from dkg.asc</pre> (optional, may be <pre>null</pre>)
*/
public Verification(@Nonnull Date creationTime,
@Nonnull String signingKeyFingerprint,
@Nonnull String signingCertFingerprint,
@Nullable SignatureMode signatureMode,
@Nullable String description) {
this(
creationTime,
signingKeyFingerprint,
signingCertFingerprint,
Optional.ofNullable(signatureMode),
Optional.ofNullable(nullSafeTrim(description))
);
}
private Verification(@Nonnull Date creationTime,
@Nonnull String signingKeyFingerprint,
@Nonnull String signingCertFingerprint,
@Nonnull Optional<SignatureMode> signatureMode,
@Nonnull Optional<String> description) {
this.creationTime = creationTime;
this.signingKeyFingerprint = signingKeyFingerprint;
this.signingCertFingerprint = signingCertFingerprint;
this.signatureMode = signatureMode;
this.description = description;
}
private static String nullSafeTrim(@Nullable String string) {
if (string == null) {
return null;
}
return string.trim();
}
@Nonnull
public static Verification fromString(@Nonnull String toString) {
String[] split = toString.trim().split(" ");
if (split.length < 3) {
throw new IllegalArgumentException("Verification must be of the format 'UTC-DATE OpenPGPFingerprint OpenPGPFingerprint [mode] [info]'");
}
if (split.length == 3) {
return new Verification(
parseUTCDate(split[0]), // timestamp
split[1], // key FP
split[2] // cert FP
);
}
SignatureMode mode = null;
int index = 3;
if (split[index].startsWith(MODE)) {
mode = SignatureMode.valueOf(split[3].substring(MODE.length()));
index++;
}
StringBuilder sb = new StringBuilder();
for (int i = index; i < split.length; i++) {
if (sb.length() != 0) {
sb.append(' ');
}
sb.append(split[i]);
}
return new Verification(
parseUTCDate(split[0]), // timestamp
split[1], // key FP
split[2], // cert FP
mode, // signature mode
sb.length() != 0 ? sb.toString() : null // description
);
}
private static Date parseUTCDate(String utcFormatted) {
try {
return UTCUtil.parseUTCDate(utcFormatted);
} catch (ParseException e) {
throw new IllegalArgumentException("Malformed UTC timestamp.", e);
}
}
/**
* Return the signatures' creation time.
*
* @return signature creation time
*/
@Nonnull
public Date getCreationTime() {
return creationTime;
}
/**
* Return the fingerprint of the signing (sub)key.
*
* @return signing key fingerprint
*/
@Nonnull
public String getSigningKeyFingerprint() {
return signingKeyFingerprint;
}
/**
* Return the fingerprint fo the signing certificate.
*
* @return signing certificate fingerprint
*/
@Nonnull
public String getSigningCertFingerprint() {
return signingCertFingerprint;
}
/**
* Return the mode of the signature.
* Optional, may return <pre>null</pre>.
*
* @return signature mode
*/
@Nonnull
public Optional<SignatureMode> getSignatureMode() {
return signatureMode;
}
/**
* Return an optional description.
* Optional, may return <pre>null</pre>.
*
* @return description
*/
@Nonnull
public Optional<String> getDescription() {
return description;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder()
.append(UTCUtil.formatUTCDate(getCreationTime()))
.append(' ')
.append(getSigningKeyFingerprint())
.append(' ')
.append(getSigningCertFingerprint());
if (signatureMode.isPresent()) {
sb.append(' ').append(MODE).append(signatureMode.get());
}
if (description.isPresent()) {
sb.append(' ').append(description.get());
}
return sb.toString();
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (!(obj instanceof Verification)) {
return false;
}
Verification other = (Verification) obj;
return toString().equals(other.toString());
}
}

View file

@ -1,19 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.enums;
public enum ArmorLabel {
Auto,
Sig,
Key,
Cert,
Message,
;
@Override
public String toString() {
return super.toString().toLowerCase();
}
}

View file

@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.enums;
public enum EncryptAs {
Binary,
Text,
;
@Override
public String toString() {
return super.toString().toLowerCase();
}
}

View file

@ -1,24 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.enums;
public enum InlineSignAs {
/**
* Signature is made over the binary message.
*/
binary,
/**
* Signature is made over the message in text mode.
*/
text,
/**
* Signature is made using the Cleartext Signature Framework.
*/
clearsigned,
}

View file

@ -1,23 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.enums;
public enum SignAs {
/**
* Signature is made over the binary message.
*/
Binary,
/**
* Signature is made over the message in text mode.
*/
Text,
;
@Override
public String toString() {
return super.toString().toLowerCase();
}
}

View file

@ -1,25 +0,0 @@
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.enums;
/**
* Enum referencing relevant signature types.
*
* @see <a href="https://www.rfc-editor.org/rfc/rfc4880#section-5.2.1">
* RFC4880 §5.2.1 - Signature Types</a>
*/
public enum SignatureMode {
/**
* Signature of a binary document (<pre>0x00</pre>).
*/
binary,
/**
* Signature of a canonical text document (<pre>0x01</pre>).
*/
text
// Other Signature Types are irrelevant.
}

View file

@ -1,9 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Stateless OpenPGP Interface for Java.
* Enumerations.
*/
package sop.enums;

View file

@ -1,473 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package sop.exception;
public abstract class SOPGPException extends RuntimeException {
public SOPGPException() {
super();
}
public SOPGPException(String message) {
super(message);
}
public SOPGPException(Throwable e) {
super(e);
}
public SOPGPException(String message, Throwable cause) {
super(message, cause);
}
public abstract int getExitCode();
/**
* No acceptable signatures found (sop verify, inline-verify).
*/
public static class NoSignature extends SOPGPException {
public static final int EXIT_CODE = 3;
public NoSignature() {
this("No verifiable signature found.");
}
public NoSignature(String message) {
super(message);
}
public NoSignature(String errorMsg, NoSignature e) {
super(errorMsg, e);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Asymmetric algorithm unsupported (sop encrypt, sign, inline-sign).
*/
public static class UnsupportedAsymmetricAlgo extends SOPGPException {
public static final int EXIT_CODE = 13;
public UnsupportedAsymmetricAlgo(String message, Throwable e) {
super(message, e);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Certificate not encryption capable (e,g, expired, revoked, unacceptable usage).
*/
public static class CertCannotEncrypt extends SOPGPException {
public static final int EXIT_CODE = 17;
public CertCannotEncrypt(String message, Throwable cause) {
super(message, cause);
}
public CertCannotEncrypt(String message) {
super(message);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Missing required argument.
*/
public static class MissingArg extends SOPGPException {
public static final int EXIT_CODE = 19;
public MissingArg() {
}
public MissingArg(String message) {
super(message);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Incomplete verification instructions (sop decrypt).
*/
public static class IncompleteVerification extends SOPGPException {
public static final int EXIT_CODE = 23;
public IncompleteVerification(String message) {
super(message);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Unable to decrypt (sop decrypt).
*/
public static class CannotDecrypt extends SOPGPException {
public static final int EXIT_CODE = 29;
public CannotDecrypt() {
}
public CannotDecrypt(String errorMsg, Throwable e) {
super(errorMsg, e);
}
public CannotDecrypt(String message) {
super(message);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Non-UTF-8 or otherwise unreliable password (sop encrypt).
*/
public static class PasswordNotHumanReadable extends SOPGPException {
public static final int EXIT_CODE = 31;
public PasswordNotHumanReadable() {
super();
}
public PasswordNotHumanReadable(String message) {
super(message);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Unsupported option.
*/
public static class UnsupportedOption extends SOPGPException {
public static final int EXIT_CODE = 37;
public UnsupportedOption(String message) {
super(message);
}
public UnsupportedOption(String message, Throwable cause) {
super(message, cause);
}
@Override
public int getExitCode() {
return EXIT_CODE;
}
}
/**
* Invalid data type (no secret key where KEYS expected, etc.).
*/
public static class BadData extends SOPGPException {
public static final int EXIT_CODE = 41;
public BadData(String message) {
super(message);
}
public BadData(Throwable throwable) {
super(throwable);
}