Skip to content

Commit

Permalink
Merge branch 'RM-4097' into 'master'
Browse files Browse the repository at this point in the history
RM-4097: Fix password encryption without label

See merge request cdoc2/cdoc2-java-ref-impl!74
  • Loading branch information
OlesjaAarma committed Nov 12, 2024
2 parents dac709e + ddaac97 commit ebb4be1
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.Objects;

import static ee.cyber.cdoc2.crypto.KeyLabelTools.createSymmetricKeyLabelParams;

Expand Down Expand Up @@ -41,10 +42,6 @@ class FormattedLabeledSecretParam implements LabeledPassword, LabeledSecret {

private final char[] secretAsPassword;

private record ParsedFields(String label, byte[] secret, char[] pw) {

}

FormattedLabeledSecretParam(EncryptionKeyOrigin keyOrigin, ParsedFields parsed) {
this.keyOrigin = keyOrigin;
this.label = parsed.label();
Expand Down Expand Up @@ -92,7 +89,7 @@ private static ParsedFields parseFields(
if (secret.startsWith(BASE_64_PREFIX)) {
byte[] secretAsBytes = Base64.getDecoder().decode(secret.substring(BASE_64_PREFIX.length()));

log.debug("Decoded bytes from base64", secretAsBytes.length);
log.debug("Decoded bytes from base64 with length {}", secretAsBytes.length);

CharBuffer chBuf = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(secretAsBytes));
char[] secretAsPassword = new char[chBuf.remaining()];
Expand Down Expand Up @@ -132,4 +129,32 @@ public char[] getPassword() {
return Arrays.copyOf(secretAsPassword, secretAsPassword.length);
}

private record ParsedFields(String label, byte[] secret, char[] pw) {
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) return false;
ParsedFields that = (ParsedFields) o;
return Objects.deepEquals(this.pw, that.pw)
&& Objects.equals(this.label, that.label)
&& Objects.deepEquals(this.secret, that.secret);
}

@Override
public int hashCode() {
return Objects.hash(this.label, Arrays.hashCode(this.secret), Arrays.hashCode(this.pw));
}

@Override
public String toString() {
return "ParsedFields{"
+ "label='" + this.label + '\''
+ ", secret=*****"
+ ", pw=*****"
+ '}';
}
}

}
57 changes: 35 additions & 22 deletions cdoc2-cli/src/test/java/cli/CDocCliTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,28 +93,39 @@ void testCreateDecryptDocRSA() throws IOException {
@Test
void testSuccessfulCreateDecryptDocWithPassword() throws IOException {
encrypt(PASSWORD_OPTION);
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(PASSWORD_OPTION);
}

@Test
@Disabled("Requires user interaction for inserting password 'myPlainTextPassword'")
void testSuccessfulCreateDecryptDocWithPasswordWhenItIsInsertedInteractively()
throws IOException {
encrypt(PASSWORD_OPTION);
decrypt("--password=", SUCCESSFUL_EXIT_CODE);
decryptSuccessfully("--password=");
}

@Test
void testSuccessfulCreateDecryptDocWithPasswordWhenLabelIsMissing()
throws IOException {
void testSuccessfulCreateDecryptDocWithPasswordWhenLabelIsMissing() throws IOException {
encrypt(PASSWORD_OPTION);
decrypt("--password=:myPlainTextPassword", SUCCESSFUL_EXIT_CODE);
decryptSuccessfully("--password=:myPlainTextPassword");
}

@Test
void testSuccessfulCreateDecryptDocWithMissingLabelInPassword() throws IOException {
encrypt("--password=:myPlainTextPassword");
decryptSuccessfully("--password=:myPlainTextPassword");
}

@Test
void testSuccessfulCreateDecryptDocWithMissingLabelInSecretKey() throws IOException {
encrypt("--secret=:base64,aejUgxxSQXqiiyrxSGACfMiIRBZq5KjlCwr/xVNY/B0=");
decryptSuccessfully("--secret=:base64,aejUgxxSQXqiiyrxSGACfMiIRBZq5KjlCwr/xVNY/B0=");
}

@Test
void testSuccessfulCreateDecryptDocWithSecret() throws IOException {
encrypt(SECRET_OPTION);
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(SECRET_OPTION);
}

@Test
Expand All @@ -135,9 +146,7 @@ void failToEncryptDocWhenSecretInPlainText() {
void shouldFailToEncryptDocWithSecretButDecryptWithPassword() {
encrypt(SECRET_OPTION);

assertThrowsException(() ->
decrypt(PASSWORD_OPTION, FAILURE_EXIT_CODE)
);
assertThrowsException(() -> failToDecrypt(PASSWORD_OPTION));
}

/**
Expand All @@ -149,29 +158,25 @@ void shouldFailToEncryptDocWithSecretButDecryptWithPassword() {
void shouldFailToEncryptDocWithPasswordButDecryptWithSecret() {
encrypt(PASSWORD_OPTION);

assertThrowsException(() ->
decrypt(SECRET_OPTION, FAILURE_EXIT_CODE)
);
assertThrowsException(() -> failToDecrypt(SECRET_OPTION));
}

@Test
void shouldFailToEncryptDocWithPasswordIfItsValidationHasFailed() {
String passwordForEncrypt = "--password=passwordlabel:short";
assertThrowsException(() ->
encrypt(passwordForEncrypt)
);
assertThrowsException(() -> encrypt(passwordForEncrypt));
}

@Test
void shouldSucceedToEncryptDocWithTwoKeysAndDecryptWithPassword() throws IOException {
encryptWithTwoKeys(PASSWORD_OPTION, SECRET_OPTION);
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(PASSWORD_OPTION);
}

@Test
void shouldSucceedToEncryptDocWithTwoKeysAndDecryptWithSecret() throws IOException {
encryptWithTwoKeys(PASSWORD_OPTION, SECRET_OPTION);
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(SECRET_OPTION);
}

@Test
Expand Down Expand Up @@ -218,7 +223,7 @@ void shouldFailWithTheSameOutputDirectoryWhenReEncrypt(@TempDir Path tempPath) {
@Test
void infoShouldDisplayKeyLabelInDefaultFormatForPassword() throws IOException {
encrypt(PASSWORD_OPTION);
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(PASSWORD_OPTION);

String expectedKeyLabel = "Password: V:1, LABEL:passwordlabel, TYPE:pw";
executeInfo(expectedKeyLabel, cdocFile);
Expand All @@ -229,7 +234,7 @@ void infoShouldDisplayKeyLabelInPlainText() throws IOException {
setUpKeyLabelFormat(false);

encrypt(PASSWORD_OPTION);
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(PASSWORD_OPTION);

String expectedKeyLabel = "Password: LABEL:passwordlabel";
executeInfo(expectedKeyLabel, cdocFile);
Expand All @@ -240,7 +245,7 @@ void infoShouldDisplayKeyLabelInPlainText() throws IOException {
@Test
void infoShouldDisplayKeyLabelInDefaultFormatForSecret() throws IOException {
encrypt(SECRET_OPTION);
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(SECRET_OPTION);

String expectedKeyLabel
= "SymmetricKey: V:1, LABEL:label_b64secret, TYPE:secret";
Expand All @@ -252,7 +257,7 @@ void infoShouldDisplayKeyLabelInPlainTextForSecret() throws IOException {
setUpKeyLabelFormat(false);

encrypt(SECRET_OPTION);
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(SECRET_OPTION);

String expectedKeyLabel = "SymmetricKey: LABEL:label_b64secret";
executeInfo(expectedKeyLabel, cdocFile);
Expand Down Expand Up @@ -287,7 +292,7 @@ private void successfullyDecryptDocWithPublicKey(
String privateKeyArg = "--key=" + privateKey;

encrypt(publicKeyArg);
decrypt(privateKeyArg, SUCCESSFUL_EXIT_CODE);
decryptSuccessfully(privateKeyArg);
}

private void reEncryptCDocAndTestToDecrypt(
Expand Down Expand Up @@ -374,6 +379,14 @@ private void encryptWithTwoKeys(String encryptionArgument1, String encryptionArg
executeEncryption(encryptArgs, cdocFile);
}

private void decryptSuccessfully(String decryptArgs) throws IOException {
decrypt(decryptArgs, SUCCESSFUL_EXIT_CODE);
}

private void failToDecrypt(String decryptArgs) throws IOException {
decrypt(decryptArgs, FAILURE_EXIT_CODE);
}

private void decrypt(String decryptionArgument, int expectedDecryptExitCode)
throws IOException {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,10 +389,14 @@ private static Map<String, String> convertStringToKeyLabelParamsMap(String data)
}
String[] parts = data.split(DATA_PARAMETERS_DELIMITER);


for (String keyValue : parts) {
String[] params = keyValue.split(DATA_PARAMETERS_KEY_VALUE_DELIMITER);
result.put(params[0], urlDecodeValue(params[1]));
if (KeyLabelDataFields.LABEL.name().equals(params[0]) && params.length == 1) {

result.put(params[0], "");
} else {
result.put(params[0], urlDecodeValue(params[1]));
}
}

return result;
Expand Down
5 changes: 5 additions & 0 deletions cdoc2-lib/src/test/java/ee/cyber/cdoc2/KeyLabelToolsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ void testPasswordKeyLabelParamsCreation() {
);
}

@Test
void testPasswordKeyLabelParamsCreationWithMissingKeyLabelInSymmetricKey() {
createSymmetricKeyLabelParams(EncryptionKeyOrigin.PASSWORD, "");
}

@Test
void testPublicKeyLabelParamsCreation() {
KeyLabelParams keyLabelParams = createPublicKeyLabelParams(null, null);
Expand Down

0 comments on commit ebb4be1

Please sign in to comment.