Signed-off-by: Leo Galambos <lg@hq.egothor.org>
This commit is contained in:
@@ -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();
|
||||||
|
|||||||
@@ -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 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))
|
.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 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))
|
.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;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
Reference in New Issue
Block a user