Skip to content

Commit ebb4be1

Browse files
committed
Merge branch 'RM-4097' into 'master'
RM-4097: Fix password encryption without label See merge request cdoc2/cdoc2-java-ref-impl!74
2 parents dac709e + ddaac97 commit ebb4be1

File tree

4 files changed

+76
-29
lines changed

4 files changed

+76
-29
lines changed

cdoc2-cli/src/main/java/ee/cyber/cdoc2/cli/util/FormattedLabeledSecretParam.java

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import java.nio.charset.StandardCharsets;
1313
import java.util.Arrays;
1414
import java.util.Base64;
15+
import java.util.Objects;
1516

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

@@ -41,10 +42,6 @@ class FormattedLabeledSecretParam implements LabeledPassword, LabeledSecret {
4142

4243
private final char[] secretAsPassword;
4344

44-
private record ParsedFields(String label, byte[] secret, char[] pw) {
45-
46-
}
47-
4845
FormattedLabeledSecretParam(EncryptionKeyOrigin keyOrigin, ParsedFields parsed) {
4946
this.keyOrigin = keyOrigin;
5047
this.label = parsed.label();
@@ -92,7 +89,7 @@ private static ParsedFields parseFields(
9289
if (secret.startsWith(BASE_64_PREFIX)) {
9390
byte[] secretAsBytes = Base64.getDecoder().decode(secret.substring(BASE_64_PREFIX.length()));
9491

95-
log.debug("Decoded bytes from base64", secretAsBytes.length);
92+
log.debug("Decoded bytes from base64 with length {}", secretAsBytes.length);
9693

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

132+
private record ParsedFields(String label, byte[] secret, char[] pw) {
133+
@Override
134+
public boolean equals(Object o) {
135+
if (this == o) {
136+
return true;
137+
}
138+
if (o == null || getClass() != o.getClass()) return false;
139+
ParsedFields that = (ParsedFields) o;
140+
return Objects.deepEquals(this.pw, that.pw)
141+
&& Objects.equals(this.label, that.label)
142+
&& Objects.deepEquals(this.secret, that.secret);
143+
}
144+
145+
@Override
146+
public int hashCode() {
147+
return Objects.hash(this.label, Arrays.hashCode(this.secret), Arrays.hashCode(this.pw));
148+
}
149+
150+
@Override
151+
public String toString() {
152+
return "ParsedFields{"
153+
+ "label='" + this.label + '\''
154+
+ ", secret=*****"
155+
+ ", pw=*****"
156+
+ '}';
157+
}
158+
}
159+
135160
}

cdoc2-cli/src/test/java/cli/CDocCliTest.java

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -93,28 +93,39 @@ void testCreateDecryptDocRSA() throws IOException {
9393
@Test
9494
void testSuccessfulCreateDecryptDocWithPassword() throws IOException {
9595
encrypt(PASSWORD_OPTION);
96-
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
96+
decryptSuccessfully(PASSWORD_OPTION);
9797
}
9898

9999
@Test
100100
@Disabled("Requires user interaction for inserting password 'myPlainTextPassword'")
101101
void testSuccessfulCreateDecryptDocWithPasswordWhenItIsInsertedInteractively()
102102
throws IOException {
103103
encrypt(PASSWORD_OPTION);
104-
decrypt("--password=", SUCCESSFUL_EXIT_CODE);
104+
decryptSuccessfully("--password=");
105105
}
106106

107107
@Test
108-
void testSuccessfulCreateDecryptDocWithPasswordWhenLabelIsMissing()
109-
throws IOException {
108+
void testSuccessfulCreateDecryptDocWithPasswordWhenLabelIsMissing() throws IOException {
110109
encrypt(PASSWORD_OPTION);
111-
decrypt("--password=:myPlainTextPassword", SUCCESSFUL_EXIT_CODE);
110+
decryptSuccessfully("--password=:myPlainTextPassword");
111+
}
112+
113+
@Test
114+
void testSuccessfulCreateDecryptDocWithMissingLabelInPassword() throws IOException {
115+
encrypt("--password=:myPlainTextPassword");
116+
decryptSuccessfully("--password=:myPlainTextPassword");
117+
}
118+
119+
@Test
120+
void testSuccessfulCreateDecryptDocWithMissingLabelInSecretKey() throws IOException {
121+
encrypt("--secret=:base64,aejUgxxSQXqiiyrxSGACfMiIRBZq5KjlCwr/xVNY/B0=");
122+
decryptSuccessfully("--secret=:base64,aejUgxxSQXqiiyrxSGACfMiIRBZq5KjlCwr/xVNY/B0=");
112123
}
113124

114125
@Test
115126
void testSuccessfulCreateDecryptDocWithSecret() throws IOException {
116127
encrypt(SECRET_OPTION);
117-
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
128+
decryptSuccessfully(SECRET_OPTION);
118129
}
119130

120131
@Test
@@ -135,9 +146,7 @@ void failToEncryptDocWhenSecretInPlainText() {
135146
void shouldFailToEncryptDocWithSecretButDecryptWithPassword() {
136147
encrypt(SECRET_OPTION);
137148

138-
assertThrowsException(() ->
139-
decrypt(PASSWORD_OPTION, FAILURE_EXIT_CODE)
140-
);
149+
assertThrowsException(() -> failToDecrypt(PASSWORD_OPTION));
141150
}
142151

143152
/**
@@ -149,29 +158,25 @@ void shouldFailToEncryptDocWithSecretButDecryptWithPassword() {
149158
void shouldFailToEncryptDocWithPasswordButDecryptWithSecret() {
150159
encrypt(PASSWORD_OPTION);
151160

152-
assertThrowsException(() ->
153-
decrypt(SECRET_OPTION, FAILURE_EXIT_CODE)
154-
);
161+
assertThrowsException(() -> failToDecrypt(SECRET_OPTION));
155162
}
156163

157164
@Test
158165
void shouldFailToEncryptDocWithPasswordIfItsValidationHasFailed() {
159166
String passwordForEncrypt = "--password=passwordlabel:short";
160-
assertThrowsException(() ->
161-
encrypt(passwordForEncrypt)
162-
);
167+
assertThrowsException(() -> encrypt(passwordForEncrypt));
163168
}
164169

165170
@Test
166171
void shouldSucceedToEncryptDocWithTwoKeysAndDecryptWithPassword() throws IOException {
167172
encryptWithTwoKeys(PASSWORD_OPTION, SECRET_OPTION);
168-
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
173+
decryptSuccessfully(PASSWORD_OPTION);
169174
}
170175

171176
@Test
172177
void shouldSucceedToEncryptDocWithTwoKeysAndDecryptWithSecret() throws IOException {
173178
encryptWithTwoKeys(PASSWORD_OPTION, SECRET_OPTION);
174-
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
179+
decryptSuccessfully(SECRET_OPTION);
175180
}
176181

177182
@Test
@@ -218,7 +223,7 @@ void shouldFailWithTheSameOutputDirectoryWhenReEncrypt(@TempDir Path tempPath) {
218223
@Test
219224
void infoShouldDisplayKeyLabelInDefaultFormatForPassword() throws IOException {
220225
encrypt(PASSWORD_OPTION);
221-
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
226+
decryptSuccessfully(PASSWORD_OPTION);
222227

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

231236
encrypt(PASSWORD_OPTION);
232-
decrypt(PASSWORD_OPTION, SUCCESSFUL_EXIT_CODE);
237+
decryptSuccessfully(PASSWORD_OPTION);
233238

234239
String expectedKeyLabel = "Password: LABEL:passwordlabel";
235240
executeInfo(expectedKeyLabel, cdocFile);
@@ -240,7 +245,7 @@ void infoShouldDisplayKeyLabelInPlainText() throws IOException {
240245
@Test
241246
void infoShouldDisplayKeyLabelInDefaultFormatForSecret() throws IOException {
242247
encrypt(SECRET_OPTION);
243-
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
248+
decryptSuccessfully(SECRET_OPTION);
244249

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

254259
encrypt(SECRET_OPTION);
255-
decrypt(SECRET_OPTION, SUCCESSFUL_EXIT_CODE);
260+
decryptSuccessfully(SECRET_OPTION);
256261

257262
String expectedKeyLabel = "SymmetricKey: LABEL:label_b64secret";
258263
executeInfo(expectedKeyLabel, cdocFile);
@@ -287,7 +292,7 @@ private void successfullyDecryptDocWithPublicKey(
287292
String privateKeyArg = "--key=" + privateKey;
288293

289294
encrypt(publicKeyArg);
290-
decrypt(privateKeyArg, SUCCESSFUL_EXIT_CODE);
295+
decryptSuccessfully(privateKeyArg);
291296
}
292297

293298
private void reEncryptCDocAndTestToDecrypt(
@@ -374,6 +379,14 @@ private void encryptWithTwoKeys(String encryptionArgument1, String encryptionArg
374379
executeEncryption(encryptArgs, cdocFile);
375380
}
376381

382+
private void decryptSuccessfully(String decryptArgs) throws IOException {
383+
decrypt(decryptArgs, SUCCESSFUL_EXIT_CODE);
384+
}
385+
386+
private void failToDecrypt(String decryptArgs) throws IOException {
387+
decrypt(decryptArgs, FAILURE_EXIT_CODE);
388+
}
389+
377390
private void decrypt(String decryptionArgument, int expectedDecryptExitCode)
378391
throws IOException {
379392

cdoc2-lib/src/main/java/ee/cyber/cdoc2/crypto/KeyLabelTools.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,10 +389,14 @@ private static Map<String, String> convertStringToKeyLabelParamsMap(String data)
389389
}
390390
String[] parts = data.split(DATA_PARAMETERS_DELIMITER);
391391

392-
393392
for (String keyValue : parts) {
394393
String[] params = keyValue.split(DATA_PARAMETERS_KEY_VALUE_DELIMITER);
395-
result.put(params[0], urlDecodeValue(params[1]));
394+
if (KeyLabelDataFields.LABEL.name().equals(params[0]) && params.length == 1) {
395+
396+
result.put(params[0], "");
397+
} else {
398+
result.put(params[0], urlDecodeValue(params[1]));
399+
}
396400
}
397401

398402
return result;

cdoc2-lib/src/test/java/ee/cyber/cdoc2/KeyLabelToolsTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,11 @@ void testPasswordKeyLabelParamsCreation() {
109109
);
110110
}
111111

112+
@Test
113+
void testPasswordKeyLabelParamsCreationWithMissingKeyLabelInSymmetricKey() {
114+
createSymmetricKeyLabelParams(EncryptionKeyOrigin.PASSWORD, "");
115+
}
116+
112117
@Test
113118
void testPublicKeyLabelParamsCreation() {
114119
KeyLabelParams keyLabelParams = createPublicKeyLabelParams(null, null);

0 commit comments

Comments
 (0)