diff --git a/external-sop/src/main/java/sop/external/ExternalSOP.java b/external-sop/src/main/java/sop/external/ExternalSOP.java index c2ec911..70acf5b 100644 --- a/external-sop/src/main/java/sop/external/ExternalSOP.java +++ b/external-sop/src/main/java/sop/external/ExternalSOP.java @@ -83,7 +83,7 @@ public class ExternalSOP implements SOP { @Override public DetachedSign detachedSign() { - return new DetachedSignExternal(binaryName, properties); + return new DetachedSignExternal(binaryName, properties, tempDirProvider); } @Override diff --git a/external-sop/src/main/java/sop/external/operation/DecryptExternal.java b/external-sop/src/main/java/sop/external/operation/DecryptExternal.java index f6b2b7f..d0ad5d8 100644 --- a/external-sop/src/main/java/sop/external/operation/DecryptExternal.java +++ b/external-sop/src/main/java/sop/external/operation/DecryptExternal.java @@ -7,17 +7,20 @@ package sop.external.operation; import sop.DecryptionResult; import sop.ReadyWithResult; import sop.SessionKey; +import sop.Verification; import sop.exception.SOPGPException; import sop.external.ExternalSOP; import sop.operation.Decrypt; import sop.util.UTCUtil; +import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Properties; @@ -104,13 +107,17 @@ public class DecryptExternal implements Decrypt { public ReadyWithResult ciphertext(InputStream ciphertext) throws SOPGPException.BadData, SOPGPException.MissingArg, SOPGPException.CannotDecrypt, SOPGPException.KeyIsProtected, IOException { - File tempDir = tempDirProvider.provideTempDirectory(); + File sessionKeyOut = new File(tempDir, "session-key-out"); + sessionKeyOut.delete(); commandList.add("--session-key-out=" + sessionKeyOut.getAbsolutePath()); - File verifyOut = new File(tempDir, "verify-out"); - commandList.add("--verify-out=" + verifyOut.getAbsolutePath()); + File verifyOut = new File(tempDir, "verifications-out"); + verifyOut.delete(); + if (verifyWithCounter != 0) { + commandList.add("--verify-out=" + verifyOut.getAbsolutePath()); + } String[] command = commandList.toArray(new String[0]); String[] env = envList.toArray(new String[0]); @@ -140,7 +147,23 @@ public class DecryptExternal implements Decrypt { ExternalSOP.finish(process); - return new DecryptionResult(null, Collections.emptyList()); // TODO + FileInputStream sessionKeyOutIn = new FileInputStream(sessionKeyOut); + String line = ExternalSOP.readFully(sessionKeyOutIn); + SessionKey sessionKey = SessionKey.fromString(line.trim()); + sessionKeyOutIn.close(); + sessionKeyOut.delete(); + + List verifications = new ArrayList<>(); + if (verifyWithCounter != 0) { + FileInputStream verifyOutIn = new FileInputStream(verifyOut); + BufferedReader reader = new BufferedReader(new InputStreamReader(verifyOutIn)); + while ((line = reader.readLine()) != null) { + verifications.add(Verification.fromString(line.trim())); + } + reader.close(); + } + + return new DecryptionResult(sessionKey, verifications); // TODO } }; } catch (IOException e) { diff --git a/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java b/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java index d82950b..9cdf6ec 100644 --- a/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java +++ b/external-sop/src/main/java/sop/external/operation/DetachedSignExternal.java @@ -4,6 +4,7 @@ package sop.external.operation; +import sop.MicAlg; import sop.ReadyWithResult; import sop.SigningResult; import sop.enums.SignAs; @@ -11,8 +12,12 @@ import sop.exception.SOPGPException; import sop.external.ExternalSOP; import sop.operation.DetachedSign; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; @@ -20,13 +25,15 @@ import java.util.Properties; public class DetachedSignExternal implements DetachedSign { + private final ExternalSOP.TempDirProvider tempDirProvider; private final List commandList = new ArrayList<>(); private final List envList; private int withKeyPasswordCounter = 0; private int keyCounter = 0; - public DetachedSignExternal(String binary, Properties properties) { + public DetachedSignExternal(String binary, Properties properties, ExternalSOP.TempDirProvider tempDirProvider) { + this.tempDirProvider = tempDirProvider; commandList.add(binary); commandList.add("sign"); envList = ExternalSOP.propertiesToEnv(properties); @@ -64,6 +71,11 @@ public class DetachedSignExternal implements DetachedSign { public ReadyWithResult data(InputStream data) throws IOException, SOPGPException.KeyIsProtected, SOPGPException.ExpectedText { + File tempDir = tempDirProvider.provideTempDirectory(); + File micAlgOut = new File(tempDir, "micAlgOut"); + micAlgOut.delete(); + commandList.add("--micalg-out=" + micAlgOut.getAbsolutePath()); + String[] command = commandList.toArray(new String[0]); String[] env = envList.toArray(new String[0]); try { @@ -92,7 +104,18 @@ public class DetachedSignExternal implements DetachedSign { ExternalSOP.finish(process); - return SigningResult.builder().build(); + SigningResult.Builder builder = SigningResult.builder(); + if (micAlgOut.exists()) { + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(micAlgOut))); + String line = reader.readLine(); + if (line != null && !line.trim().isEmpty()) { + builder.setMicAlg(MicAlg.fromHashAlgorithmId(Integer.parseInt(line))); + } + reader.close(); + micAlgOut.delete(); + } + + return builder.build(); } }; } catch (IOException e) { diff --git a/external-sop/src/test/java/sop/external/EncryptDecryptRoundTripTest.java b/external-sop/src/test/java/sop/external/EncryptDecryptRoundTripTest.java index de16215..4a5ad01 100644 --- a/external-sop/src/test/java/sop/external/EncryptDecryptRoundTripTest.java +++ b/external-sop/src/test/java/sop/external/EncryptDecryptRoundTripTest.java @@ -6,15 +6,39 @@ package sop.external; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIf; +import sop.ByteArrayAndResult; +import sop.DecryptionResult; +import sop.Verification; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.List; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; @EnabledIf("sop.external.AbstractExternalSOPTest#isExternalSopInstalled") public class EncryptDecryptRoundTripTest extends AbstractExternalSOPTest { + @Test + public void encryptDecryptRoundTripPasswordTest() throws IOException { + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + byte[] ciphertext = getSop().encrypt() + .withPassword("sw0rdf1sh") + .plaintext(message) + .getBytes(); + + byte[] plaintext = getSop().decrypt() + .withPassword("sw0rdf1sh") + .ciphertext(ciphertext) + .toByteArrayAndResult() + .getBytes(); + + assertArrayEquals(message, plaintext); + } + @Test public void encryptDecryptRoundTripAliceTest() throws IOException { byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); @@ -23,13 +47,16 @@ public class EncryptDecryptRoundTripTest extends AbstractExternalSOPTest { .plaintext(message) .getBytes(); - byte[] plaintext = getSop().decrypt() + ByteArrayAndResult bytesAndResult = getSop().decrypt() .withKey(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) .ciphertext(ciphertext) - .toByteArrayAndResult() - .getBytes(); + .toByteArrayAndResult(); + byte[] plaintext = bytesAndResult.getBytes(); assertArrayEquals(message, plaintext); + + DecryptionResult result = bytesAndResult.getResult(); + assertNotNull(result.getSessionKey().get()); } @Test @@ -67,4 +94,29 @@ public class EncryptDecryptRoundTripTest extends AbstractExternalSOPTest { assertArrayEquals(message, plaintext); } + + @Test + public void encryptSignDecryptVerifyRoundTripAliceTest() throws IOException { + byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8); + byte[] ciphertext = getSop().encrypt() + .withCert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .signWith(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) + .plaintext(message) + .getBytes(); + + ByteArrayAndResult bytesAndResult = getSop().decrypt() + .withKey(TestKeys.ALICE_KEY.getBytes(StandardCharsets.UTF_8)) + .verifyWithCert(TestKeys.ALICE_CERT.getBytes(StandardCharsets.UTF_8)) + .ciphertext(ciphertext) + .toByteArrayAndResult(); + + byte[] plaintext = bytesAndResult.getBytes(); + assertArrayEquals(message, plaintext); + + DecryptionResult result = bytesAndResult.getResult(); + assertNotNull(result.getSessionKey().get()); + List verificationList = result.getVerifications(); + assertEquals(1, verificationList.size()); + assertTrue(verificationList.get(0).toString().contains("EB85BB5FA33A75E15E944E63F231550C4F47E38E EB85BB5FA33A75E15E944E63F231550C4F47E38E")); + } }