mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-26 12:58:02 +01:00
Wip: Start implementing a SOP client
This commit is contained in:
parent
ff8c6d8b6d
commit
9d3ad01dfc
8 changed files with 254 additions and 1 deletions
30
pgpainless-sop/build.gradle
Normal file
30
pgpainless-sop/build.gradle
Normal file
|
@ -0,0 +1,30 @@
|
|||
plugins {
|
||||
id 'com.github.johnrengelman.shadow' version '1.2.2'
|
||||
}
|
||||
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
||||
dependencies {
|
||||
implementation(project(":pgpainless-core"))
|
||||
|
||||
compile 'info.picocli:picocli:3.9.6'
|
||||
|
||||
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
|
||||
|
||||
/*
|
||||
implementation "org.bouncycastle:bcprov-debug-jdk15on:$bouncyCastleVersion"
|
||||
/*/
|
||||
implementation "org.bouncycastle:bcprov-jdk15on:$bouncyCastleVersion"
|
||||
//*/
|
||||
api "org.bouncycastle:bcpg-jdk15on:$bouncyCastleVersion"
|
||||
|
||||
// https://mvnrepository.com/artifact/com.google.code.findbugs/jsr305
|
||||
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
|
||||
}
|
||||
|
||||
mainClassName = 'org.pgpainless.sop.PGPainlessCLI'
|
||||
|
||||
shadowJar {
|
||||
baseName = 'pgpcli'
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.pgpainless.sop;
|
||||
|
||||
import org.pgpainless.sop.commands.ExtractCert;
|
||||
import org.pgpainless.sop.commands.GenerateKey;
|
||||
import org.pgpainless.sop.commands.Sign;
|
||||
import org.pgpainless.sop.commands.Version;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@CommandLine.Command(
|
||||
subcommands = {
|
||||
Version.class,
|
||||
GenerateKey.class,
|
||||
ExtractCert.class,
|
||||
Sign.class
|
||||
}
|
||||
)
|
||||
public class PGPainlessCLI implements Runnable {
|
||||
|
||||
public static void main(String[] args) {
|
||||
interpret(args);
|
||||
// generateKey();
|
||||
}
|
||||
|
||||
public static void interpret(String... args) {
|
||||
CommandLine.run(new PGPainlessCLI(), args);
|
||||
}
|
||||
|
||||
private static void version() {
|
||||
CommandLine.run(new PGPainlessCLI(), "version");
|
||||
}
|
||||
|
||||
private static void generateKey() {
|
||||
interpret("generate-key", "--armor", "Alice Example <alice@wonderland.lit>");
|
||||
}
|
||||
|
||||
private static void extractCert() {
|
||||
CommandLine.run(new PGPainlessCLI(), "extract-cert");
|
||||
}
|
||||
|
||||
private static void sign() {
|
||||
interpret("sign", "--armor", "--as=text", "alice.sec");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
}
|
||||
}
|
16
pgpainless-sop/src/main/java/org/pgpainless/sop/Print.java
Normal file
16
pgpainless-sop/src/main/java/org/pgpainless/sop/Print.java
Normal file
|
@ -0,0 +1,16 @@
|
|||
package org.pgpainless.sop;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.pgpainless.util.ArmorUtils;
|
||||
|
||||
public class Print {
|
||||
|
||||
public static String toString(byte[] bytes, boolean armor) throws IOException {
|
||||
if (armor) {
|
||||
return ArmorUtils.toAsciiArmoredString(bytes);
|
||||
} else {
|
||||
return new String(bytes, "UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package org.pgpainless.sop.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.sop.Print;
|
||||
import org.pgpainless.util.BCUtil;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@CommandLine.Command(name = "extract-cert")
|
||||
public class ExtractCert implements Runnable {
|
||||
|
||||
@CommandLine.Option(names = {"--armor"}, description = "ASCII Armor the output")
|
||||
boolean armor = false;
|
||||
|
||||
@CommandLine.Option(names = {"--no-armor"})
|
||||
boolean noArmor = false;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(System.in);
|
||||
PGPPublicKeyRing publicKeys = BCUtil.publicKeyRingFromSecretKeyRing(secretKeys);
|
||||
|
||||
System.out.println(Print.toString(publicKeys.getEncoded(), !noArmor));
|
||||
} catch (IOException | PGPException e) {
|
||||
System.err.println("Error extracting certificate from keys;");
|
||||
System.err.println(e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package org.pgpainless.sop.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.sop.Print;
|
||||
import org.pgpainless.util.ArmorUtils;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@CommandLine.Command(name = "generate-key")
|
||||
public class GenerateKey implements Runnable {
|
||||
|
||||
@CommandLine.Option(names = {"--armor"}, description = "ASCII Armor the output")
|
||||
boolean armor = false;
|
||||
|
||||
@CommandLine.Option(names = {"--no-armor"})
|
||||
boolean noArmor = false;
|
||||
|
||||
@CommandLine.Parameters
|
||||
String userId;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing(userId).getSecretKeys();
|
||||
|
||||
System.out.println(Print.toString(secretKeys.getEncoded(), !noArmor));
|
||||
|
||||
} catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | PGPException | IOException e) {
|
||||
System.err.println("Error creating OpenPGP key:");
|
||||
System.err.println(e.getMessage());
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package org.pgpainless.sop.commands;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSignature;
|
||||
import org.bouncycastle.util.io.Streams;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.encryption_signing.EncryptionStream;
|
||||
import org.pgpainless.key.protection.UnprotectedKeysProtector;
|
||||
import org.pgpainless.sop.Print;
|
||||
import picocli.CommandLine;
|
||||
|
||||
@CommandLine.Command(name = "sign")
|
||||
public class Sign implements Runnable {
|
||||
|
||||
public enum Type {
|
||||
binary,
|
||||
text
|
||||
}
|
||||
|
||||
@CommandLine.Option(names = {"--armor"}, description = "ASCII Armor the output")
|
||||
boolean armor = false;
|
||||
|
||||
@CommandLine.Option(names = {"--no-armor"})
|
||||
boolean noArmor = false;
|
||||
|
||||
@CommandLine.Option(names = "--as", description = "Defaults to 'binary'. If '--as=text' and the input data is not valid UTF-8, sign fails with return code 53.")
|
||||
Type type;
|
||||
|
||||
@CommandLine.Parameters
|
||||
File secretKeyFile;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PGPSecretKeyRing secretKeys;
|
||||
try {
|
||||
secretKeys = PGPainless.readKeyRing().secretKeyRing(new FileInputStream(secretKeyFile));
|
||||
} catch (IOException | PGPException e) {
|
||||
System.err.println("Error reading secret key ring.");
|
||||
System.err.println(e.getMessage());
|
||||
|
||||
System.exit(1);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
EncryptionStream encryptionStream = PGPainless.createEncryptor()
|
||||
.onOutputStream(out)
|
||||
.doNotEncrypt()
|
||||
.createDetachedSignature()
|
||||
.signWith(new UnprotectedKeysProtector(), secretKeys)
|
||||
.noArmor();
|
||||
|
||||
Streams.pipeAll(System.in, encryptionStream);
|
||||
encryptionStream.close();
|
||||
|
||||
PGPSignature signature = encryptionStream.getResult().getSignatures().iterator().next();
|
||||
|
||||
System.out.println(Print.toString(signature.getEncoded(), !noArmor));
|
||||
} catch (PGPException | IOException e) {
|
||||
System.err.println("Error signing data.");
|
||||
System.err.println(e.getMessage());
|
||||
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package org.pgpainless.sop.commands;
|
||||
|
||||
import picocli.CommandLine;
|
||||
|
||||
@CommandLine.Command(name = "version")
|
||||
public class Version implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println("PGPainless CLI version 0.0.1");
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
rootProject.name = 'PGPainless'
|
||||
|
||||
include 'pgpainless-core'
|
||||
include 'pgpainless-core',
|
||||
'pgpainless-sop'
|
||||
|
||||
|
|
Loading…
Reference in a new issue