• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

pgpainless / sop-java / #70

20 Jan 2026 10:49PM UTC coverage: 57.318% (-0.1%) from 57.424%
#70

push

other

vanitasvitae
Fix test actually performing the decryption

1 of 7 new or added lines in 1 file covered. (14.29%)

29 existing lines in 3 files now uncovered.

2103 of 3669 relevant lines covered (57.32%)

0.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

24.37
/sop-java-testfixtures/src/main/java/sop/testsuite/operation/EncryptDecryptTest.java
1
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
2
//
3
// SPDX-License-Identifier: Apache-2.0
4

5
package sop.testsuite.operation;
6

7
import org.junit.jupiter.api.Disabled;
8
import org.junit.jupiter.api.condition.EnabledIf;
9
import org.junit.jupiter.params.ParameterizedTest;
10
import org.junit.jupiter.params.provider.Arguments;
11
import org.junit.jupiter.params.provider.MethodSource;
12
import sop.ByteArrayAndResult;
13
import sop.DecryptionResult;
14
import sop.EncryptionResult;
15
import sop.Profile;
16
import sop.SOP;
17
import sop.SessionKey;
18
import sop.Verification;
19
import sop.enums.EncryptAs;
20
import sop.enums.EncryptFor;
21
import sop.enums.SignatureMode;
22
import sop.exception.SOPGPException;
23
import sop.operation.Decrypt;
24
import sop.operation.Encrypt;
25
import sop.testsuite.TestData;
26
import sop.testsuite.assertions.VerificationListAssert;
27
import sop.util.Optional;
28
import sop.util.UTCUtil;
29

30
import java.io.IOException;
31
import java.nio.charset.StandardCharsets;
32
import java.text.ParseException;
33
import java.util.ArrayList;
34
import java.util.Date;
35
import java.util.List;
36
import java.util.stream.Stream;
37

38
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
39
import static org.junit.jupiter.api.Assertions.assertEquals;
40
import static org.junit.jupiter.api.Assertions.assertNotNull;
41
import static org.junit.jupiter.api.Assertions.assertThrows;
42

