mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-09-10 18:59:39 +02:00
Base PGPainlessCLI on new sop-java module
* Rename pgpainless-sop -> pgpainless-cli * Introduce sop-java (implementation-independent SOP API) * Introduce sop-java-picocli (CLI frontend for sop-java) * Introduce pgpainless-sop (implementation of sop-java using PGPainless) * Rework pgpainless-cli (plugs pgpainless-sop into sop-java-picocli)
This commit is contained in:
parent
2ba782c451
commit
8cf5347b52
112 changed files with 6146 additions and 1303 deletions
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli;
|
||||
|
||||
import org.pgpainless.sop.SOPImpl;
|
||||
import sop.cli.picocli.SopCLI;
|
||||
|
||||
public class PGPainlessCLI {
|
||||
|
||||
static {
|
||||
SopCLI.setSopInstance(new SOPImpl());
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int result = execute(args);
|
||||
if (result != 0) {
|
||||
System.exit(result);
|
||||
}
|
||||
}
|
||||
|
||||
public static int execute(String... args) {
|
||||
return SopCLI.execute(args);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2020 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/**
|
||||
* PGPainless SOP implementing a Stateless OpenPGP Command Line Interface.
|
||||
* @see <a href="https://tools.ietf.org/html/draft-dkg-openpgp-stateless-cli-01">
|
||||
* Stateless OpenPGP Command Line Interface
|
||||
* draft-dkg-openpgp-stateless-cli-01</a>
|
||||
*/
|
||||
package org.pgpainless.cli;
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli;
|
||||
|
||||
import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
|
||||
import com.ginsberg.junit.exit.FailOnSystemExit;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class ExitCodeTest {
|
||||
|
||||
@Test
|
||||
@ExpectSystemExitWithStatus(69)
|
||||
public void testUnknownCommand_69() {
|
||||
PGPainlessCLI.main(new String[] {"generate-kex"});
|
||||
}
|
||||
|
||||
@Test
|
||||
@ExpectSystemExitWithStatus(37)
|
||||
public void testCommandWithUnknownOption_37() {
|
||||
PGPainlessCLI.main(new String[] {"generate-key", "-k", "\"k is unknown\""});
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void successfulExecutionDoesNotTerminateJVM() {
|
||||
PGPainlessCLI.main(new String[] {"version"});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Random;
|
||||
|
||||
public class TestUtils {
|
||||
|
||||
public static final String ALPHABET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
private static final Random RANDOM = new Random();
|
||||
|
||||
public static final String ARMOR_PRIVATE_KEY_HEADER = "-----BEGIN PGP PRIVATE KEY BLOCK-----";
|
||||
public static final byte[] ARMOR_PRIVATE_KEY_HEADER_BYTES =
|
||||
ARMOR_PRIVATE_KEY_HEADER.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
public static File createTempDirectory() throws IOException {
|
||||
String name = randomString(10);
|
||||
File dir = Files.createTempDirectory(name).toFile();
|
||||
// dir.deleteOnExit();
|
||||
return dir;
|
||||
}
|
||||
|
||||
private static String randomString(int length) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < length; i++) {
|
||||
sb.append(ALPHABET.charAt(RANDOM.nextInt(ALPHABET.length())));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli.commands;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.cli.PGPainlessCLI;
|
||||
|
||||
public class ArmorTest {
|
||||
|
||||
private static PrintStream originalSout;
|
||||
|
||||
@BeforeEach
|
||||
public void saveSout() {
|
||||
originalSout = System.out;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void restoreSout() {
|
||||
System.setOut(originalSout);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void armorSecretKey() throws IOException, PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
byte[] bytes = secretKey.getEncoded();
|
||||
|
||||
System.setIn(new ByteArrayInputStream(bytes));
|
||||
ByteArrayOutputStream armorOut = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(armorOut));
|
||||
PGPainlessCLI.execute("armor");
|
||||
|
||||
PGPSecretKeyRing armored = PGPainless.readKeyRing().secretKeyRing(armorOut.toString());
|
||||
assertArrayEquals(secretKey.getEncoded(), armored.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void armorPublicKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
PGPPublicKeyRing publicKey = PGPainless.extractCertificate(secretKey);
|
||||
byte[] bytes = publicKey.getEncoded();
|
||||
|
||||
System.setIn(new ByteArrayInputStream(bytes));
|
||||
ByteArrayOutputStream armorOut = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(armorOut));
|
||||
PGPainlessCLI.execute("armor");
|
||||
|
||||
PGPPublicKeyRing armored = PGPainless.readKeyRing().publicKeyRing(armorOut.toString());
|
||||
assertArrayEquals(publicKey.getEncoded(), armored.getEncoded());
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void armorMessage() {
|
||||
String message = "Hello, World!\n";
|
||||
|
||||
System.setIn(new ByteArrayInputStream(message.getBytes(StandardCharsets.UTF_8)));
|
||||
ByteArrayOutputStream armorOut = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(armorOut));
|
||||
PGPainlessCLI.execute("armor");
|
||||
|
||||
String armored = armorOut.toString();
|
||||
|
||||
assertTrue(armored.startsWith("-----BEGIN PGP MESSAGE-----\n"));
|
||||
assertTrue(armored.contains("SGVsbG8sIFdvcmxkIQo="));
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void doesNotNestArmorByDefault() {
|
||||
String armored = "-----BEGIN PGP MESSAGE-----\n" +
|
||||
"Version: BCPG v1.69\n" +
|
||||
"\n" +
|
||||
"SGVsbG8sIFdvcmxkCg==\n" +
|
||||
"=fkLo\n" +
|
||||
"-----END PGP MESSAGE-----";
|
||||
|
||||
System.setIn(new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8)));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
PGPainlessCLI.execute("armor");
|
||||
|
||||
assertEquals(armored, out.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void testAllowNested() {
|
||||
String armored = "-----BEGIN PGP MESSAGE-----\n" +
|
||||
"Version: BCPG v1.69\n" +
|
||||
"\n" +
|
||||
"SGVsbG8sIFdvcmxkCg==\n" +
|
||||
"=fkLo\n" +
|
||||
"-----END PGP MESSAGE-----";
|
||||
|
||||
System.setIn(new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8)));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
PGPainlessCLI.execute("armor", "--allow-nested");
|
||||
|
||||
assertNotEquals(armored, out.toString());
|
||||
assertTrue(out.toString().contains(
|
||||
"LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tClZlcnNpb246IEJDUEcgdjEuNjkK\n" +
|
||||
"ClNHVnNiRzhzSUZkdmNteGtDZz09Cj1ma0xvCi0tLS0tRU5EIFBHUCBNRVNTQUdF\n" +
|
||||
"LS0tLS0="));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli.commands;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
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;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.cli.PGPainlessCLI;
|
||||
|
||||
public class DearmorTest {
|
||||
|
||||
private PrintStream originalSout;
|
||||
|
||||
@BeforeEach
|
||||
public void saveSout() {
|
||||
this.originalSout = System.out;
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void restoreSout() {
|
||||
System.setOut(originalSout);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void dearmorSecretKey() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
String armored = PGPainless.asciiArmor(secretKey);
|
||||
|
||||
System.setIn(new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8)));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
PGPainlessCLI.execute("dearmor");
|
||||
|
||||
assertArrayEquals(secretKey.getEncoded(), out.toByteArray());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void dearmorCertificate() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
PGPSecretKeyRing secretKey = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice@pgpainless.org", null);
|
||||
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKey);
|
||||
String armored = PGPainless.asciiArmor(certificate);
|
||||
|
||||
System.setIn(new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8)));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
PGPainlessCLI.execute("dearmor");
|
||||
|
||||
assertArrayEquals(certificate.getEncoded(), out.toByteArray());
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void dearmorMessage() {
|
||||
String armored = "-----BEGIN PGP MESSAGE-----\n" +
|
||||
"Version: BCPG v1.69\n" +
|
||||
"\n" +
|
||||
"SGVsbG8sIFdvcmxkCg==\n" +
|
||||
"=fkLo\n" +
|
||||
"-----END PGP MESSAGE-----";
|
||||
|
||||
System.setIn(new ByteArrayInputStream(armored.getBytes(StandardCharsets.UTF_8)));
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
PGPainlessCLI.execute("dearmor");
|
||||
|
||||
assertEquals("Hello, World\n", out.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli.commands;
|
||||
|
||||
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.pgpainless.cli.PGPainlessCLI;
|
||||
import org.pgpainless.cli.TestUtils;
|
||||
|
||||
public class EncryptDecryptTest {
|
||||
|
||||
private static File tempDir;
|
||||
private static PrintStream originalSout;
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() throws IOException {
|
||||
tempDir = TestUtils.createTempDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void encryptAndDecryptAMessage() throws IOException {
|
||||
originalSout = System.out;
|
||||
File julietKeyFile = new File(tempDir, "juliet.key");
|
||||
assertTrue(julietKeyFile.createNewFile());
|
||||
|
||||
File julietCertFile = new File(tempDir, "juliet.asc");
|
||||
assertTrue(julietCertFile.createNewFile());
|
||||
|
||||
File romeoKeyFile = new File(tempDir, "romeo.key");
|
||||
assertTrue(romeoKeyFile.createNewFile());
|
||||
|
||||
File romeoCertFile = new File(tempDir, "romeo.asc");
|
||||
assertTrue(romeoCertFile.createNewFile());
|
||||
|
||||
File msgAscFile = new File(tempDir, "msg.asc");
|
||||
assertTrue(msgAscFile.createNewFile());
|
||||
|
||||
OutputStream julietKeyOut = new FileOutputStream(julietKeyFile);
|
||||
System.setOut(new PrintStream(julietKeyOut));
|
||||
PGPainlessCLI.execute("generate-key", "Juliet Capulet <juliet@capulet.lit>");
|
||||
julietKeyOut.close();
|
||||
|
||||
FileInputStream julietKeyIn = new FileInputStream(julietKeyFile);
|
||||
System.setIn(julietKeyIn);
|
||||
OutputStream julietCertOut = new FileOutputStream(julietCertFile);
|
||||
System.setOut(new PrintStream(julietCertOut));
|
||||
PGPainlessCLI.execute("extract-cert");
|
||||
julietKeyIn.close();
|
||||
julietCertOut.close();
|
||||
|
||||
OutputStream romeoKeyOut = new FileOutputStream(romeoKeyFile);
|
||||
System.setOut(new PrintStream(romeoKeyOut));
|
||||
PGPainlessCLI.execute("generate-key", "Romeo Montague <romeo@montague.lit>");
|
||||
romeoKeyOut.close();
|
||||
|
||||
FileInputStream romeoKeyIn = new FileInputStream(romeoKeyFile);
|
||||
System.setIn(romeoKeyIn);
|
||||
OutputStream romeoCertOut = new FileOutputStream(romeoCertFile);
|
||||
System.setOut(new PrintStream(romeoCertOut));
|
||||
PGPainlessCLI.execute("extract-cert");
|
||||
romeoKeyIn.close();
|
||||
romeoCertOut.close();
|
||||
|
||||
String msg = "Hello World!\n";
|
||||
ByteArrayInputStream msgIn = new ByteArrayInputStream(msg.getBytes(StandardCharsets.UTF_8));
|
||||
System.setIn(msgIn);
|
||||
OutputStream msgAscOut = new FileOutputStream(msgAscFile);
|
||||
System.setOut(new PrintStream(msgAscOut));
|
||||
PGPainlessCLI.execute("encrypt",
|
||||
"--sign-with", romeoKeyFile.getAbsolutePath(),
|
||||
julietCertFile.getAbsolutePath());
|
||||
msgAscOut.close();
|
||||
|
||||
File verifyFile = new File(tempDir, "verify.txt");
|
||||
assertTrue(verifyFile.createNewFile());
|
||||
|
||||
FileInputStream msgAscIn = new FileInputStream(msgAscFile);
|
||||
System.setIn(msgAscIn);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
PrintStream pOut = new PrintStream(out);
|
||||
System.setOut(pOut);
|
||||
PGPainlessCLI.execute("decrypt",
|
||||
"--verify-out", verifyFile.getAbsolutePath(),
|
||||
"--verify-with", romeoCertFile.getAbsolutePath(),
|
||||
julietKeyFile.getAbsolutePath());
|
||||
msgAscIn.close();
|
||||
|
||||
assertEquals(msg, out.toString());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
System.setOut(originalSout);
|
||||
// CHECKSTYLE:OFF
|
||||
System.out.println(tempDir.getAbsolutePath());
|
||||
// CHECKSTYLE:ON
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli.commands;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
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;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.cli.PGPainlessCLI;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
|
||||
public class ExtractCertTest {
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void testExtractCert() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, PGPException, IOException {
|
||||
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing()
|
||||
.simpleEcKeyRing("Juliet Capulet <juliet@capulet.lit>");
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(secretKeys.getEncoded());
|
||||
System.setIn(inputStream);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
|
||||
PGPainlessCLI.execute("extract-cert");
|
||||
PGPPublicKeyRing publicKeys = PGPainless.readKeyRing().publicKeyRing(out.toByteArray());
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(publicKeys);
|
||||
assertFalse(info.isSecretKey());
|
||||
assertTrue(info.isUserIdValid("Juliet Capulet <juliet@capulet.lit>"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli.commands;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.pgpainless.cli.TestUtils.ARMOR_PRIVATE_KEY_HEADER_BYTES;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ginsberg.junit.exit.FailOnSystemExit;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.pgpainless.PGPainless;
|
||||
import org.pgpainless.cli.PGPainlessCLI;
|
||||
import org.pgpainless.cli.TestUtils;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
|
||||
public class GenerateCertTest {
|
||||
|
||||
private static File tempDir;
|
||||
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() throws IOException {
|
||||
tempDir = TestUtils.createTempDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void testKeyGeneration() throws IOException, PGPException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
PGPainlessCLI.execute("generate-key", "--armor", "Juliet Capulet <juliet@capulet.lit>");
|
||||
|
||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(out.toByteArray());
|
||||
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
|
||||
assertTrue(info.isUserIdValid("Juliet Capulet <juliet@capulet.lit>"));
|
||||
|
||||
byte[] outBegin = new byte[37];
|
||||
System.arraycopy(out.toByteArray(), 0, outBegin, 0, 37);
|
||||
assertArrayEquals(outBegin, ARMOR_PRIVATE_KEY_HEADER_BYTES);
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void testNoArmor() {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(out));
|
||||
PGPainlessCLI.execute("generate-key", "--no-armor", "Test <test@test.test>");
|
||||
|
||||
byte[] outBegin = new byte[37];
|
||||
System.arraycopy(out.toByteArray(), 0, outBegin, 0, 37);
|
||||
assertFalse(Arrays.equals(outBegin, ARMOR_PRIVATE_KEY_HEADER_BYTES));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2021 Paul Schaub.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.pgpainless.cli.commands;
|
||||
|
||||
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.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidAlgorithmParameterException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Date;
|
||||
|
||||
import com.ginsberg.junit.exit.FailOnSystemExit;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||
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.PGPainless;
|
||||
import org.pgpainless.cli.PGPainlessCLI;
|
||||
import org.pgpainless.cli.TestUtils;
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint;
|
||||
import org.pgpainless.key.info.KeyRingInfo;
|
||||
import org.pgpainless.key.util.KeyRingUtils;
|
||||
|
||||
public class SignVerifyTest {
|
||||
|
||||
private static File tempDir;
|
||||
private static PrintStream originalSout;
|
||||
|
||||
private final String data = "If privacy is outlawed, only outlaws will have privacy.\n";
|
||||
|
||||
@BeforeAll
|
||||
public static void prepare() throws IOException {
|
||||
tempDir = TestUtils.createTempDirectory();
|
||||
}
|
||||
|
||||
@Test
|
||||
@FailOnSystemExit
|
||||
public void testSignatureCreationAndVerification() throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, IOException {
|
||||
originalSout = System.out;
|
||||
InputStream originalIn = System.in;
|
||||
|
||||
// Write alice key to disc
|
||||
File aliceKeyFile = new File(tempDir, "alice.key");
|
||||
assertTrue(aliceKeyFile.createNewFile());
|
||||
PGPSecretKeyRing aliceKeys = PGPainless.generateKeyRing()
|
||||
.modernKeyRing("alice", null);
|
||||
OutputStream aliceKeyOut = new FileOutputStream(aliceKeyFile);
|
||||
Streams.pipeAll(new ByteArrayInputStream(aliceKeys.getEncoded()), aliceKeyOut);
|
||||
aliceKeyOut.close();
|
||||
|
||||
// Write alice pub key to disc
|
||||
File aliceCertFile = new File(tempDir, "alice.pub");
|
||||
assertTrue(aliceCertFile.createNewFile());
|
||||
PGPPublicKeyRing alicePub = KeyRingUtils.publicKeyRingFrom(aliceKeys);
|
||||
OutputStream aliceCertOut = new FileOutputStream(aliceCertFile);
|
||||
Streams.pipeAll(new ByteArrayInputStream(alicePub.getEncoded()), aliceCertOut);
|
||||
aliceCertOut.close();
|
||||
|
||||
// Write test data to disc
|
||||
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
|
||||
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.execute("sign", "--armor", aliceKeyFile.getAbsolutePath());
|
||||
sigOut.close();
|
||||
|
||||
// verify test data signature
|
||||
ByteArrayOutputStream verifyOut = new ByteArrayOutputStream();
|
||||
System.setOut(new PrintStream(verifyOut));
|
||||
dataIn = new FileInputStream(dataFile);
|
||||
System.setIn(dataIn);
|
||||
PGPainlessCLI.execute("verify", sigFile.getAbsolutePath(), aliceCertFile.getAbsolutePath());
|
||||
dataIn.close();
|
||||
|
||||
// Test verification output
|
||||
|
||||
// [date] [signing-key-fp] [primary-key-fp] signed by [key.pub]
|
||||
String verification = verifyOut.toString();
|
||||
String[] split = verification.split(" ");
|
||||
OpenPgpV4Fingerprint primaryKeyFingerprint = new OpenPgpV4Fingerprint(aliceKeys);
|
||||
OpenPgpV4Fingerprint signingKeyFingerprint = new OpenPgpV4Fingerprint(new KeyRingInfo(alicePub, new Date()).getSigningSubkeys().get(0));
|
||||
assertEquals(signingKeyFingerprint.toString(), split[1].trim());
|
||||
assertEquals(primaryKeyFingerprint.toString(), split[2].trim());
|
||||
|
||||
System.setIn(originalIn);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void after() {
|
||||
System.setOut(originalSout);
|
||||
// CHECKSTYLE:OFF
|
||||
System.out.println(tempDir.getAbsolutePath());
|
||||
// CHECKSTYLE:ON
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue