From 0c4060774e8310bfec242542604b35b2b3c55fa1 Mon Sep 17 00:00:00 2001 From: Leo Galambos Date: Wed, 17 Sep 2025 00:57:41 +0200 Subject: [PATCH] fix: comments improved Signed-off-by: Leo Galambos --- .../test/java/demo/CombinedDeliveryTest.java | 4 +- .../src/test/java/demo/PostQuantumTest.java | 46 ++++++++++--- .../src/test/java/demo/SigningAesTest.java | 66 ++++++++++++------- 3 files changed, 82 insertions(+), 34 deletions(-) diff --git a/samples/src/test/java/demo/CombinedDeliveryTest.java b/samples/src/test/java/demo/CombinedDeliveryTest.java index 3b6b1a5..7798a5b 100644 --- a/samples/src/test/java/demo/CombinedDeliveryTest.java +++ b/samples/src/test/java/demo/CombinedDeliveryTest.java @@ -130,8 +130,8 @@ class CombinedDeliveryTest { // Password (via KDF) .addPasswordRecipient(password, /* iterations */ 200_000, /* saltLen */ 16, /* kekBytes */ 32) // and some decoys - .addRecipient(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy1rsa.getPublic())) - .addRecipient(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy2rsa.getPublic())); + .addRecipientDecoy(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy1rsa.getPublic())) + .addRecipientDecoy(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy2rsa.getPublic())); // shuffle all the recipients multi.shuffle(); diff --git a/samples/src/test/java/demo/PostQuantumTest.java b/samples/src/test/java/demo/PostQuantumTest.java index 509f247..5447aaf 100644 --- a/samples/src/test/java/demo/PostQuantumTest.java +++ b/samples/src/test/java/demo/PostQuantumTest.java @@ -79,28 +79,54 @@ class PostQuantumTest { @Test void pqcSdkLevelAPI() throws GeneralSecurityException, IOException { - // Sample message to encrypt + // Create a random sample message to be encrypted byte[] msg = randomBytes(100); - + // Generate a post-quantum key pair (Kyber, here wrapped as ML-KEM) KeyPair kp = generateKyberKeys(); - DataContent dccb = DataContentChainBuilder.encrypt().add(PlainBytesBuilder.builder().bytes(msg)) - .add(KemDataContentBuilder.builder().kem("ML-KEM").recipientPublic(kp.getPublic()) + DataContent dccb = DataContentChainBuilder.encrypt() + // Start the chain with a plain byte array as input + .add(PlainBytesBuilder.builder().bytes(msg)) + // Add a KEM (Key Encapsulation Mechanism) stage + .add(KemDataContentBuilder.builder() + // Select a KEM-capable algorithm: ML-KEM (Kyber variant) + .kem("ML-KEM") + // Encrypt to this recipient’s public key + .recipientPublic(kp.getPublic()) + // Derive a shared secret and expand/obfuscate it using HKDF-SHA256 .hkdfSha256("KEM-demo".getBytes(StandardCharsets.US_ASCII)) - .withAes(AesDataContentBuilder.builder().modeGcm(128).withHeader())) + // Use the derived secret as a key for AES + .withAes(AesDataContentBuilder.builder() + // Configure AES in GCM mode with a 128-bit authentication tag + .modeGcm(128) + // Store auxiliary parameters (e.g., random IV) inside the stream header + .withHeader())) .build(); byte[] encrypted; try (InputStream encryptedStream = dccb.getStream()) { - // Consume the encrypted data into memory + // Consume the encrypted output stream into memory encrypted = readAll(encryptedStream); } - // Decryption - dccb = DataContentChainBuilder.decrypt().add(PlainBytesBuilder.builder().bytes(encrypted)) - .add(KemDataContentBuilder.builder().kem("ML-KEM").recipientPrivate(kp.getPrivate()) + // Now decrypt the message + dccb = DataContentChainBuilder.decrypt() + // Start with the encrypted byte array as input + .add(PlainBytesBuilder.builder().bytes(encrypted)) + // Add the KEM stage again, matching the encryption parameters + .add(KemDataContentBuilder.builder() + // Use the same KEM algorithm that was used for encryption + .kem("ML-KEM") + // Provide the recipient’s private key for decapsulation + .recipientPrivate(kp.getPrivate()) + // Re-derive the shared secret with the same HKDF-SHA256 label .hkdfSha256("KEM-demo".getBytes(StandardCharsets.US_ASCII)) - .withAes(AesDataContentBuilder.builder().modeGcm(128).withHeader())) + // Use the secret to unlock AES payload decryption + .withAes(AesDataContentBuilder.builder() + // AES in GCM mode with a 128-bit tag, consistent with encryption + .modeGcm(128) + // Read auxiliary parameters (IV, etc.) back from the header + .withHeader())) .build(); byte[] decrypted; diff --git a/samples/src/test/java/demo/SigningAesTest.java b/samples/src/test/java/demo/SigningAesTest.java index 7daacb1..a289829 100644 --- a/samples/src/test/java/demo/SigningAesTest.java +++ b/samples/src/test/java/demo/SigningAesTest.java @@ -96,27 +96,35 @@ class SigningAesTest { void aesRoundStESdkLevelAPI() throws GeneralSecurityException, IOException { LOG.info("aesRoundSmarterSdkLevelAPI - Sign then Encrypt"); - // Sample message to encrypt + // Create a random sample message to be encrypted byte[] msg = randomBytes(100); - + // Configure AES in GCM mode with a 128-bit authentication tag. A fresh 256-bit + // AES key will be generated automatically, and runtime parameters (IV, AAD) + // will be written into the header. AesDataContentBuilder aesBuilder = AesDataContentBuilder.builder().generateKey(256).modeGcm(128).withHeader(); - // RSA-4096 keys (use registry for convenience) + // Generate RSA-4096 key pair (retrieved via algorithm registry for convenience) KeyPair rsa = generateRsaKeys(); - // Tag engines (SHA-256, saltLen=32) + // Configure PSS signature parameters: SHA-256 hash, salt length = 32 bytes RsaSigSpec pss = RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32); + // Create signing engine (RSA-PSS with private key) TagEngine tagEnc = TagEngineBuilder.rsaSign(rsa.getPrivate(), pss).get(); + // Create verification engine (RSA-PSS with public key) TagEngine tagDec = TagEngineBuilder.rsaVerify(rsa.getPublic(), pss).get(); - // The builder stores generated IV and AAD inside the stream header - DataContent dccb = DataContentChainBuilder.encrypt().add(PlainBytesBuilder.builder().bytes(msg)) - // sign the data + // Build the encryption pipeline + DataContent dccb = DataContentChainBuilder.encrypt() + // Input: raw message bytes + .add(PlainBytesBuilder.builder().bytes(msg)) + // Sign the data with RSA-PSS (trailer attached to the stream) .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192)) - // and then encrypt + // Encrypt everything using AES-GCM (IV + AAD stored in the header) .add(aesBuilder).build(); + // Retrieve and log the generated AES key in hex (for demonstration only) SecretKey key = aesBuilder.generatedKey(); + // In production, keys should never be logged or exposed LOG.log(Level.INFO, "SDK-smart: AES256 key generated {0}", Strings.toShortHexString(key.getEncoded())); byte[] encrypted; @@ -125,10 +133,15 @@ class SigningAesTest { encrypted = readAll(encryptedStream); } - dccb = DataContentChainBuilder.decrypt().add(PlainBytesBuilder.builder().bytes(encrypted)) - // Use the same AES key for decryption; IV and AAD are restored from the header + // Build the decryption pipeline + dccb = DataContentChainBuilder.decrypt() + // Input: encrypted byte array + .add(PlainBytesBuilder.builder().bytes(encrypted)) + // AES-GCM decryption using the same key; IV and AAD are restored automatically + // from the header .add(AesDataContentBuilder.builder().importKeyRaw(key.getEncoded()).modeGcm(128).withHeader()) - // the decrypted stream must be verified + // Verify the RSA-PSS signature trailer at the end of the stream (configured to + // throw on mismatch) .add(new TagTrailerDataContentBuilder<>(tagDec).bufferSize(8192).throwOnMismatch()) // Build the pipeline .build(); @@ -146,26 +159,28 @@ class SigningAesTest { void aesRoundEtSSdkLevelAPI() throws GeneralSecurityException, IOException { LOG.info("aesRoundSmarterSdkLevelAPI - Encrypt then Sign"); - // Sample message to encrypt + // Create a random sample message to be encrypted byte[] msg = randomBytes(100); AesDataContentBuilder aesBuilder = AesDataContentBuilder.builder().generateKey(256).modeGcm(128).withHeader(); - // RSA-4096 keys (use registry for convenience) + // Generate RSA-4096 key pair (retrieved via algorithm registry for convenience) KeyPair rsa = generateRsaKeys(); - // Tag engines (SHA-256, saltLen=32) + // Configure PSS signature parameters: SHA-256 hash, salt length = 32 bytes RsaSigSpec pss = RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32); TagEngine tagEnc = TagEngineBuilder.rsaSign(rsa.getPrivate(), pss).get(); TagEngine tagDec = TagEngineBuilder.rsaVerify(rsa.getPublic(), pss).get(); - // The builder stores generated IV and AAD inside the stream header - DataContent dccb = DataContentChainBuilder.encrypt().add(PlainBytesBuilder.builder().bytes(msg)) - // encrypt + // Build the encryption pipeline + DataContent dccb = DataContentChainBuilder.encrypt() + // Input: raw message bytes + .add(PlainBytesBuilder.builder().bytes(msg)) + // Encrypt everything using AES-GCM (IV + AAD stored in the header) .add(aesBuilder) - // and then sign + // Sign the encrypted data with RSA-PSS (trailer attached to the stream) .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192)) - // + // Build the pipeline .build(); SecretKey key = aesBuilder.generatedKey(); @@ -177,10 +192,17 @@ class SigningAesTest { encrypted = readAll(encryptedStream); } - dccb = DataContentChainBuilder.decrypt().add(PlainBytesBuilder.builder().bytes(encrypted)) - // the stream must be verified, but encryption still runs as data flows through + // Build the decryption pipeline + dccb = DataContentChainBuilder.decrypt() + // Input: encrypted byte array + .add(PlainBytesBuilder.builder().bytes(encrypted)) + // Verify the RSA-PSS signature trailer at the end of the stream. + // The pipeline is configured to throw an exception if verification fails. + // Verification happens while the data continues flowing into the decryptor, + // so the consumer can fully process plaintext only if the signature is valid. .add(new TagTrailerDataContentBuilder<>(tagDec).bufferSize(8192).throwOnMismatch()) - // Use the same AES key for decryption; IV and AAD are restored from the header + // AES-GCM decryption using the same key; IV and AAD are restored automatically + // from the header .add(AesDataContentBuilder.builder().importKeyRaw(key.getEncoded()).modeGcm(128).withHeader()) // Build the pipeline .build();