fix: comments improved

Signed-off-by: Leo Galambos <lg@hq.egothor.org>
This commit is contained in:
2025-09-17 00:57:41 +02:00
parent f3ab7476f2
commit 1772a45b17
3 changed files with 82 additions and 34 deletions

View File

@@ -130,8 +130,8 @@ class CombinedDeliveryTest {
// Password (via KDF) // Password (via KDF)
.addPasswordRecipient(password, /* iterations */ 200_000, /* saltLen */ 16, /* kekBytes */ 32) .addPasswordRecipient(password, /* iterations */ 200_000, /* saltLen */ 16, /* kekBytes */ 32)
// and some decoys // and some decoys
.addRecipient(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy1rsa.getPublic())) .addRecipientDecoy(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy1rsa.getPublic()))
.addRecipient(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy2rsa.getPublic())); .addRecipientDecoy(CryptoAlgorithms.create("RSA", KeyUsage.ENCRYPT, decoy2rsa.getPublic()));
// shuffle all the recipients // shuffle all the recipients
multi.shuffle(); multi.shuffle();

View File

@@ -79,28 +79,54 @@ class PostQuantumTest {
@Test @Test
void pqcSdkLevelAPI() throws GeneralSecurityException, IOException { void pqcSdkLevelAPI() throws GeneralSecurityException, IOException {
// Sample message to encrypt // Create a random sample message to be encrypted
byte[] msg = randomBytes(100); byte[] msg = randomBytes(100);
// Generate a post-quantum key pair (Kyber, here wrapped as ML-KEM)
KeyPair kp = generateKyberKeys(); KeyPair kp = generateKyberKeys();
DataContent dccb = DataContentChainBuilder.encrypt().add(PlainBytesBuilder.builder().bytes(msg)) DataContent dccb = DataContentChainBuilder.encrypt()
.add(KemDataContentBuilder.builder().kem("ML-KEM").recipientPublic(kp.getPublic()) // 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 recipients public key
.recipientPublic(kp.getPublic())
// Derive a shared secret and expand/obfuscate it using HKDF-SHA256
.hkdfSha256("KEM-demo".getBytes(StandardCharsets.US_ASCII)) .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(); .build();
byte[] encrypted; byte[] encrypted;
try (InputStream encryptedStream = dccb.getStream()) { try (InputStream encryptedStream = dccb.getStream()) {
// Consume the encrypted data into memory // Consume the encrypted output stream into memory
encrypted = readAll(encryptedStream); encrypted = readAll(encryptedStream);
} }
// Decryption // Now decrypt the message
dccb = DataContentChainBuilder.decrypt().add(PlainBytesBuilder.builder().bytes(encrypted)) dccb = DataContentChainBuilder.decrypt()
.add(KemDataContentBuilder.builder().kem("ML-KEM").recipientPrivate(kp.getPrivate()) // 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 recipients 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)) .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(); .build();
byte[] decrypted; byte[] decrypted;

View File

@@ -96,27 +96,35 @@ class SigningAesTest {
void aesRoundStESdkLevelAPI() throws GeneralSecurityException, IOException { void aesRoundStESdkLevelAPI() throws GeneralSecurityException, IOException {
LOG.info("aesRoundSmarterSdkLevelAPI - Sign then Encrypt"); LOG.info("aesRoundSmarterSdkLevelAPI - Sign then Encrypt");
// Sample message to encrypt // Create a random sample message to be encrypted
byte[] msg = randomBytes(100); 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(); 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(); 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); RsaSigSpec pss = RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32);
// Create signing engine (RSA-PSS with private key)
TagEngine<Signature> tagEnc = TagEngineBuilder.rsaSign(rsa.getPrivate(), pss).get(); TagEngine<Signature> tagEnc = TagEngineBuilder.rsaSign(rsa.getPrivate(), pss).get();
// Create verification engine (RSA-PSS with public key)
TagEngine<Signature> tagDec = TagEngineBuilder.rsaVerify(rsa.getPublic(), pss).get(); TagEngine<Signature> tagDec = TagEngineBuilder.rsaVerify(rsa.getPublic(), pss).get();
// The builder stores generated IV and AAD inside the stream header // Build the encryption pipeline
DataContent dccb = DataContentChainBuilder.encrypt().add(PlainBytesBuilder.builder().bytes(msg)) DataContent dccb = DataContentChainBuilder.encrypt()
// sign the data // 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)) .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192))
// and then encrypt // Encrypt everything using AES-GCM (IV + AAD stored in the header)
.add(aesBuilder).build(); .add(aesBuilder).build();
// Retrieve and log the generated AES key in hex (for demonstration only)
SecretKey key = aesBuilder.generatedKey(); 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())); LOG.log(Level.INFO, "SDK-smart: AES256 key generated {0}", Strings.toShortHexString(key.getEncoded()));
byte[] encrypted; byte[] encrypted;
@@ -125,10 +133,15 @@ class SigningAesTest {
encrypted = readAll(encryptedStream); encrypted = readAll(encryptedStream);
} }
dccb = DataContentChainBuilder.decrypt().add(PlainBytesBuilder.builder().bytes(encrypted)) // Build the decryption pipeline
// Use the same AES key for decryption; IV and AAD are restored from the header 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()) .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()) .add(new TagTrailerDataContentBuilder<>(tagDec).bufferSize(8192).throwOnMismatch())
// Build the pipeline // Build the pipeline
.build(); .build();
@@ -146,26 +159,28 @@ class SigningAesTest {
void aesRoundEtSSdkLevelAPI() throws GeneralSecurityException, IOException { void aesRoundEtSSdkLevelAPI() throws GeneralSecurityException, IOException {
LOG.info("aesRoundSmarterSdkLevelAPI - Encrypt then Sign"); LOG.info("aesRoundSmarterSdkLevelAPI - Encrypt then Sign");
// Sample message to encrypt // Create a random sample message to be encrypted
byte[] msg = randomBytes(100); byte[] msg = randomBytes(100);
AesDataContentBuilder aesBuilder = AesDataContentBuilder.builder().generateKey(256).modeGcm(128).withHeader(); 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(); 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); RsaSigSpec pss = RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32);
TagEngine<Signature> tagEnc = TagEngineBuilder.rsaSign(rsa.getPrivate(), pss).get(); TagEngine<Signature> tagEnc = TagEngineBuilder.rsaSign(rsa.getPrivate(), pss).get();
TagEngine<Signature> tagDec = TagEngineBuilder.rsaVerify(rsa.getPublic(), pss).get(); TagEngine<Signature> tagDec = TagEngineBuilder.rsaVerify(rsa.getPublic(), pss).get();
// The builder stores generated IV and AAD inside the stream header // Build the encryption pipeline
DataContent dccb = DataContentChainBuilder.encrypt().add(PlainBytesBuilder.builder().bytes(msg)) DataContent dccb = DataContentChainBuilder.encrypt()
// encrypt // Input: raw message bytes
.add(PlainBytesBuilder.builder().bytes(msg))
// Encrypt everything using AES-GCM (IV + AAD stored in the header)
.add(aesBuilder) .add(aesBuilder)
// and then sign // Sign the encrypted data with RSA-PSS (trailer attached to the stream)
.add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192)) .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192))
// // Build the pipeline
.build(); .build();
SecretKey key = aesBuilder.generatedKey(); SecretKey key = aesBuilder.generatedKey();
@@ -177,10 +192,17 @@ class SigningAesTest {
encrypted = readAll(encryptedStream); encrypted = readAll(encryptedStream);
} }
dccb = DataContentChainBuilder.decrypt().add(PlainBytesBuilder.builder().bytes(encrypted)) // Build the decryption pipeline
// the stream must be verified, but encryption still runs as data flows through 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()) .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()) .add(AesDataContentBuilder.builder().importKeyRaw(key.getEncoded()).modeGcm(128).withHeader())
// Build the pipeline // Build the pipeline
.build(); .build();