43
@EnabledIf("sop.testsuite.operation.AbstractSOPTest#hasBackends")
44
public class EncryptDecryptTest extends AbstractSOPTest {
1✔
45

46
    static Stream<Arguments> provideInstances() {
47
        return provideBackends();
1✔
48
    }
49

50
    @ParameterizedTest
51
    @MethodSource("provideInstances")
52
    public void encryptDecryptRoundTripPasswordTest(SOP sop) throws IOException {
53
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
1✔
54
        ByteArrayAndResult<EncryptionResult> encResult = assumeSupported(sop::encrypt)
1✔
55
                .withPassword("sw0rdf1sh")
1✔
56
                .plaintext(message)
1✔
57
                .toByteArrayAndResult();
×
58

59
        byte[] ciphertext = encResult.getBytes();
×
60
        Optional<SessionKey> encSessionKey = encResult.getResult().getSessionKey();
×
61

62
        ByteArrayAndResult<DecryptionResult> decResult = assumeSupported(sop::decrypt)
×
63
                .withPassword("sw0rdf1sh")
×
64
                .ciphertext(ciphertext)
×
65
                .toByteArrayAndResult();
×
66

67
        byte[] plaintext = decResult.getBytes();
×
68
        Optional<SessionKey> decSessionKey = decResult.getResult().getSessionKey();
×
69

70
        assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext.");
×
71
        if (encSessionKey.isPresent() && decSessionKey.isPresent()) {
×
72
            assertEquals(encSessionKey.get(), decSessionKey.get(),
×
73
                    "Extracted Session Key mismatch.");
74
        }
75
    }
×
76

77
    @ParameterizedTest
78
    @MethodSource("provideInstances")
79
    public void encryptDecryptRoundTripAliceTest(SOP sop) throws IOException {
80
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
1✔
81
        byte[] ciphertext = assumeSupported(sop::encrypt)
1✔
82
                .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
1✔
83
                .plaintext(message)
1✔
84
                .toByteArrayAndResult()
×
85
                .getBytes();
×
86

87
        ByteArrayAndResult<DecryptionResult> bytesAndResult = assumeSupported(sop::decrypt)
×
88
                .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
×
89
                .ciphertext(ciphertext)
×
90
                .toByteArrayAndResult();
×
91

92
        byte[] plaintext = bytesAndResult.getBytes();
×
93
        assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext.");
×
94

95
        DecryptionResult result = bytesAndResult.getResult();
×
96
        if (result.getSessionKey().isPresent()) {
×
97
            assertNotNull(result.getSessionKey().get(), "Session key MUST NOT be null.");
×
98
        }
99
    }
×
100

101
    @ParameterizedTest
102
    @MethodSource("provideInstances")
103
    public void encryptDecryptRoundTripBobTest(SOP sop) throws IOException {
104
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
1✔
105
        byte[] ciphertext = assumeSupported(sop::encrypt)
1✔
106
                .withCert(TestData.BOB_CERT.getBytes(StandardCharsets.UTF_8))
1✔
107
                .plaintext(message)
1✔
108
                .toByteArrayAndResult()
×
109
                .getBytes();
×
110

111
        byte[] plaintext = assumeSupported(sop::decrypt)
×
112
                .withKey(TestData.BOB_KEY.getBytes(StandardCharsets.UTF_8))
×
113
                .ciphertext(ciphertext)
×
114
                .toByteArrayAndResult()
×
115
                .getBytes();
×
116

117
        assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext.");
×
118
    }
×
119

120
    @ParameterizedTest
121
    @MethodSource("provideInstances")
122
    @Disabled("Carol is a deprecated ElGamal key")
123
    public void encryptDecryptRoundTripCarolTest(SOP sop) throws IOException {
124
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
×
125
        byte[] ciphertext = assumeSupported(sop::encrypt)
×
126
                .withCert(TestData.CAROL_CERT.getBytes(StandardCharsets.UTF_8))
×
127
                .plaintext(message)
×
128
                .toByteArrayAndResult()
×
129
                .getBytes();
×
130

131
        byte[] plaintext = assumeSupported(sop::decrypt)
×
132
                .withKey(TestData.CAROL_KEY.getBytes(StandardCharsets.UTF_8))
×
133
                .ciphertext(ciphertext)
×
134
                .toByteArrayAndResult()
×
135
                .getBytes();
×
136

137
        assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext.");
×
138
    }
×
139

140
    @ParameterizedTest
141
    @MethodSource("provideInstances")
142
    public void encryptNoArmorThenArmorThenDecryptRoundTrip(SOP sop) throws IOException {
143
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
1✔
144
        byte[] ciphertext = assumeSupported(sop::encrypt)
1✔
145
                .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
1✔
146
                .noArmor()
1✔
147
                .plaintext(message)
1✔
148
                .toByteArrayAndResult()
×
149
                .getBytes();
×
150

151
        byte[] armored = assumeSupported(sop::armor)
×
152
                .data(ciphertext)
×
153
                .getBytes();
×
154

155
        ByteArrayAndResult<DecryptionResult> bytesAndResult = assumeSupported(sop::decrypt)
×
156
                .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
×
157
                .ciphertext(armored)
×
158
                .toByteArrayAndResult();
×
159

160
        byte[] plaintext = bytesAndResult.getBytes();
×
161
        assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext.");
×
162
    }
×
163

164
    @ParameterizedTest
165
    @MethodSource("provideInstances")
166
    public void encryptSignDecryptVerifyRoundTripAliceTest(SOP sop) throws IOException {
167
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
1✔
168
        byte[] ciphertext = assumeSupported(sop::encrypt)
1✔
169
                .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
1✔
170
                .signWith(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
1✔
171
                .mode(EncryptAs.binary)
1✔
172
                .plaintext(message)
1✔
173
                .toByteArrayAndResult()
×
174
                .getBytes();
×
175

176
        ByteArrayAndResult<DecryptionResult> bytesAndResult = assumeSupported(sop::decrypt)
×
177
                .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
×
178
                .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
×
179
                .ciphertext(ciphertext)
×
180
                .toByteArrayAndResult();
×
181

182
        byte[] plaintext = bytesAndResult.getBytes();
×
183
        assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext.");
×
184

185
        DecryptionResult result = bytesAndResult.getResult();
×
186
        if (result.getSessionKey().isPresent()) {
×
187
            assertNotNull(result.getSessionKey().get(), "Session key MUST NOT be null.");
×
188
        }
189

190
        List<Verification> verificationList = result.getVerifications();
×
191
        VerificationListAssert.assertThatVerificationList(verificationList)
×
192
                .isNotEmpty()
×
193
                .hasSingleItem()
×
194
                .issuedBy(TestData.ALICE_SIGNING_FINGERPRINT, TestData.ALICE_PRIMARY_FINGERPRINT)
×
195
                .hasModeOrNull(SignatureMode.binary);
×
196
    }
×
197

198
    @ParameterizedTest
199
    @MethodSource("provideInstances")
200
    public void encryptSignAsTextDecryptVerifyRoundTripAliceTest(SOP sop) throws IOException {
201
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
1✔
202
        byte[] ciphertext = assumeSupported(sop::encrypt)
1✔
203
                .withCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
1✔
204
                .signWith(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
1✔
205
                .mode(EncryptAs.text)
1✔
206
                .plaintext(message)
1✔
207
                .toByteArrayAndResult()
×
208
                .getBytes();
×
209

210
        ByteArrayAndResult<DecryptionResult> bytesAndResult = assumeSupported(sop::decrypt)
×
211
                .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
×
212
                .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
×
213
                .ciphertext(ciphertext)
×
214
                .toByteArrayAndResult();
×
215

216
        byte[] plaintext = bytesAndResult.getBytes();
×
217
        assertArrayEquals(message, plaintext, "Decrypted plaintext does not match original plaintext.");
×
218

219
        DecryptionResult result = bytesAndResult.getResult();
×
220
        assertNotNull(result.getSessionKey().get());
×
221

222
        List<Verification> verificationList = result.getVerifications();
×
223
        VerificationListAssert.assertThatVerificationList(verificationList)
×
224
                .hasSingleItem()
×
225
                .issuedBy(TestData.ALICE_SIGNING_FINGERPRINT, TestData.ALICE_PRIMARY_FINGERPRINT)
×
226
                .hasModeOrNull(SignatureMode.text);
×
227
    }
×
228

229
    @ParameterizedTest
230
    @MethodSource("provideInstances")
231
    public void encryptSignDecryptVerifyRoundTripWithFreshEncryptedKeyTest(SOP sop) throws IOException {
232
        byte[] keyPassword = "sw0rdf1sh".getBytes(StandardCharsets.UTF_8);
1✔
233
        byte[] key = assumeSupported(sop::generateKey)
1✔
234
                .withKeyPassword(keyPassword)
1✔
235
                .userId("Alice <alice@openpgp.org>")
1✔
236
                .generate()
1✔
237
                .getBytes();
×
238
        byte[] cert = assumeSupported(sop::extractCert)
×
239
                .key(key)
×
240
                .getBytes();
×
241

242
        byte[] message = "Hello, World!\n".getBytes(StandardCharsets.UTF_8);
×
243
        byte[] ciphertext = assumeSupported(sop::encrypt)
×
244
                .withCert(cert)
×
245
                .signWith(key)
×
246
                .withKeyPassword(keyPassword)
×
247
                .plaintext(message)
×
248
                .toByteArrayAndResult()
×
249
                .getBytes();
×
250

251
        ByteArrayAndResult<DecryptionResult> bytesAndResult = assumeSupported(sop::decrypt)
×
252
                .withKey(key)
×
253
                .withKeyPassword(keyPassword)
×
254
                .verifyWithCert(cert)
×
255
                .ciphertext(ciphertext)
×
256
                .toByteArrayAndResult();
×
257

258
        List<Verification> verifications = bytesAndResult.getResult().getVerifications();
×
259
        VerificationListAssert.assertThatVerificationList(verifications)
×
260
                .isNotEmpty()
×
261
                .hasSingleItem();
×
262
    }
×
263

264
    @ParameterizedTest
265
    @MethodSource("provideInstances")
266
    public void decryptVerifyNotAfterTest(SOP sop) throws ParseException {
267
        byte[] message = ("-----BEGIN PGP MESSAGE-----\n" +
1✔
268
                "\n" +
269
                "wV4DR2b2udXyHrYSAQdAwlOwwyxFDJta5+H9abgSj8jum9v7etUc9usdrElESmow\n" +
270
                "2Hka48AFVfOezYh0OFn9R8+DMcpuE+e4nw3XnnX5nKs/j3AC2IW6zRHUkRcF3ZCq\n" +
271
                "0sBNAfjnTYCMjuBmqdcCLzaZT4Hadnpg6neP1UecT/jP14maGfv8nwt0IDGR0Bik\n" +
272
                "0WC/UJLpWyJ/6TgRrA5hNfANVnfiFBzIiThiVBRWPT2StHr2cOAvFxQK4Uk07rK9\n" +
273
                "9aTUak8FpML+QA83U8I3qOk4QbzGVBP+IDJ+AKmvDz+0V+9kUhKp+8vyXsBmo9c3\n" +
274
                "SAXjhFSiPQkU7ORsc6gQHL9+KPOU+W2poPK87H3cmaGiusnXMeLXLIUbkBUJTswd\n" +
275
                "JNrA2yAkTTFP9QabsdcdTGoeYamq1c29kHF3GOTTcEqXw4WWXngcF7Kbcf435kkL\n" +
276
                "4iSJnCaxTPftKUxmiGqMqLef7ICVnq/lz3HrH1VD54s=\n" +
277
                "=Ebi3\n" +
278
                "-----END PGP MESSAGE-----").getBytes(StandardCharsets.UTF_8);
1✔
279
        Date signatureDate = UTCUtil.parseUTCDate("2023-01-13T16:09:32Z");
1✔
280

281
        Date beforeSignature = new Date(signatureDate.getTime() - 1000); // 1 sec before signing date
1✔
282

283
        assertThrows(SOPGPException.NoSignature.class, () -> {
×
284
            ByteArrayAndResult<DecryptionResult> bytesAndResult = assumeSupported(sop::decrypt)
1✔
285
                    .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
1✔
286
                    .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
1✔
287
                    .verifyNotAfter(beforeSignature)
1✔
288
                    .ciphertext(message)
1✔
289
                    .toByteArrayAndResult();
×
290

291
            // Some implementations do not throw NoSignature and instead return an empty list.
292
            if (bytesAndResult.getResult().getVerifications().isEmpty()) {
×
293
                throw new SOPGPException.NoSignature("No verifiable signature found.");
×
294
            }
295
        });
×
296
    }
×
297

298
    @ParameterizedTest
299
    @MethodSource("provideInstances")
300
    public void decryptVerifyNotBeforeTest(SOP sop) throws ParseException {
301
        byte[] message = ("-----BEGIN PGP MESSAGE-----\n" +
1✔
302
                "\n" +
303
                "wV4DR2b2udXyHrYSAQdAwlOwwyxFDJta5+H9abgSj8jum9v7etUc9usdrElESmow\n" +
304
                "2Hka48AFVfOezYh0OFn9R8+DMcpuE+e4nw3XnnX5nKs/j3AC2IW6zRHUkRcF3ZCq\n" +
305
                "0sBNAfjnTYCMjuBmqdcCLzaZT4Hadnpg6neP1UecT/jP14maGfv8nwt0IDGR0Bik\n" +
306
                "0WC/UJLpWyJ/6TgRrA5hNfANVnfiFBzIiThiVBRWPT2StHr2cOAvFxQK4Uk07rK9\n" +
307
                "9aTUak8FpML+QA83U8I3qOk4QbzGVBP+IDJ+AKmvDz+0V+9kUhKp+8vyXsBmo9c3\n" +
308
                "SAXjhFSiPQkU7ORsc6gQHL9+KPOU+W2poPK87H3cmaGiusnXMeLXLIUbkBUJTswd\n" +
309
                "JNrA2yAkTTFP9QabsdcdTGoeYamq1c29kHF3GOTTcEqXw4WWXngcF7Kbcf435kkL\n" +
310
                "4iSJnCaxTPftKUxmiGqMqLef7ICVnq/lz3HrH1VD54s=\n" +
311
                "=Ebi3\n" +
312
                "-----END PGP MESSAGE-----").getBytes(StandardCharsets.UTF_8);
1✔
313
        Date signatureDate = UTCUtil.parseUTCDate("2023-01-13T16:09:32Z");
1✔
314

315
        Date afterSignature = new Date(signatureDate.getTime() + 1000); // 1 sec after signing date
1✔
316

317
        assertThrows(SOPGPException.NoSignature.class, () -> {
×
318
            ByteArrayAndResult<DecryptionResult> bytesAndResult = assumeSupported(sop::decrypt)
1✔
319
                    .withKey(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
1✔
320
                    .verifyWithCert(TestData.ALICE_CERT.getBytes(StandardCharsets.UTF_8))
1✔
321
                    .verifyNotBefore(afterSignature)
1✔
322
                    .ciphertext(message)
1✔
323
                    .toByteArrayAndResult();
×
324

325
            // Some implementations do not throw NoSignature and instead return an empty list.
326
            if (bytesAndResult.getResult().getVerifications().isEmpty()) {
×
327
                throw new SOPGPException.NoSignature("No verifiable signature found.");
×
328
            }
329
        });
×
330
    }
×
331

332
    @ParameterizedTest
333
    @MethodSource("provideInstances")
334
    public void missingArgsTest(SOP sop) {
335
        byte[] message = TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8);
1✔
336

337
        assertThrows(SOPGPException.MissingArg.class, () -> assumeSupported(sop::encrypt)
1✔
338
                .plaintext(message)
1✔
339
                .toByteArrayAndResult()
×
340
                .getBytes());
×
341
    }
×
342

343
    @ParameterizedTest
344
    @MethodSource("provideInstances")
345
    public void passingSecretKeysForPublicKeysFails(SOP sop) {
346
        assertThrows(SOPGPException.BadData.class, () ->
×
347
                assumeSupported(sop::encrypt)
1✔
348
                        .withCert(TestData.ALICE_KEY.getBytes(StandardCharsets.UTF_8))
1✔
349
                        .plaintext(TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8))
1✔
350
                        .toByteArrayAndResult()
×
351
                        .getBytes());
×
352
    }
×
353

354
    @ParameterizedTest
355
    @MethodSource("provideInstances")
356
    public void encryptDecryptWithAllSupportedKeyGenerationProfiles(SOP sop) throws IOException {
357
        List<Profile> profiles = assumeSupported(sop::listProfiles).generateKey();
×
358

359
        List<byte[]> keys = new ArrayList<>();
×
360
        List<byte[]> certs = new ArrayList<>();
×
361
        for (Profile p : profiles) {
×
362
            byte[] k = assumeSupported(sop::generateKey)
×
363
                    .profile(p)
×
364
                    .userId(p.getName())
×
365
                    .generate()
×
366
                    .getBytes();
×
367
            keys.add(k);
×
368

369
            byte[] c = assumeSupported(sop::extractCert)
×
370
                    .key(k)
×
371
                    .getBytes();
×
372
            certs.add(c);
×
373
        }
×
374

375
        byte[] plaintext = "Hello, World!\n".getBytes();
×
376

377
        Encrypt encrypt = assumeSupported(sop::encrypt);
×
378
        for (byte[] c : certs) {
×
379
            encrypt.withCert(c);
×
380
        }
×
381
        for (byte[] k : keys) {
×
382
            encrypt.signWith(k);
×
383
        }
×
384

385
        ByteArrayAndResult<EncryptionResult> encRes = encrypt.plaintext(plaintext)
×
386
                .toByteArrayAndResult();
×
387
        EncryptionResult eResult = encRes.getResult();
×
388
        byte[] ciphertext = encRes.getBytes();
×
389

390
        for (byte[] k : keys) {
×
391
            Decrypt decrypt = assumeSupported(sop::decrypt)
×
392
                    .withKey(k);
×
393
            for (byte[] c : certs) {
×
394
                decrypt.verifyWithCert(c);
×
395
            }
×
396
            ByteArrayAndResult<DecryptionResult> decRes = decrypt.ciphertext(ciphertext)
×
397
                    .toByteArrayAndResult();
×
398
            DecryptionResult dResult = decRes.getResult();
×
399
            byte[] decPlaintext = decRes.getBytes();
×
400
            assertArrayEquals(plaintext, decPlaintext, "Decrypted plaintext does not match original plaintext.");
×
401
            assertEquals(certs.size(), dResult.getVerifications().size());
×
402
        }
×
403
    }
×
404

405
    @ParameterizedTest
406
    @MethodSource("provideInstances")
407
    public void encryptForPurpose(SOP sop) throws IOException {
408
        String CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
1✔
409
                "Comment: 88BF 5516 C226 5B7D 1817  03E6 1FF0 DE1E AF8B 379F\n" +
410
                "\n" +
411
                "mCYEaVxG2BvmBuO3v5cDQQCuGnAIuaeP0frpw7mutcMQwPkGuuAKUMKSBB8bCgA+\n" +
412
                "FqEEiL9VFsImW30YFwPmH/DeHq+LN58FgmlcRtgCngkFlQoJCAsFlgIDAQAEiwkI\n" +
413
                "BwknCQEJAgkDCAECmwEACgkQH/DeHq+LN5/NVHbqH098dr34p9KVQQNLXr8CITqP\n" +
414
                "vLTkijVXyfZg6Lz1krs3EgEvc8nz3evyYj5xJI+Hg1kHb+ctB5myyTyEtge4JgRp\n" +
415
                "XEbYG52SLEi5Biq9vn1pFgrozM2QuCqkwXtOr/0ASs0b3t20wsAnBBgbCgCTFqEE\n" +
416
                "iL9VFsImW30YFwPmH/DeHq+LN58FgmlcRtgCmwJyoAQZGwoAHRahBGp6EAtdr26T\n" +
417
                "x4sGLa+TQ+g71BlpBYJpXEbYAAoJEK+TQ+g71BlpkJ4VPAQeTXN88wXzLloW2WYP\n" +
418
                "5w3w7Js4csGE5OynUupCNwUBcIfC+FBMuUdgqjczw4xKRLbZMgp5YLr8Ve3pG48L\n" +
419
                "AAoJEB/w3h6vizefXrbECKbGBPh+c3+fFG3Au0gzkRMCsZsMaQaRWlQ1E2P/VWlo\n" +
420
                "xy4JF5nCA6bSC+sFl+DTbwpgvdQlIILR9O386EcHuCYEaVxG2Blrm96fHzaN1JmO\n" +
421
                "uhU0OMbiDMBYKOL3Iup+TQWzx897CMJ0BBgbCgAgFqEEiL9VFsImW30YFwPmH/De\n" +
422
                "Hq+LN58FgmlcRtgCmwQACgkQH/DeHq+LN5/wOkjl+MJktOsh+COv4tAhSu2kR0iw\n" +
423
                "rdY4IAEp7jlnZfx0BVMnVURSrZSge3Zw2vbQQe864GA3Y4le4CWFKm2QAwG4JgRp\n" +
424
                "XEbYGUzlbIju0H0KDcLmLXsXp7CCLmkcnSjNAj9WTRW7GCJownQEGBsKACAWoQSI\n" +
425
                "v1UWwiZbfRgXA+Yf8N4er4s3nwWCaVxG2AKbCAAKCRAf8N4er4s3n4+EpHlXYNzD\n" +
426
                "I2OT9NpobaalDbmDMuvIu/81Uoxv+pJLkrMV+WW5be27HrH6w7YTH1TngILr4V2e\n" +
427
                "jSB2HhjClk4YBw==\n" +
428
                "=3S3M\n" +
429
                "-----END PGP PUBLIC KEY BLOCK-----";
430
        String KEY_ONLY_STORAGE = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
1✔
431
                "Comment: 88BF 5516 C226 5B7D 1817  03E6 1FF0 DE1E AF8B 379F\n" +
432
                "\n" +
433
                "lEkEaVxG2BvmBuO3v5cDQQCuGnAIuaeP0frpw7mutcMQwPkGuuAKUAA0eJO2aUrG\n" +
434
                "NwfD+W5mn/EHzossHrQPa0jPzERJ1m7kkA/MwpIEHxsKAD4WoQSIv1UWwiZbfRgX\n" +
435
                "A+Yf8N4er4s3nwWCaVxG2AKeCQWVCgkICwWWAgMBAASLCQgHCScJAQkCCQMIAQKb\n" +
436
                "AQAKCRAf8N4er4s3n81UduofT3x2vfin0pVBA0tevwIhOo+8tOSKNVfJ9mDovPWS\n" +
437
                "uzcSAS9zyfPd6/JiPnEkj4eDWQdv5y0HmbLJPIS2B5xJBGlcRtgbnZIsSLkGKr2+\n" +
438
                "fWkWCujMzZC4KqTBe06v/QBKzRve3bQA80/esWlwPguauRAay+kli/gw/SRhTAK7\n" +
439
                "n1k63W1vkxkPHsLAJwQYGwoAkxahBIi/VRbCJlt9GBcD5h/w3h6vizefBYJpXEbY\n" +
440
                "ApsCcqAEGRsKAB0WoQRqehALXa9uk8eLBi2vk0PoO9QZaQWCaVxG2AAKCRCvk0Po\n" +
441
                "O9QZaZCeFTwEHk1zfPMF8y5aFtlmD+cN8OybOHLBhOTsp1LqQjcFAXCHwvhQTLlH\n" +
442
                "YKo3M8OMSkS22TIKeWC6/FXt6RuPCwAKCRAf8N4er4s3n162xAimxgT4fnN/nxRt\n" +
443
                "wLtIM5ETArGbDGkGkVpUNRNj/1VpaMcuCReZwgOm0gvrBZfg028KYL3UJSCC0fTt\n" +
444
                "/OhHB5xJBGlcRtgZTOVsiO7QfQoNwuYtexensIIuaRydKM0CP1ZNFbsYImgAUDFh\n" +
445
                "CkwFwBaiasW9oHJQd1TALWOtj0TjQo9tEp1zxmQOC8J0BBgbCgAgFqEEiL9VFsIm\n" +
446
                "W30YFwPmH/DeHq+LN58FgmlcRtgCmwgACgkQH/DeHq+LN5+PhKR5V2DcwyNjk/Ta\n" +
447
                "aG2mpQ25gzLryLv/NVKMb/qSS5KzFflluW3tux6x+sO2Ex9U54CC6+Fdno0gdh4Y\n" +
448
                "wpZOGAc=\n" +
449
                "=oK8k\n" +
450
                "-----END PGP PRIVATE KEY BLOCK-----";
451
        String KEY_ONLY_COMMS = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
1✔
452
                "Comment: 88BF 5516 C226 5B7D 1817  03E6 1FF0 DE1E AF8B 379F\n" +
453
                "\n" +
454
                "lEkEaVxG2BvmBuO3v5cDQQCuGnAIuaeP0frpw7mutcMQwPkGuuAKUAA0eJO2aUrG\n" +
455
                "NwfD+W5mn/EHzossHrQPa0jPzERJ1m7kkA/MwpIEHxsKAD4WoQSIv1UWwiZbfRgX\n" +
456
                "A+Yf8N4er4s3nwWCaVxG2AKeCQWVCgkICwWWAgMBAASLCQgHCScJAQkCCQMIAQKb\n" +
457
                "AQAKCRAf8N4er4s3n81UduofT3x2vfin0pVBA0tevwIhOo+8tOSKNVfJ9mDovPWS\n" +
458
                "uzcSAS9zyfPd6/JiPnEkj4eDWQdv5y0HmbLJPIS2B5xJBGlcRtgbnZIsSLkGKr2+\n" +
459
                "fWkWCujMzZC4KqTBe06v/QBKzRve3bQA80/esWlwPguauRAay+kli/gw/SRhTAK7\n" +
460
                "n1k63W1vkxkPHsLAJwQYGwoAkxahBIi/VRbCJlt9GBcD5h/w3h6vizefBYJpXEbY\n" +
461
                "ApsCcqAEGRsKAB0WoQRqehALXa9uk8eLBi2vk0PoO9QZaQWCaVxG2AAKCRCvk0Po\n" +
462
                "O9QZaZCeFTwEHk1zfPMF8y5aFtlmD+cN8OybOHLBhOTsp1LqQjcFAXCHwvhQTLlH\n" +
463
                "YKo3M8OMSkS22TIKeWC6/FXt6RuPCwAKCRAf8N4er4s3n162xAimxgT4fnN/nxRt\n" +
464
                "wLtIM5ETArGbDGkGkVpUNRNj/1VpaMcuCReZwgOm0gvrBZfg028KYL3UJSCC0fTt\n" +
465
                "/OhHB5xJBGlcRtgZa5venx82jdSZjroVNDjG4gzAWCji9yLqfk0Fs8fPewgAILUp\n" +
466
                "R5Ihy+ooSi/6ZnicHsld84qTXLpmeKZMVYhqDm4Ov8J0BBgbCgAgFqEEiL9VFsIm\n" +
467
                "W30YFwPmH/DeHq+LN58FgmlcRtgCmwQACgkQH/DeHq+LN5/wOkjl+MJktOsh+COv\n" +
468
                "4tAhSu2kR0iwrdY4IAEp7jlnZfx0BVMnVURSrZSge3Zw2vbQQe864GA3Y4le4CWF\n" +
469
                "Km2QAwE=\n" +
470
                "=6hyI\n" +
471
                "-----END PGP PRIVATE KEY BLOCK-----";
472
        System.out.println(CERT);
1✔
473

474
        // Encrypt message only for the storage encryption subkey
475
        byte[] forStorage = sop.encrypt()
1✔
476
                .encryptFor(EncryptFor.storage)
1✔
477
                .withCert(CERT.getBytes(StandardCharsets.UTF_8))
1✔
478
                .plaintext(TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8))
1✔
479
                .toByteArrayAndResult()
×
480
                .getBytes();
×
481

482
        // Storage enc key can decrypt
483
        assertArrayEquals(
×
484
                TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8),
×
485
                sop.decrypt()
×
486
                        .withKey(KEY_ONLY_STORAGE.getBytes(StandardCharsets.UTF_8))
×
487
                        .ciphertext(forStorage)
×
488
                        .toByteArrayAndResult()
×
489
                        .getBytes());
×
490
        // Comms only subkey cannot decrypt
491
        assertThrows(SOPGPException.CannotDecrypt.class, () -> sop.decrypt()
×
492
                .withKey(KEY_ONLY_COMMS.getBytes(StandardCharsets.UTF_8))
×
NEW
493
                .ciphertext(forStorage)
×
NEW
494
                .toByteArrayAndResult()
×
NEW
495
                .getBytes());
×
496

497
        // Encrypt message only for the comms encryption subkey
498
        byte[] forComms = sop.encrypt()
×
499
                .encryptFor(EncryptFor.communications)
×
500
                .withCert(CERT.getBytes(StandardCharsets.UTF_8))
×
501
                .plaintext(TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8))
×
502
                .toByteArrayAndResult()
×
503
                .getBytes();
×
504

505
        // Comms enc key can decrypt
506
        assertArrayEquals(
×
507
                TestData.PLAINTEXT.getBytes(StandardCharsets.UTF_8),
×
508
                sop.decrypt()
×
509
                        .withKey(KEY_ONLY_COMMS.getBytes(StandardCharsets.UTF_8))
×
510
                        .ciphertext(forComms)
×
511
                        .toByteArrayAndResult()
×
512
                        .getBytes());
×
513
        // Storage only subkey cannot decrypt
514
        assertThrows(SOPGPException.CannotDecrypt.class, () -> sop.decrypt()
×
515
                .withKey(KEY_ONLY_STORAGE.getBytes(StandardCharsets.UTF_8))
×
NEW
516
                .ciphertext(forComms)
×
NEW
517
                .toByteArrayAndResult()
×
NEW
518
                .getBytes());
×
UNCOV
519
    }
×
520
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc