From dedd16f584c6c6d2811fa667097cb83a11fbba58 Mon Sep 17 00:00:00 2001
From: Leo Galambos
Date: Thu, 30 Jul 2026 20:28:43 +0200
Subject: [PATCH] chore(text): source code format
---
app/src/main/java/zeroecho/Guard.java | 58 +-
app/src/main/java/zeroecho/Kem.java | 201 ++++---
.../java/zeroecho/KeyStoreManagement.java | 25 +-
.../main/java/zeroecho/KeyringUnlocks.java | 3 +-
app/src/main/java/zeroecho/Tag.java | 22 +-
app/src/test/java/zeroecho/GuardTest.java | 28 +-
app/src/test/java/zeroecho/KemTest.java | 11 +-
.../java/zeroecho/KeyStoreManagementTest.java | 11 +-
app/src/test/java/zeroecho/TagTest.java | 31 +-
.../java/zeroecho/TestKeyringUnlocks.java | 3 +-
.../covert/jpeg/JpegExifIntegrationTest.java | 23 +-
.../main/java/zeroecho/core/Capability.java | 26 +-
.../java/zeroecho/core/CryptoAlgorithm.java | 115 ++--
.../java/zeroecho/core/CryptoAlgorithms.java | 6 +-
.../java/zeroecho/core/CryptoCatalog.java | 56 +-
.../java/zeroecho/core/KeyOperationInfo.java | 18 +-
.../core/alg/AbstractCryptoAlgorithm.java | 4 +-
.../core/alg/aes/AesCipherContext.java | 12 +-
.../core/alg/aes/AesKeyImportSpec.java | 4 +-
.../chacha/AbstractChaChaCipherContext.java | 9 +-
.../core/alg/chacha/ChaChaAlgorithm.java | 1 +
.../core/alg/chacha/package-info.java | 8 +-
.../agreement/GenericJcaAgreementContext.java | 6 +-
.../core/alg/common/eddsa/package-info.java | 6 +-
.../common/sig/SignatureInteropProfile.java | 3 +-
.../core/alg/common/sig/package-info.java | 6 +-
.../core/alg/digest/Sha2Sha3Algorithm.java | 4 +-
.../zeroecho/core/alg/ecdh/EcdhAlgorithm.java | 3 +-
.../core/alg/ecdh/EcdhKeyGenBuilder.java | 4 +-
.../core/alg/ecdsa/EcdsaAlgorithm.java | 7 +-
.../core/alg/ecdsa/EcdsaKeyGenBuilder.java | 14 +-
.../alg/ecdsa/EcdsaPrivateKeyBuilder.java | 8 +-
.../core/alg/ecdsa/EcdsaPublicKeyBuilder.java | 8 +-
.../alg/ed25519/Ed25519KeyGenBuilder.java | 4 +-
.../alg/ed25519/Ed25519PrivateKeyBuilder.java | 4 +-
.../alg/ed25519/Ed25519PublicKeyBuilder.java | 4 +-
.../alg/ed448/Ed448PrivateKeyBuilder.java | 3 +-
.../core/alg/ed448/Ed448PublicKeyBuilder.java | 3 +-
.../core/alg/kyber/KyberKeyGenSpec.java | 3 +-
.../core/alg/kyber/KyberPrivateKeySpec.java | 6 +-
.../zeroecho/core/alg/rsa/BlockGeometry.java | 3 +-
.../core/alg/saber/SaberKeyGenSpec.java | 3 +-
.../sphincsplus/SphincsPlusKeyGenBuilder.java | 10 +-
.../SphincsPlusPrivateKeyBuilder.java | 6 +-
.../SphincsPlusPrivateKeySpec.java | 3 +-
.../SphincsPlusPublicKeyBuilder.java | 6 +-
.../core/alg/xdh/XdhKeyGenBuilder.java | 3 +-
.../zeroecho/core/audit/AuditListeners.java | 10 +-
.../java/zeroecho/core/audit/AuditMode.java | 6 +-
.../zeroecho/core/audit/AuditedContexts.java | 13 +-
.../core/audit/JulAuditListenerStd.java | 9 +-
.../core/err/UnsupportedRoleException.java | 6 +-
.../io/AbstractChunkTransformInputStream.java | 17 +-
.../io/CipherTransformInputStreamBuilder.java | 12 +-
.../zeroecho/core/io/SmartBlockStream.java | 1 +
.../core/io/SmartPaddedBlockStream.java | 1 +
.../java/zeroecho/core/io/package-info.java | 8 +-
.../java/zeroecho/core/marshal/PairSeq.java | 11 +-
.../zeroecho/core/marshal/PairSeqCodec.java | 17 +-
.../zeroecho/core/spec/AlgorithmKeySpec.java | 1 -
.../core/spi/AsymmetricKeyPairGenerator.java | 3 +-
.../zeroecho/core/spi/ContextFactoryKS.java | 8 +-
.../core/spi/KeyringUnlockProvider.java | 6 +-
.../zeroecho/core/spi/PrivateKeyImporter.java | 4 +-
.../java/zeroecho/core/spi/package-info.java | 18 +-
.../core/storage/KeyringException.java | 20 +-
.../core/storage/KeyringFileOperations.java | 18 +-
.../core/storage/KeyringImportRegistry.java | 193 +++----
.../storage/KeyringNonceReservationKdf.java | 15 +-
.../core/storage/KeyringPassword.java | 14 +-
.../core/storage/KeyringProtection.java | 7 +-
.../core/storage/KeyringRandomBytes.java | 6 +-
.../zeroecho/core/storage/KeyringStore.java | 492 ++++++++---------
.../zeroecho/core/storage/package-info.java | 18 +-
.../zeroecho/core/tag/TagEngineBuilder.java | 27 +-
.../main/java/zeroecho/sdk/KeyBuilders.java | 80 +--
.../main/java/zeroecho/sdk/Pbkdf2Limits.java | 11 +-
.../java/zeroecho/sdk/ZeroEchoSession.java | 38 +-
.../sdk/builders/HybridKexBuilder.java | 6 +-
.../SignatureTrailerDataContentBuilder.java | 17 +-
.../alg/ChaChaDataContentBuilder.java | 6 +-
.../alg/DigestDataContentBuilder.java | 1 +
.../alg/ElgamalEncDataContentBuilder.java | 6 +-
.../builders/alg/HmacDataContentBuilder.java | 4 +-
.../alg/RsaEncDataContentBuilder.java | 6 +-
.../alg/RsaSigDataContentBuilder.java | 1 +
.../zeroecho/sdk/builders/package-info.java | 3 +-
.../sdk/content/builtin/SecretPassword.java | 4 +-
.../java/zeroecho/sdk/guard/Decryptor.java | 16 +-
.../java/zeroecho/sdk/guard/Encryptor.java | 6 +-
.../zeroecho/sdk/guard/KemCtxRecipient.java | 6 +-
.../zeroecho/sdk/guard/KemKeyDerivation.java | 6 +-
.../sdk/guard/MultiRecipientContent.java | 16 +-
.../MultiRecipientDataSourceBuilder.java | 26 +-
.../zeroecho/sdk/guard/PasswordOpener.java | 1 +
.../zeroecho/sdk/guard/PasswordRecipient.java | 4 +-
.../zeroecho/sdk/guard/RecipientKekSizes.java | 6 +-
.../zeroecho/sdk/guard/UnlockMaterial.java | 12 +-
.../java/zeroecho/sdk/guard/package-info.java | 4 +-
.../sdk/hybrid/derived/HybridDerived.java | 12 +-
.../sdk/hybrid/kex/HybridKexContext.java | 13 +-
.../sdk/hybrid/kex/HybridKexContexts.java | 30 +-
.../sdk/hybrid/kex/HybridKexExporter.java | 6 +-
.../signature/HybridSignatureContext.java | 6 +-
.../signature/HybridSignatureContexts.java | 3 +-
.../main/java/zeroecho/sdk/util/Password.java | 1 -
.../core/CapabilityValueSemanticsTest.java | 8 +-
.../zeroecho/core/CatalogContractTest.java | 13 +-
.../core/CryptoAlgorithmsAuditWrapTest.java | 8 +-
.../zeroecho/core/CryptoArchitectureTest.java | 23 +-
.../core/SecretSpecLifecycleTest.java | 32 +-
.../zeroecho/core/TargetArchitectureTest.java | 32 +-
.../ZeroEchoSessionWrapIntegrationTest.java | 74 ++-
.../alg/aes/AesDecryptionSecurityTest.java | 46 +-
.../core/alg/aes/AesRandomSupportTest.java | 3 +-
.../core/alg/chacha/ChaChaLargeDataTest.java | 48 +-
.../alg/chacha/ChaChaNonceLifecycleTest.java | 8 +-
.../AgreementAlgorithmsRoundTripTest.java | 20 +-
.../core/alg/ecdsa/EcdsaLargeDataTest.java | 9 +-
.../alg/ed25519/Ed25519LargeDataTest.java | 9 +-
.../core/alg/ed448/Ed448LargeDataTest.java | 9 +-
.../alg/elgamal/ElgamalLargeDataTest.java | 24 +-
.../core/alg/hmac/HmacLargeDataTest.java | 3 +-
.../core/alg/mldsa/MldsaLargeDataTest.java | 9 +-
.../core/alg/rsa/BlockGeometryTest.java | 9 +-
.../core/alg/rsa/RsaLargeDataTest.java | 18 +-
.../core/alg/slhdsa/SlhDsaLargeDataTest.java | 9 +-
.../audit/AuditedContextsRegressionTest.java | 23 +-
.../JulAuditListenerStdSecurityTest.java | 4 +-
...CipherTransformInputStreamBuilderTest.java | 16 +-
.../zeroecho/core/marshal/PairSeqTest.java | 7 +-
.../storage/KeyringAlgorithmCoverageTest.java | 149 ++----
.../storage/KeyringAtomicPersistenceTest.java | 130 ++---
.../KeyringCryptographicFormatTest.java | 388 ++++++--------
.../KeyringFilesystemSecurityTest.java | 104 ++--
.../storage/KeyringImportRegistryTest.java | 76 +--
.../storage/KeyringNonceReservationTest.java | 72 +--
.../core/storage/KeyringStoreTest.java | 76 +--
.../sdk/ZeroEchoSessionDestroyKeyTest.java | 5 +-
.../sdk/builders/HybridKexBuilderTest.java | 212 ++++----
.../TagTrailerDataContentBuilderTest.java | 227 +++++---
.../builders/alg/KemHybridRoundTripTest.java | 34 +-
.../builders/alg/SessionBoundBuilderTest.java | 19 +-
.../sdk/guard/DecryptorCekCleanupTest.java | 7 +-
.../sdk/guard/EncryptorCekAllocationTest.java | 16 +-
.../sdk/guard/KemRecipientLifecycleTest.java | 12 +-
.../sdk/guard/MultiRecipientEnvelopeTest.java | 384 +++++++------
.../sdk/guard/PasswordRecipientTest.java | 33 +-
.../SessionRecipientOpenerContractTest.java | 18 +-
.../sdk/hybrid/derived/HybridDerivedTest.java | 38 +-
.../hybrid/kex/HybridKexFrameCodecTest.java | 14 +-
.../sdk/hybrid/kex/HybridKexTest.java | 36 +-
.../hybrid/signature/HybridSignatureTest.java | 85 ++-
.../java/zeroecho/pki/api/ProfileService.java | 4 +-
.../pki/api/credential/Credential.java | 11 +-
.../EffectiveCredentialStatusResolver.java | 8 +-
.../pki/api/issuance/VerificationPolicy.java | 7 +-
.../pki/api/orch/SigningSubmissionId.java | 25 +-
.../api/profile/ActiveCertificateProfile.java | 5 +-
.../BuiltInCertificateProfileCatalog.java | 64 +--
.../BuiltInCertificateProfileTemplate.java | 15 +-
.../pki/api/profile/CaCertificatePolicy.java | 11 +-
.../pki/api/profile/CertificateProfile.java | 24 +-
.../profile/CertificateProfileDefinition.java | 25 +-
.../CertificateProfileDocumentCodec.java | 226 +++-----
.../api/profile/CertificateProfileRef.java | 14 +-
.../ImportedCertificateProfileVersion.java | 16 +-
.../api/profile/LeafCertificatePolicy.java | 19 +-
.../profile/SubjectAlternativeNamePolicy.java | 30 +-
.../profile/SubjectAlternativeNameRule.java | 19 +-
.../pki/api/profile/SubjectRdnRule.java | 16 +-
.../request/ParsedCertificationRequest.java | 48 +-
.../api/request/SubjectAlternativeName.java | 7 +-
.../pki/api/revocation/RevocationCommand.java | 8 +-
.../pki/api/revocation/RevocationJournal.java | 6 +-
.../api/revocation/RevocationTransition.java | 8 +-
.../pki/impl/ProfileLifecycleFailure.java | 19 +-
.../core/CaCertificateProfileValidator.java | 29 +-
.../zeroecho/pki/impl/core/CaProofGate.java | 10 +-
.../core/CertificateProfileValidator.java | 27 +-
.../impl/core/CredentialProfileBindings.java | 9 +-
.../pki/impl/core/CredentialSnapshots.java | 3 +-
.../pki/impl/core/CredentialTrustAudit.java | 6 +-
.../pki/impl/core/DefaultCaService.java | 188 +++----
.../pki/impl/core/DefaultIssuanceService.java | 53 +-
.../pki/impl/core/DefaultProfileService.java | 47 +-
.../impl/core/DefaultRevocationService.java | 12 +-
.../impl/core/DefaultStatusObjectService.java | 34 +-
.../core/ValidatedCaCertificateRequest.java | 17 +-
.../core/ValidatedCertificateRequest.java | 3 +-
.../pki/impl/core/async/PkiSigningBus.java | 86 ++-
.../ZeroEchoLibSignatureWorkflow.java | 101 ++--
.../ZeroEchoLibSignatureWorkflowProvider.java | 55 +-
.../bc/BcX509CertificationRequestParser.java | 5 +-
.../x509/bc/BcX509CredentialFramework.java | 10 +-
.../bc/BcX509CredentialIssuerBackend.java | 22 +-
.../x509/bc/BcX509ProfileSupport.java | 14 +-
.../x509/bc/BcX509StatusObjectGenerator.java | 5 +-
.../x509/bc/PkiBusContentSigner.java | 3 +-
.../pki/impl/fs/FilesystemPkiStore.java | 147 +++--
.../java/zeroecho/pki/impl/fs/FsCodec.java | 218 +++-----
.../zeroecho/pki/impl/fs/FsOperations.java | 22 +-
.../java/zeroecho/pki/impl/fs/FsPaths.java | 10 +-
.../pki/impl/fs/FsSnapshotExporter.java | 9 +-
.../pki/impl/fs/ValidatedImportedProfile.java | 27 +-
.../zeroecho/pki/impl/fs/package-info.java | 6 +-
.../pki/spi/bootstrap/PkiBootstrap.java | 16 +-
.../pki/spi/crypto/SignatureWorkflow.java | 58 +-
.../spi/crypto/SignatureWorkflowProvider.java | 22 +-
.../SignatureWorkflowRuntimeDependencies.java | 28 +-
.../spi/framework/CredentialFramework.java | 4 +-
.../framework/CredentialIssuerBackend.java | 30 +-
.../zeroecho/pki/spi/framework/CrlEntry.java | 10 +-
.../spi/framework/StatusObjectGenerator.java | 6 +-
.../java/zeroecho/pki/spi/store/PkiStore.java | 18 +-
.../pki/spi/store/SignWorkflowStore.java | 75 ++-
.../BuiltInCertificateProfileCatalogTest.java | 171 +++---
.../BuiltInProfileImportIntegrityTest.java | 16 +-
.../CertificateProfileDocumentCodecTest.java | 413 ++++++--------
.../e2e/CaProfileIssuanceEnforcementTest.java | 363 +++++++------
.../pki/e2e/H7EndEntityAcceptanceE2eTest.java | 354 +++++-------
.../e2e/H7EndEntityCsrRejectionE2eTest.java | 129 +++--
.../java/zeroecho/pki/e2e/PkiCoreE2eTest.java | 77 ++-
.../zeroecho/pki/e2e/PkiProofGateE2eTest.java | 505 +++++++++---------
.../impl/core/DefaultProfileServiceTest.java | 79 ++-
.../core/DefaultRevocationServiceTest.java | 8 +-
.../DefaultStatusObjectServiceCrlTest.java | 136 ++---
.../impl/core/H7ProfileEnforcementTest.java | 111 ++--
...EffectiveCredentialStatusResolverTest.java | 51 +-
.../core/async/PkiSigningBusFailureTest.java | 138 ++---
.../PkiSigningBusOperatorApprovalTest.java | 7 +-
.../zeroecholib/TestKeyringUnlocks.java | 3 +-
.../ZeroEchoLibKeyRefParsingTest.java | 16 +-
...hoLibSignatureWorkflowPersistenceTest.java | 59 +-
...gnatureWorkflowVerifyEncodedEcdsaTest.java | 6 +-
...LibSignatureWorkflowVerifyEncodedTest.java | 6 +-
.../bc/PkiBusContentSignerCleanupTest.java | 5 +-
...WorkflowProofOfPossessionVerifierTest.java | 8 +-
.../fs/FilesystemPkiStoreOwnershipTest.java | 26 +-
.../pki/impl/fs/FilesystemPkiStoreTest.java | 46 +-
.../fs/FilesystemProfileLifecycleTest.java | 78 ++-
.../fs/FilesystemRevocationJournalTest.java | 227 ++++----
.../fs/FilesystemSignWorkflowStoreTest.java | 211 ++++----
.../zeroecho/pki/impl/fs/FsCodecTest.java | 42 +-
.../pki/spi/bootstrap/PkiBootstrapTest.java | 109 ++--
.../pki/spi/framework/CrlEntryTest.java | 14 +-
.../DurableDelayedSignatureWorkflow.java | 4 +-
...ableOperatorApprovalSignatureWorkflow.java | 4 +-
.../pki/testkit/H7ProfileDocuments.java | 119 ++---
.../testkit/InMemorySignatureWorkflow.java | 8 +-
.../OperatorApprovalSignatureWorkflow.java | 3 +-
.../pki/testkit/PkiSigningBusWorker.java | 6 +-
.../zeroecho/pki/testkit/PkiTestRuntime.java | 22 +-
.../pki/util/async/DurableAsyncBusTest.java | 78 ++-
samples/src/test/java/demo/AesTest.java | 9 +-
.../test/java/demo/AgreementVariantsTest.java | 6 +-
.../test/java/demo/CombinedDeliveryTest.java | 9 +-
.../java/demo/HybridDerivedAesDemoTest.java | 9 +-
.../src/test/java/demo/HybridKexDemoTest.java | 25 +-
.../test/java/demo/HybridSigningAesTest.java | 36 +-
.../src/test/java/demo/PostQuantumTest.java | 3 +-
.../src/test/java/demo/SigningAesTest.java | 27 +-
262 files changed, 4867 insertions(+), 5717 deletions(-)
diff --git a/app/src/main/java/zeroecho/Guard.java b/app/src/main/java/zeroecho/Guard.java
index d036ca9..7c2ad60 100644
--- a/app/src/main/java/zeroecho/Guard.java
+++ b/app/src/main/java/zeroecho/Guard.java
@@ -138,18 +138,16 @@ public final class Guard {
/**
* Executes Guard with an explicit keyring unlock source.
*
- * @param args command arguments
- * @param options dispatcher options
+ * @param args command arguments
+ * @param options dispatcher options
* @param keyringUnlockProvider destroyable-password provider
* @return process exit code
- * @throws ParseException if parsing fails
- * @throws IOException if I/O fails
+ * @throws ParseException if parsing fails
+ * @throws IOException if I/O fails
* @throws GeneralSecurityException if cryptographic processing fails
*/
- @SuppressWarnings({ "PMD.NcssCount", "PMD.CognitiveComplexity",
- "PMD.CyclomaticComplexity", "PMD.NPathComplexity" })
- public static int main(final String[] args, final Options options,
- KeyringUnlockProvider keyringUnlockProvider)
+ @SuppressWarnings({ "PMD.NcssCount", "PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.NPathComplexity" })
+ public static int main(final String[] args, final Options options, KeyringUnlockProvider keyringUnlockProvider)
throws ParseException, IOException, GeneralSecurityException {
// ---- operation selection
final Option OPT_ENCRYPT = Option.builder("e").longOpt("encrypt").hasArg().argName("in-file")
@@ -206,8 +204,7 @@ public final class Guard {
.desc("Recipient KEK length: exactly 16 or 32 bytes (default 32)").get();
final Option OPT_PBKDF2_MAX = Option.builder().longOpt("pbkdf2-max").hasArg().argName("iterations")
.desc("Operational PBKDF2 ceiling; required for password operations").get();
- final Option OPT_PBKDF2_HARD_MAX = Option.builder().longOpt("pbkdf2-hard-max").hasArg()
- .argName("iterations")
+ final Option OPT_PBKDF2_HARD_MAX = Option.builder().longOpt("pbkdf2-hard-max").hasArg().argName("iterations")
.desc("Absolute decoded PBKDF2 safety ceiling; required for password operations").get();
// ---- decoys (all types)
@@ -260,8 +257,7 @@ public final class Guard {
final CommandLine cmd = parser.parse(options, args);
final boolean passwordOperation = cmd.hasOption(OPT_TO_PSW) || cmd.hasOption(OPT_DECOY_PSW)
|| cmd.hasOption(OPT_DECOY_PSW_RAND) || cmd.hasOption(OPT_PASSWORD);
- final ZeroEchoSession session = createSession(cmd, OPT_PBKDF2_MAX, OPT_PBKDF2_HARD_MAX,
- passwordOperation);
+ final ZeroEchoSession session = createSession(cmd, OPT_PBKDF2_MAX, OPT_PBKDF2_HARD_MAX, passwordOperation);
final boolean encrypt = cmd.hasOption(OPT_ENCRYPT);
final Path inPath = Paths.get(cmd.getOptionValue(encrypt ? OPT_ENCRYPT : OPT_DECRYPT));
@@ -359,8 +355,7 @@ public final class Guard {
// envelope builder (new API)
final MultiRecipientDataSourceBuilder env = MultiRecipientDataSourceBuilder.builder(session)
- .payloadKeyBytes(cekBytes)
- .headerLimits(maxRecipients, maxEntryLen);
+ .payloadKeyBytes(cekBytes).headerLimits(maxRecipients, maxEntryLen);
UnlockMaterial borrowedUnlockMaterial = null;
try (env) {
if (aes != null) {
@@ -374,11 +369,10 @@ public final class Guard {
if (encrypt) {
final int iter = Integer.parseInt(cmd.getOptionValue(OPT_PSW_ITER, "200000"));
final int saltLen = Integer.parseInt(cmd.getOptionValue(OPT_PSW_SALT, "16"));
- final int kekLen = RecipientKekSizes.requireSupported(
- Integer.parseInt(cmd.getOptionValue(OPT_PSW_KEK, "32")));
+ final int kekLen = RecipientKekSizes
+ .requireSupported(Integer.parseInt(cmd.getOptionValue(OPT_PSW_KEK, "32")));
- KeyringStore ks = loadKeyringIfPresent(cmd, OPT_KEYRING,
- keyringUnlockProvider);
+ KeyringStore ks = loadKeyringIfPresent(cmd, OPT_KEYRING, keyringUnlockProvider);
try (ks) {
for (String alias : cmd.getOptionValues(OPT_TO_ALIAS) == null ? new String[0]
: cmd.getOptionValues(OPT_TO_ALIAS)) {
@@ -424,8 +418,7 @@ public final class Guard {
throw new ParseException("Specify exactly one of --priv-alias or --password for decryption");
}
if (privAlias != null) {
- try (KeyringStore ks = requireKeyring(cmd, OPT_KEYRING,
- keyringUnlockProvider)) {
+ try (KeyringStore ks = requireKeyring(cmd, OPT_KEYRING, keyringUnlockProvider)) {
final KeyringStore.PrivateWithId pr = ks.getPrivateWithId(privAlias);
borrowedUnlockMaterial = new UnlockMaterial.Private(pr.key());
}
@@ -474,8 +467,7 @@ public final class Guard {
boolean hasAbsoluteMaximum = cmd.hasOption(absoluteMaximumOption);
if (!hasOperationalMaximum && !hasAbsoluteMaximum) {
if (passwordOperation) {
- throw new ParseException(
- "Password operations require --pbkdf2-max and --pbkdf2-hard-max");
+ throw new ParseException("Password operations require --pbkdf2-max and --pbkdf2-hard-max");
}
return new ZeroEchoSession();
}
@@ -485,11 +477,9 @@ public final class Guard {
try {
int operationalMaximum = Integer.parseInt(cmd.getOptionValue(operationalMaximumOption));
int absoluteMaximum = Integer.parseInt(cmd.getOptionValue(absoluteMaximumOption));
- return new ZeroEchoSession().withPbkdf2Limits(
- new Pbkdf2Limits(operationalMaximum, absoluteMaximum));
+ return new ZeroEchoSession().withPbkdf2Limits(new Pbkdf2Limits(operationalMaximum, absoluteMaximum));
} catch (IllegalArgumentException exception) {
- ParseException parseException =
- new ParseException("Invalid PBKDF2 limits: " + exception.getMessage());
+ ParseException parseException = new ParseException("Invalid PBKDF2 limits: " + exception.getMessage());
parseException.initCause(exception);
throw parseException;
}
@@ -524,9 +514,9 @@ public final class Guard {
*
*
*
- * In both cases, the created context is consumed by
- * the matching {@link MultiRecipientDataSourceBuilder} recipient method and is
- * closed internally by the resulting content.
+ * In both cases, the created context is consumed by the matching
+ * {@link MultiRecipientDataSourceBuilder} recipient method and is closed
+ * internally by the resulting content.
*
*
* @param env target builder to which the recipient is added
@@ -542,8 +532,8 @@ public final class Guard {
*/
@SuppressWarnings({ "PMD.CloseResource", "PMD.UseTryWithResources" })
private static void addRecipientFromAlias(ZeroEchoSession session, MultiRecipientDataSourceBuilder env,
- KeyringStore ks, String alias,
- int kekBytes, int saltLen, boolean decoy) throws GeneralSecurityException, IOException {
+ KeyringStore ks, String alias, int kekBytes, int saltLen, boolean decoy)
+ throws GeneralSecurityException, IOException {
KeyringStore.PublicWithId r = ks.getPublicWithId(alias);
final String algId = r.algorithm();
final java.security.PublicKey pub = r.key();
@@ -602,16 +592,14 @@ public final class Guard {
}
private static KeyringStore loadKeyringIfPresent(CommandLine cmd, Option optKs,
- KeyringUnlockProvider unlockProvider)
- throws IOException, GeneralSecurityException {
+ KeyringUnlockProvider unlockProvider) throws IOException, GeneralSecurityException {
if (!cmd.hasOption(optKs)) {
return null;
}
return KeyringUnlocks.open(Paths.get(cmd.getOptionValue(optKs)), unlockProvider);
}
- private static KeyringStore requireKeyring(CommandLine cmd, Option optKs,
- KeyringUnlockProvider unlockProvider)
+ private static KeyringStore requireKeyring(CommandLine cmd, Option optKs, KeyringUnlockProvider unlockProvider)
throws IOException, ParseException, GeneralSecurityException {
if (!cmd.hasOption(optKs)) {
throw new ParseException("--keyring is required when aliases are used");
diff --git a/app/src/main/java/zeroecho/Kem.java b/app/src/main/java/zeroecho/Kem.java
index 6d9d9d1..81dc966 100644
--- a/app/src/main/java/zeroecho/Kem.java
+++ b/app/src/main/java/zeroecho/Kem.java
@@ -210,30 +210,27 @@ public final class Kem { // NOPMD
* @param args command arguments
* @param opts command options
* @return process exit code
- * @throws ParseException if arguments are invalid
- * @throws IOException if I/O fails
+ * @throws ParseException if arguments are invalid
+ * @throws IOException if I/O fails
* @throws GeneralSecurityException if cryptographic processing fails
*/
- public static int main(String[] args, Options opts)
- throws ParseException, IOException, GeneralSecurityException {
+ public static int main(String[] args, Options opts) throws ParseException, IOException, GeneralSecurityException {
return main(args, opts, KeyringUnlocks.console());
}
/**
* Executes the KEM command with an explicit keyring unlock source.
*
- * @param args command arguments
- * @param opts command options
+ * @param args command arguments
+ * @param opts command options
* @param unlockProvider keyring password provider
* @return process exit code
- * @throws ParseException if arguments are invalid
- * @throws IOException if I/O fails
+ * @throws ParseException if arguments are invalid
+ * @throws IOException if I/O fails
* @throws GeneralSecurityException if cryptographic processing fails
*/
- @SuppressWarnings({ "PMD.NcssCount", "PMD.CyclomaticComplexity",
- "PMD.NPathComplexity" })
- public static int main(String[] args, Options opts,
- KeyringUnlockProvider unlockProvider)
+ @SuppressWarnings({ "PMD.NcssCount", "PMD.CyclomaticComplexity", "PMD.NPathComplexity" })
+ public static int main(String[] args, Options opts, KeyringUnlockProvider unlockProvider)
throws ParseException, IOException, GeneralSecurityException {
ZeroEchoSession session = new ZeroEchoSession();
defineOptions(opts);
@@ -275,105 +272,105 @@ public final class Kem { // NOPMD
final Path keyringPath = Path.of(cmd.getOptionValue(OPT_KEYRING.getLongOpt()));
try (KeyringStore keyring = KeyringUnlocks.open(keyringPath, unlockProvider)) {
- // Configure KEM envelope
- KemDataContentBuilder kem = KemDataContentBuilder.builder(session).kem(kemId);
- if (cmd.hasOption(OPT_DIRECT.getLongOpt())) {
- kem = kem.directSecret();
- } else {
- byte[] info = parseOptionalHex(cmd, OPT_HKDF, "ZeroEcho-KEM".getBytes());
- kem = kem.hkdfSha256(info);
- }
- // typed numeric options
- Integer keyBytes = parsedIntOpt(cmd, OPT_KEY_BYTES);
- if (keyBytes != null) {
- kem = kem.derivedKeyBytes(keyBytes);
- }
- Integer maxKemCt = parsedIntOpt(cmd, OPT_MAX_KEM_CT);
- if (maxKemCt != null) {
- kem = kem.maxKemCiphertextLen(maxKemCt);
- }
+ // Configure KEM envelope
+ KemDataContentBuilder kem = KemDataContentBuilder.builder(session).kem(kemId);
+ if (cmd.hasOption(OPT_DIRECT.getLongOpt())) {
+ kem = kem.directSecret();
+ } else {
+ byte[] info = parseOptionalHex(cmd, OPT_HKDF, "ZeroEcho-KEM".getBytes());
+ kem = kem.hkdfSha256(info);
+ }
+ // typed numeric options
+ Integer keyBytes = parsedIntOpt(cmd, OPT_KEY_BYTES);
+ if (keyBytes != null) {
+ kem = kem.derivedKeyBytes(keyBytes);
+ }
+ Integer maxKemCt = parsedIntOpt(cmd, OPT_MAX_KEM_CT);
+ if (maxKemCt != null) {
+ kem = kem.maxKemCiphertextLen(maxKemCt);
+ }
- // Common symmetric knobs
- final byte[] aad = parseHexOpt(cmd, OPT_AAD);
- final boolean wantHeader = cmd.hasOption(OPT_HEADER.getLongOpt());
+ // Common symmetric knobs
+ final byte[] aad = parseHexOpt(cmd, OPT_AAD);
+ final boolean wantHeader = cmd.hasOption(OPT_HEADER.getLongOpt());
- // AES payload
- if (wantAes) {
- String mode = cmd.getOptionValue(OPT_AES_CIPHER.getLongOpt(), "gcm").toLowerCase(Locale.ROOT);
- AesDataContentBuilder aes = AesDataContentBuilder.builder(session);
- switch (mode) {
- case "gcm" -> {
- Integer tagBitsOpt = parsedIntOpt(cmd, OPT_AES_TAG_BITS);
- int tagBits = tagBitsOpt == null ? 128 : tagBitsOpt;
+ // AES payload
+ if (wantAes) {
+ String mode = cmd.getOptionValue(OPT_AES_CIPHER.getLongOpt(), "gcm").toLowerCase(Locale.ROOT);
+ AesDataContentBuilder aes = AesDataContentBuilder.builder(session);
+ switch (mode) {
+ case "gcm" -> {
+ Integer tagBitsOpt = parsedIntOpt(cmd, OPT_AES_TAG_BITS);
+ int tagBits = tagBitsOpt == null ? 128 : tagBitsOpt;
- aes = aes.modeGcm(tagBits);
+ aes = aes.modeGcm(tagBits);
+ }
+ case "ctr" -> aes = aes.modeCtr();
+ case "cbc" -> aes = aes.modeCbcPkcs5();
+ default -> throw new ParseException("Unsupported --aes-cipher: " + mode);
}
- case "ctr" -> aes = aes.modeCtr();
- case "cbc" -> aes = aes.modeCbcPkcs5();
- default -> throw new ParseException("Unsupported --aes-cipher: " + mode);
+ byte[] iv = parseHexOpt(cmd, OPT_AES_IV);
+ if (iv != null) {
+ aes = aes.withDecryptionIv(iv);
+ }
+ if (aad != null && aad.length > 0) {
+ aes = aes.withAad(aad);
+ }
+ if (wantHeader) {
+ aes = aes.withHeader();
+ }
+ kem = kem.withAes(aes);
}
- byte[] iv = parseHexOpt(cmd, OPT_AES_IV);
- if (iv != null) {
- aes = aes.withDecryptionIv(iv);
- }
- if (aad != null && aad.length > 0) {
- aes = aes.withAad(aad);
- }
- if (wantHeader) {
- aes = aes.withHeader();
- }
- kem = kem.withAes(aes);
- }
- // ChaCha payload
- if (wantChaCha) {
- ChaChaDataContentBuilder cc = ChaChaDataContentBuilder.builder(session);
- byte[] nonce = parseHexOpt(cmd, OPT_CHACHA_NONCE);
- if (nonce != null) {
- cc = cc.withDecryptionNonce(nonce);
+ // ChaCha payload
+ if (wantChaCha) {
+ ChaChaDataContentBuilder cc = ChaChaDataContentBuilder.builder(session);
+ byte[] nonce = parseHexOpt(cmd, OPT_CHACHA_NONCE);
+ if (nonce != null) {
+ cc = cc.withDecryptionNonce(nonce);
+ }
+ // counter is an integer, not bytes; use typed parsed option
+ Integer counter = parsedIntOpt(cmd, OPT_CHACHA_COUNTER);
+ if (counter != null) {
+ cc = cc.withCounter(counter);
+ }
+ Integer initial = parsedIntOpt(cmd, OPT_CHACHA_INITIAL);
+ if (initial != null) {
+ cc = cc.initialCounter(initial);
+ }
+ if (aad != null && aad.length > 0) {
+ cc = cc.withAad(aad); // selects AEAD
+ }
+ if (wantHeader) {
+ cc = cc.withHeader();
+ }
+ kem = kem.withChaCha(cc);
}
- // counter is an integer, not bytes; use typed parsed option
- Integer counter = parsedIntOpt(cmd, OPT_CHACHA_COUNTER);
- if (counter != null) {
- cc = cc.withCounter(counter);
- }
- Integer initial = parsedIntOpt(cmd, OPT_CHACHA_INITIAL);
- if (initial != null) {
- cc = cc.initialCounter(initial);
- }
- if (aad != null && aad.length > 0) {
- cc = cc.withAad(aad); // selects AEAD
- }
- if (wantHeader) {
- cc = cc.withHeader();
- }
- kem = kem.withChaCha(cc);
- }
- // Pipeline: source -> kem payload stage
- DataContent chain;
- if (encrypt) {
- String alias = require(cmd, OPT_PUB, "Missing --pub for encryption");
- PublicKey recipient = keyring.getPublic(alias);
- chain = DataContentChainBuilder.encrypt()
- .add(PlainFileBuilder.builder().url(Path.of(input).toUri().toURL()))
- .add(kem.recipientPublic(recipient)).build();
- } else {
- String alias = require(cmd, OPT_PRIV, "Missing --priv for decryption");
- PrivateKey recipient = keyring.getPrivate(alias);
- chain = DataContentChainBuilder.decrypt()
- .add(PlainFileBuilder.builder().url(Path.of(input).toUri().toURL()))
- .add(kem.recipientPrivate(recipient)).build();
- }
-
- try (InputStream in = chain.getStream(); OutputStream out = Files.newOutputStream(output)) {
- in.transferTo(out);
- } catch (IOException ex) {
- if (LOG.isLoggable(Level.SEVERE)) {
- LOG.log(Level.SEVERE, "I/O error", ex);
+ // Pipeline: source -> kem payload stage
+ DataContent chain;
+ if (encrypt) {
+ String alias = require(cmd, OPT_PUB, "Missing --pub for encryption");
+ PublicKey recipient = keyring.getPublic(alias);
+ chain = DataContentChainBuilder.encrypt()
+ .add(PlainFileBuilder.builder().url(Path.of(input).toUri().toURL()))
+ .add(kem.recipientPublic(recipient)).build();
+ } else {
+ String alias = require(cmd, OPT_PRIV, "Missing --priv for decryption");
+ PrivateKey recipient = keyring.getPrivate(alias);
+ chain = DataContentChainBuilder.decrypt()
+ .add(PlainFileBuilder.builder().url(Path.of(input).toUri().toURL()))
+ .add(kem.recipientPrivate(recipient)).build();
+ }
+
+ try (InputStream in = chain.getStream(); OutputStream out = Files.newOutputStream(output)) {
+ in.transferTo(out);
+ } catch (IOException ex) {
+ if (LOG.isLoggable(Level.SEVERE)) {
+ LOG.log(Level.SEVERE, "I/O error", ex);
+ }
+ return 1;
}
- return 1;
- }
return 0;
}
}
diff --git a/app/src/main/java/zeroecho/KeyStoreManagement.java b/app/src/main/java/zeroecho/KeyStoreManagement.java
index b63b36c..c52181c 100644
--- a/app/src/main/java/zeroecho/KeyStoreManagement.java
+++ b/app/src/main/java/zeroecho/KeyStoreManagement.java
@@ -192,16 +192,15 @@ public final class KeyStoreManagement {
/**
* Executes the command with an explicit unlock source.
*
- * @param args arguments passed by the application dispatcher
+ * @param args arguments passed by the application dispatcher
* @param dispatcherOptions dispatcher options
- * @param unlockProvider explicit destroyable-password provider
+ * @param unlockProvider explicit destroyable-password provider
* @return process exit code
- * @throws ParseException if parsing fails
- * @throws IOException if keyring I/O fails
+ * @throws ParseException if parsing fails
+ * @throws IOException if keyring I/O fails
* @throws GeneralSecurityException if cryptographic processing fails
*/
- public static int main(final String[] args, final Options dispatcherOptions,
- KeyringUnlockProvider unlockProvider)
+ public static int main(final String[] args, final Options dispatcherOptions, KeyringUnlockProvider unlockProvider)
throws ParseException, IOException, GeneralSecurityException {
ZeroEchoSession session = new ZeroEchoSession();
defineOptions(dispatcherOptions);
@@ -218,8 +217,7 @@ public final class KeyStoreManagement {
}
Path keyringPath = Path.of(cmd.getOptionValue(KEYSTORE_OPTION.getLongOpt()));
- try (KeyringStore store = Files.exists(keyringPath)
- ? KeyringUnlocks.open(keyringPath, unlockProvider)
+ try (KeyringStore store = Files.exists(keyringPath) ? KeyringUnlocks.open(keyringPath, unlockProvider)
: KeyringUnlocks.create(keyringPath, unlockProvider)) {
if (cmd.hasOption(LIST_ALIASES_OPTION.getLongOpt())) {
listAliases(store);
@@ -310,8 +308,8 @@ public final class KeyStoreManagement {
* @param store keyring store to mutate
* @param cmd parsed command line
*/
- public static void doGenerate(final ZeroEchoSession session, final KeyringStore store,
- final CommandLine cmd) throws IOException, GeneralSecurityException {
+ public static void doGenerate(final ZeroEchoSession session, final KeyringStore store, final CommandLine cmd)
+ throws IOException, GeneralSecurityException {
String algId = required(cmd, ALG_OPTION, "--alg is required for --generate");
String aliasBase = required(cmd, ALIAS_OPTION, "--alias is required for --generate");
String kind = cmd.getOptionValue(KIND_OPTION.getLongOpt());
@@ -391,8 +389,7 @@ public final class KeyStoreManagement {
}
private static void generateSymmetric(ZeroEchoSession session, KeyringStore store, CryptoAlgorithm algorithm,
- String algorithmId, String alias, boolean overwrite)
- throws IOException, GeneralSecurityException {
+ String algorithmId, String alias, boolean overwrite) throws IOException, GeneralSecurityException {
GeneratedSecret generated = firstGeneratedSecret(session, algorithm, algorithmId);
ensureWritable(store, alias, overwrite);
store.putSecret(alias, algorithmId, generated.key());
@@ -430,9 +427,7 @@ public final class KeyStoreManagement {
/** Selects the exact key-generation operation requested by the command. */
private enum GenerationKind {
- ASYMMETRIC,
- SYMMETRIC,
- NONE
+ ASYMMETRIC, SYMMETRIC, NONE
}
private static String required(CommandLine cmd, Option opt, String message) {
diff --git a/app/src/main/java/zeroecho/KeyringUnlocks.java b/app/src/main/java/zeroecho/KeyringUnlocks.java
index 9d2c01b..549b20e 100644
--- a/app/src/main/java/zeroecho/KeyringUnlocks.java
+++ b/app/src/main/java/zeroecho/KeyringUnlocks.java
@@ -53,8 +53,7 @@ final class KeyringUnlocks {
}
}
- private static KeyringPassword acquire(KeyringUnlockProvider provider)
- throws IOException {
+ private static KeyringPassword acquire(KeyringUnlockProvider provider) throws IOException {
KeyringPassword password = provider.acquire();
if (password == null) {
throw new IOException("Keyring unlock provider returned no password");
diff --git a/app/src/main/java/zeroecho/Tag.java b/app/src/main/java/zeroecho/Tag.java
index 6171f2a..e755410 100644
--- a/app/src/main/java/zeroecho/Tag.java
+++ b/app/src/main/java/zeroecho/Tag.java
@@ -158,24 +158,22 @@ public final class Tag { // NOPMD
* @throws GeneralSecurityException if a cryptographic error occurs during
* signature or digest processing
*/
- public static int main(String[] args, Options root)
- throws ParseException, IOException, GeneralSecurityException {
+ public static int main(String[] args, Options root) throws ParseException, IOException, GeneralSecurityException {
return main(args, root, KeyringUnlocks.console());
}
/**
* Executes the command with an explicit keyring unlock source.
*
- * @param args command arguments
- * @param root root options
+ * @param args command arguments
+ * @param root root options
* @param unlockProvider keyring password provider
* @return process exit code
- * @throws ParseException if parsing fails
- * @throws IOException if I/O fails
+ * @throws ParseException if parsing fails
+ * @throws IOException if I/O fails
* @throws GeneralSecurityException if cryptographic processing fails
*/
- public static int main(String[] args, Options root,
- KeyringUnlockProvider unlockProvider)
+ public static int main(String[] args, Options root, KeyringUnlockProvider unlockProvider)
throws ParseException, IOException, GeneralSecurityException {
ZeroEchoSession session = new ZeroEchoSession();
Options opts = root;
@@ -222,13 +220,13 @@ public final class Tag { // NOPMD
if (produce) {
String privAlias = require(cli, PRIV_OPT, "signature produce requires --priv ");
PrivateKey priv = keyring.getPrivate(privAlias);
- tail = new TagTrailerDataContentBuilder<>(
- TagEngineBuilder.signature(session, alg, priv, spec)).build(true);
+ tail = new TagTrailerDataContentBuilder<>(TagEngineBuilder.signature(session, alg, priv, spec))
+ .build(true);
} else {
String pubAlias = require(cli, PUB_OPT, "signature verify requires --pub ");
PublicKey pub = keyring.getPublic(pubAlias);
- tail = new TagTrailerDataContentBuilder<>(
- TagEngineBuilder.signature(session, alg, pub, spec)).build(false);
+ tail = new TagTrailerDataContentBuilder<>(TagEngineBuilder.signature(session, alg, pub, spec))
+ .build(false);
}
}
} else { // digest
diff --git a/app/src/test/java/zeroecho/GuardTest.java b/app/src/test/java/zeroecho/GuardTest.java
index 8c08be4..70a678d 100644
--- a/app/src/test/java/zeroecho/GuardTest.java
+++ b/app/src/test/java/zeroecho/GuardTest.java
@@ -124,16 +124,16 @@ public class GuardTest {
// Encrypt
String[] encArgs = { "--encrypt", in.toString(), "--output", enc.toString(), "--to-psw", password,
- "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg",
- "aes-gcm", "--tag-bits", Integer.toString(tagBits), "--aad-hex", aadHex };
+ "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg", "aes-gcm",
+ "--tag-bits", Integer.toString(tagBits), "--aad-hex", aadHex };
System.out.println("...encrypt: " + Arrays.toString(encArgs));
int e = Guard.main(encArgs, new Options(), TestKeyringUnlocks.provider());
assertEquals(0, e, "... encrypt expected exit code 0");
// Decrypt (using password)
String[] decArgs = { "--decrypt", enc.toString(), "--output", dec.toString(), "--password", password,
- "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg",
- "aes-gcm", "--tag-bits", Integer.toString(tagBits), "--aad-hex", aadHex };
+ "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg", "aes-gcm",
+ "--tag-bits", Integer.toString(tagBits), "--aad-hex", aadHex };
System.out.println("...decrypt: " + Arrays.toString(decArgs));
int d = Guard.main(decArgs, new Options(), TestKeyringUnlocks.provider());
assertEquals(0, d, "... decrypt expected exit code 0");
@@ -163,10 +163,8 @@ public class GuardTest {
System.out.println(method);
Path input = writeRandom(tmp.resolve("invalid-kek.bin"), 32, 0x4B454B);
Path output = tmp.resolve("invalid-kek.enc");
- String[] arguments = { "--encrypt", input.toString(), "--output", output.toString(),
- "--to-psw", "controlled", "--to-kek-bytes", "24",
- "--pbkdf2-max", TEST_PBKDF2_MAXIMUM,
- "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM,
+ String[] arguments = { "--encrypt", input.toString(), "--output", output.toString(), "--to-psw", "controlled",
+ "--to-kek-bytes", "24", "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM,
"--alg", "aes-gcm" };
IllegalArgumentException failure = assertThrows(IllegalArgumentException.class,
@@ -290,8 +288,8 @@ public class GuardTest {
// plus 2 random password decoys. Recipients are shuffled by default.
String[] encArgs = { "--encrypt", in.toString(), "--output", enc.toString(), "--keyring", ring.toString(),
"--to-alias", rsa.pub, "--to-psw", password, "--decoy-alias", elg.pub, "--decoy-psw-rand", "2",
- "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg",
- "aes-gcm", "--tag-bits", Integer.toString(tagBits), "--aad-hex", aad };
+ "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg", "aes-gcm",
+ "--tag-bits", Integer.toString(tagBits), "--aad-hex", aad };
System.out.println("...encrypt: " + Arrays.toString(encArgs));
int e = Guard.main(encArgs, new Options(), TestKeyringUnlocks.provider());
assertEquals(0, e, "... encrypt rc");
@@ -308,8 +306,8 @@ public class GuardTest {
// Decrypt via password instead of key
String[] decPwd = { "--decrypt", enc.toString(), "--output", dec2.toString(), "--password", password,
- "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg",
- "aes-gcm", "--tag-bits", Integer.toString(tagBits), "--aad-hex", aad };
+ "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg", "aes-gcm",
+ "--tag-bits", Integer.toString(tagBits), "--aad-hex", aad };
System.out.println("...decrypt(password): " + Arrays.toString(decPwd));
int d2 = Guard.main(decPwd, new Options(), TestKeyringUnlocks.provider());
assertEquals(0, d2, "... decrypt(password) rc");
@@ -334,9 +332,9 @@ public class GuardTest {
Path enc = tmp.resolve("pt-neg.bin.enc");
String pwd = "x";
- String[] encArgs = { "--encrypt", in.toString(), "--output", enc.toString(), "--to-psw", pwd,
- "--pbkdf2-max", TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg",
- "aes-gcm", "--tag-bits", "128" };
+ String[] encArgs = { "--encrypt", in.toString(), "--output", enc.toString(), "--to-psw", pwd, "--pbkdf2-max",
+ TEST_PBKDF2_MAXIMUM, "--pbkdf2-hard-max", TEST_PBKDF2_MAXIMUM, "--alg", "aes-gcm", "--tag-bits",
+ "128" };
int e = Guard.main(encArgs, new Options(), TestKeyringUnlocks.provider());
assertEquals(0, e, "... encrypt rc");
diff --git a/app/src/test/java/zeroecho/KemTest.java b/app/src/test/java/zeroecho/KemTest.java
index e7c022b..1722cd0 100644
--- a/app/src/test/java/zeroecho/KemTest.java
+++ b/app/src/test/java/zeroecho/KemTest.java
@@ -165,8 +165,7 @@ public class KemTest {
KeyAliases aliases = generateKemIntoKeyStore(ring, kemId, "alias-" + shortId(kemId));
// Sanity: re-open to ensure the file is valid
- try (zeroecho.core.storage.KeyringPassword password =
- TestKeyringUnlocks.provider().acquire();
+ try (zeroecho.core.storage.KeyringPassword password = TestKeyringUnlocks.provider().acquire();
KeyringStore ks = KeyringStore.open(ring, password)) {
if (!(ks.contains(aliases.pub) && ks.contains(aliases.prv))) {
throw new IllegalStateException("Keyring does not contain expected aliases for " + kemId);
@@ -210,15 +209,15 @@ public class KemTest {
Files.write(plain, content);
System.out.println("...[" + kemId + "] ChaCha encrypt");
int e = Kem.main(new String[] { "--encrypt", plain.toString(), "--output", enc.toString(),
- "--keyring", ring.toString(), "--pub", aliases.pub, "--kem", kemId, "--chacha",
- "--aad", aadChaCha, "--header" }, new Options(), TestKeyringUnlocks.provider());
+ "--keyring", ring.toString(), "--pub", aliases.pub, "--kem", kemId, "--chacha", "--aad",
+ aadChaCha, "--header" }, new Options(), TestKeyringUnlocks.provider());
if (e != 0) {
throw new IllegalStateException("ChaCha encrypt rc=" + e);
}
System.out.println("...[" + kemId + "] ChaCha decrypt");
int d = Kem.main(new String[] { "--decrypt", enc.toString(), "--output", dec.toString(),
- "--keyring", ring.toString(), "--priv", aliases.prv, "--kem", kemId, "--chacha",
- "--aad", aadChaCha, "--header" }, new Options(), TestKeyringUnlocks.provider());
+ "--keyring", ring.toString(), "--priv", aliases.prv, "--kem", kemId, "--chacha", "--aad",
+ aadChaCha, "--header" }, new Options(), TestKeyringUnlocks.provider());
if (d != 0) {
throw new IllegalStateException("ChaCha decrypt rc=" + d);
}
diff --git a/app/src/test/java/zeroecho/KeyStoreManagementTest.java b/app/src/test/java/zeroecho/KeyStoreManagementTest.java
index 54a0aed..85f673b 100644
--- a/app/src/test/java/zeroecho/KeyStoreManagementTest.java
+++ b/app/src/test/java/zeroecho/KeyStoreManagementTest.java
@@ -139,8 +139,7 @@ public class KeyStoreManagementTest {
assertTrue(attempted > 0, "No generation attempts were successful");
// Verify by reloading and materializing.
- zeroecho.core.storage.KeyringPassword password =
- TestKeyringUnlocks.provider().acquire();
+ zeroecho.core.storage.KeyringPassword password = TestKeyringUnlocks.provider().acquire();
KeyringStore store;
try {
store = KeyringStore.open(ring, password);
@@ -197,15 +196,13 @@ public class KeyStoreManagementTest {
// ---- helpers ----
private static boolean hasAsymmetricDefault(CryptoAlgorithm alg) {
- return alg.keyOperations().stream()
- .anyMatch(info -> info.operation() == KeyOperation.ASYMMETRIC_KEY_PAIR_GENERATE
- && info.defaultSpec() != null);
+ return alg.keyOperations().stream().anyMatch(
+ info -> info.operation() == KeyOperation.ASYMMETRIC_KEY_PAIR_GENERATE && info.defaultSpec() != null);
}
private static boolean hasSymmetricDefault(CryptoAlgorithm alg) {
return alg.keyOperations().stream()
- .anyMatch(info -> info.operation() == KeyOperation.SYMMETRIC_GENERATE
- && info.defaultSpec() != null);
+ .anyMatch(info -> info.operation() == KeyOperation.SYMMETRIC_GENERATE && info.defaultSpec() != null);
}
private static String sanitize(String id) {
diff --git a/app/src/test/java/zeroecho/TagTest.java b/app/src/test/java/zeroecho/TagTest.java
index aa4fd77..1ce7560 100644
--- a/app/src/test/java/zeroecho/TagTest.java
+++ b/app/src/test/java/zeroecho/TagTest.java
@@ -127,8 +127,7 @@ public class TagTest {
Path ring = tmp.resolve("ring-ed25519.txt");
KeyAliases ed = generateIntoKeyStore(ring, "Ed25519", "ed");
// sanity
- try (zeroecho.core.storage.KeyringPassword password =
- TestKeyringUnlocks.provider().acquire();
+ try (zeroecho.core.storage.KeyringPassword password = TestKeyringUnlocks.provider().acquire();
KeyringStore ks = KeyringStore.open(ring, password)) {
assertTrue(ks.contains(ed.pub) && ks.contains(ed.prv), "missing expected aliases");
}
@@ -200,12 +199,18 @@ public class TagTest {
Files.write(plain, pt);
// produce
- assertEquals(0, Tag.main(new String[] { "--type", "digest", "--mode", "produce", "--alg", "SHA-256", "--in",
- plain.toString(), "--out", tagged.toString() }, new Options(), TestKeyringUnlocks.provider()));
+ assertEquals(0,
+ Tag.main(
+ new String[] { "--type", "digest", "--mode", "produce", "--alg", "SHA-256", "--in",
+ plain.toString(), "--out", tagged.toString() },
+ new Options(), TestKeyringUnlocks.provider()));
// verify (match)
- assertEquals(0, Tag.main(new String[] { "--type", "digest", "--mode", "verify", "--alg", "SHA-256", "--in",
- tagged.toString(), "--out", recovered.toString() }, new Options(), TestKeyringUnlocks.provider()));
+ assertEquals(0,
+ Tag.main(
+ new String[] { "--type", "digest", "--mode", "verify", "--alg", "SHA-256", "--in",
+ tagged.toString(), "--out", recovered.toString() },
+ new Options(), TestKeyringUnlocks.provider()));
assertArrayEquals(pt, Files.readAllBytes(recovered), "digest round-trip mismatch");
@@ -223,15 +228,21 @@ public class TagTest {
Files.write(plain, pt);
// produce
- assertEquals(0, Tag.main(new String[] { "--type", "digest", "--mode", "produce", "--alg", "SHA-256", "--in",
- plain.toString(), "--out", tagged.toString() }, new Options(), TestKeyringUnlocks.provider()));
+ assertEquals(0,
+ Tag.main(
+ new String[] { "--type", "digest", "--mode", "produce", "--alg", "SHA-256", "--in",
+ plain.toString(), "--out", tagged.toString() },
+ new Options(), TestKeyringUnlocks.provider()));
// corrupt last byte -> break digest
flipLastByte(tagged);
// verify (mismatch): expect throw + default marker ("digest invalid")
- assertEquals(1, Tag.main(new String[] { "--type", "digest", "--mode", "verify", "--alg", "SHA-256", "--in",
- tagged.toString(), "--out", out.toString() }, new Options(), TestKeyringUnlocks.provider()));
+ assertEquals(1,
+ Tag.main(
+ new String[] { "--type", "digest", "--mode", "verify", "--alg", "SHA-256", "--in",
+ tagged.toString(), "--out", out.toString() },
+ new Options(), TestKeyringUnlocks.provider()));
assertTrue(Files.notExists(out, LinkOption.NOFOLLOW_LINKS));
diff --git a/app/src/test/java/zeroecho/TestKeyringUnlocks.java b/app/src/test/java/zeroecho/TestKeyringUnlocks.java
index bce4419..fe52199 100644
--- a/app/src/test/java/zeroecho/TestKeyringUnlocks.java
+++ b/app/src/test/java/zeroecho/TestKeyringUnlocks.java
@@ -8,7 +8,6 @@ final class TestKeyringUnlocks {
}
static KeyringUnlockProvider provider() {
- return () -> new KeyringPassword(
- new char[] { 't', 'e', 's', 't', '-', 'k', 'e', 'y', 'r', 'i', 'n', 'g' });
+ return () -> new KeyringPassword(new char[] { 't', 'e', 's', 't', '-', 'k', 'e', 'y', 'r', 'i', 'n', 'g' });
}
}
diff --git a/ext/src/test/java/zeroecho/ext/integrations/covert/jpeg/JpegExifIntegrationTest.java b/ext/src/test/java/zeroecho/ext/integrations/covert/jpeg/JpegExifIntegrationTest.java
index d60a531..d575848 100644
--- a/ext/src/test/java/zeroecho/ext/integrations/covert/jpeg/JpegExifIntegrationTest.java
+++ b/ext/src/test/java/zeroecho/ext/integrations/covert/jpeg/JpegExifIntegrationTest.java
@@ -91,17 +91,17 @@ class JpegExifIntegrationTest {
// AES encryption setup
/*
- * SecretKey key = zeroEchoSession.keyBuilders().symmetric()
- * .generate("AES", AesKeyGenSpec.aes256()); AesSpec spec =
+ * SecretKey key = zeroEchoSession.keyBuilders().symmetric() .generate("AES",
+ * AesKeyGenSpec.aes256()); AesSpec spec =
* AesSpec.builder().mode(Mode.GCM).tagLenBits(128).header(null).build();
- * EncryptionContext enc = zeroEchoSession.createContext("AES", KeyUsage.ENCRYPT, key,
- * spec); CtxInterface session = Ctx.INSTANCE.getContext("aes-ctx-" +
- * System.nanoTime()); session.put(ConfluxKeys.aad("AES"), aad); ((ContextAware)
+ * EncryptionContext enc = zeroEchoSession.createContext("AES",
+ * KeyUsage.ENCRYPT, key, spec); CtxInterface session =
+ * Ctx.INSTANCE.getContext("aes-ctx-" + System.nanoTime());
+ * session.put(ConfluxKeys.aad("AES"), aad); ((ContextAware)
* enc).setContext(session);
*/
ZeroEchoSession zeroEchoSession = new ZeroEchoSession();
- SecretKey key = zeroEchoSession.keyBuilders().symmetric()
- .generate("AES", AesKeyGenSpec.aes256());
+ SecretKey key = zeroEchoSession.keyBuilders().symmetric().generate("AES", AesKeyGenSpec.aes256());
CtxInterface session = Ctx.INSTANCE.getContext("aes-ctx-" + System.nanoTime());
byte[] encryptedBytes;
@@ -152,7 +152,8 @@ class JpegExifIntegrationTest {
// input
.add(PlainBytesBuilder.builder().bytes(extractedEncryptedBytes))
// encryption
- .add(AesDataContentBuilder.builder(zeroEchoSession).importKeyRaw(key.getEncoded()).spec(AesSpec.gcm128(null))
+ .add(AesDataContentBuilder.builder(zeroEchoSession).importKeyRaw(key.getEncoded())
+ .spec(AesSpec.gcm128(null))
// let us use the default header for AAD and IV
.withHeader().withAad(aad).context(session))
// and create the pipeline
@@ -164,9 +165,9 @@ class JpegExifIntegrationTest {
/*
* AesSpec spec =
* AesSpec.builder().mode(Mode.GCM).tagLenBits(128).header(null).build();
- * EncryptionContext dec1 = zeroEchoSession.createContext("AES", KeyUsage.DECRYPT,
- * key, spec); ((ContextAware) dec1).setContext(session); // same IV/AAD in ctx
- * byte[] pt1 = readAll(dec1.attach(new
+ * EncryptionContext dec1 = zeroEchoSession.createContext("AES",
+ * KeyUsage.DECRYPT, key, spec); ((ContextAware) dec1).setContext(session); //
+ * same IV/AAD in ctx byte[] pt1 = readAll(dec1.attach(new
* ByteArrayInputStream(extractedEncryptedBytes))); dec1.close();
*/
String decrypted = new String(pt1, StandardCharsets.UTF_8);
diff --git a/lib/src/main/java/zeroecho/core/Capability.java b/lib/src/main/java/zeroecho/core/Capability.java
index 3303f9e..86dfd22 100644
--- a/lib/src/main/java/zeroecho/core/Capability.java
+++ b/lib/src/main/java/zeroecho/core/Capability.java
@@ -16,29 +16,31 @@ import zeroecho.core.spec.ContextSpec;
/**
* Immutable value descriptor of one algorithm context capability.
*
- * The default specification is resolved once during provider construction.
- * All components therefore have stable value semantics and are safe for
- * concurrent reads.
+ *
+ * The default specification is resolved once during provider construction. All
+ * components therefore have stable value semantics and are safe for concurrent
+ * reads.
+ *
*
* @param algorithmId canonical algorithm identifier
- * @param family algorithm family
- * @param role supported key usage
+ * @param family algorithm family
+ * @param role supported key usage
* @param contextType produced context type
- * @param keyType accepted key type
- * @param specType accepted specification type
+ * @param keyType accepted key type
+ * @param specType accepted specification type
* @param defaultSpec non-null resolved default specification
* @since 1.0
*/
public record Capability(String algorithmId, AlgorithmFamily family, KeyUsage role,
- Class extends CryptoContext> contextType, Class extends Key> keyType,
- Class extends ContextSpec> specType, ContextSpec defaultSpec) {
+ Class extends CryptoContext> contextType, Class extends Key> keyType, Class extends ContextSpec> specType,
+ ContextSpec defaultSpec) {
/**
* Validates the capability metadata.
*
- * @throws NullPointerException if a component is {@code null}
- * @throws IllegalArgumentException if {@code defaultSpec} is incompatible
- * with {@code specType}
+ * @throws NullPointerException if a component is {@code null}
+ * @throws IllegalArgumentException if {@code defaultSpec} is incompatible with
+ * {@code specType}
*/
public Capability {
Objects.requireNonNull(algorithmId, "algorithmId must not be null");
diff --git a/lib/src/main/java/zeroecho/core/CryptoAlgorithm.java b/lib/src/main/java/zeroecho/core/CryptoAlgorithm.java
index 39f2337..6e7c2d4 100644
--- a/lib/src/main/java/zeroecho/core/CryptoAlgorithm.java
+++ b/lib/src/main/java/zeroecho/core/CryptoAlgorithm.java
@@ -106,8 +106,8 @@ import zeroecho.core.spi.SymmetricKeyImporter;
*
* Security note: Algorithms must enforce strong validation of keys and
* specs during registration and
- * {@link #createContext(KeyUsage, Key, ContextSpec)} to
- * prevent downgrade or misuse attacks.
+ * {@link #createContext(KeyUsage, Key, ContextSpec)} to prevent downgrade or
+ * misuse attacks.
*
*
* @since 1.0
@@ -123,16 +123,11 @@ public abstract class CryptoAlgorithm { // NOPMD
private final List capabilities = new ArrayList<>();
private final Map>> ctxBindings = new EnumMap<>(KeyUsage.class);
- private final Map, AsymmetricKeyPairGenerator>> keyPairGenerators =
- new LinkedHashMap<>();
- private final Map, PublicKeyImporter>> publicKeyImporters =
- new LinkedHashMap<>();
- private final Map, PrivateKeyImporter>> privateKeyImporters =
- new LinkedHashMap<>();
- private final Map, SymmetricKeyGenerator>> symmetricKeyGenerators =
- new LinkedHashMap<>();
- private final Map, SymmetricKeyImporter>> symmetricKeyImporters =
- new LinkedHashMap<>();
+ private final Map, AsymmetricKeyPairGenerator>> keyPairGenerators = new LinkedHashMap<>();
+ private final Map, PublicKeyImporter>> publicKeyImporters = new LinkedHashMap<>();
+ private final Map, PrivateKeyImporter>> privateKeyImporters = new LinkedHashMap<>();
+ private final Map, SymmetricKeyGenerator>> symmetricKeyGenerators = new LinkedHashMap<>();
+ private final Map, SymmetricKeyImporter>> symmetricKeyImporters = new LinkedHashMap<>();
private final Map, AlgorithmKeySpec> asymmetricDefaults = new LinkedHashMap<>();
private final Map, AlgorithmKeySpec> symmetricDefaults = new LinkedHashMap<>();
@@ -296,8 +291,9 @@ public abstract class CryptoAlgorithm { // NOPMD
*
* Concrete algorithms call this during construction to declare support for
* specific roles (e.g., {@code ENCRYPT}, {@code VERIFY}). When
- * {@link #createContext(KeyUsage, Key, ContextSpec)} is later invoked, the provided
- * {@code key} and optional {@code spec} are matched against these bindings.
+ * {@link #createContext(KeyUsage, Key, ContextSpec)} is later invoked, the
+ * provided {@code key} and optional {@code spec} are matched against these
+ * bindings.
*
*
* @param role supported {@link KeyUsage} role
@@ -397,8 +393,7 @@ public abstract class CryptoAlgorithm { // NOPMD
if (rb.accepts(key, spec)) {
S resolved = (spec != null) ? spec
: Objects.requireNonNull(rb.defaultSpec.get(), "defaultSpec value must not be null");
- C ctx = Objects.requireNonNull(rb.factory.createContext(key, resolved),
- _id + " factory returned null");
+ C ctx = Objects.requireNonNull(rb.factory.createContext(key, resolved), _id + " factory returned null");
// Enforce the declared context type contract:
if (!rb.ctxType.isInstance(ctx)) {
throw new IllegalStateException(_id + " factory returned " + ctx.getClass().getName()
@@ -411,8 +406,7 @@ public abstract class CryptoAlgorithm { // NOPMD
+ (spec == null ? " (default spec)" : " and spec=" + spec.getClass().getName()));
}
- private S resolveDefault(Class specType,
- Supplier extends S> defaultSpecOrNull) {
+ private S resolveDefault(Class specType, Supplier extends S> defaultSpecOrNull) {
if (defaultSpecOrNull == null) {
return null;
}
@@ -426,16 +420,18 @@ public abstract class CryptoAlgorithm { // NOPMD
/**
* Registers asymmetric key-pair generation for one exact specification class.
*
- * The optional default is resolved and validated during registration.
+ *
+ * The optional default is resolved and validated during registration.
* Registered generators must be safe for concurrent invocation after the
- * algorithm is published.
+ * algorithm is published.
+ *
*
- * @param specType exact specification class
- * @param generator non-null generator
+ * @param specType exact specification class
+ * @param generator non-null generator
* @param defaultSpecOrNull optional default supplier, evaluated once
- * @param specification type
- * @throws NullPointerException if a required argument or supplied default is
- * {@code null}
+ * @param specification type
+ * @throws NullPointerException if a required argument or supplied default
+ * is {@code null}
* @throws IllegalArgumentException if the supplied default has the wrong type
*/
protected final void registerAsymmetricKeyPairGenerator(Class specType,
@@ -450,7 +446,7 @@ public abstract class CryptoAlgorithm { // NOPMD
*
* @param specType exact specification class
* @param importer non-null importer safe for concurrent invocation
- * @param specification type
+ * @param specification type
* @throws NullPointerException if an argument is {@code null}
*/
protected final void registerPublicKeyImporter(Class specType,
@@ -464,7 +460,7 @@ public abstract class CryptoAlgorithm { // NOPMD
*
* @param specType exact specification class
* @param importer non-null importer safe for concurrent invocation
- * @param specification type
+ * @param specification type
* @throws NullPointerException if an argument is {@code null}
*/
protected final void registerPrivateKeyImporter(Class specType,
@@ -476,14 +472,16 @@ public abstract class CryptoAlgorithm { // NOPMD
/**
* Registers symmetric-key generation for one exact specification class.
*
- * The optional default is resolved and validated during registration.
+ *
+ * The optional default is resolved and validated during registration.
+ *
*
- * @param specType exact specification class
- * @param generator non-null generator safe for concurrent invocation
+ * @param specType exact specification class
+ * @param generator non-null generator safe for concurrent invocation
* @param defaultSpecOrNull optional default supplier, evaluated once
- * @param specification type
- * @throws NullPointerException if a required argument or supplied default is
- * {@code null}
+ * @param specification type
+ * @throws NullPointerException if a required argument or supplied default
+ * is {@code null}
* @throws IllegalArgumentException if the supplied default has the wrong type
*/
protected final void registerSymmetricKeyGenerator(Class specType,
@@ -498,7 +496,7 @@ public abstract class CryptoAlgorithm { // NOPMD
*
* @param specType exact specification class
* @param importer non-null importer safe for concurrent invocation
- * @param specification type
+ * @param specification type
* @throws NullPointerException if an argument is {@code null}
*/
protected final void registerSymmetricKeyImporter(Class specType,
@@ -515,12 +513,14 @@ public abstract class CryptoAlgorithm { // NOPMD
* Returns the asymmetric key-pair generator registered for an exact
* specification class.
*
- * The returned implementation may be shared and invoked concurrently.
+ *
+ * The returned implementation may be shared and invoked concurrently.
+ *
*
* @param specType exact specification class; subclasses are not matched
- * @param specification type
+ * @param specification type
* @return registered generator
- * @throws NullPointerException if {@code specType} is {@code null}
+ * @throws NullPointerException if {@code specType} is {@code null}
* @throws IllegalArgumentException if no generator is registered
*/
@SuppressWarnings("unchecked")
@@ -537,12 +537,14 @@ public abstract class CryptoAlgorithm { // NOPMD
/**
* Returns the public-key importer registered for an exact specification class.
*
- * The returned implementation may be shared and invoked concurrently.
+ *
+ * The returned implementation may be shared and invoked concurrently.
+ *
*
* @param specType exact specification class; subclasses are not matched
- * @param specification type
+ * @param specification type
* @return registered importer
- * @throws NullPointerException if {@code specType} is {@code null}
+ * @throws NullPointerException if {@code specType} is {@code null}
* @throws IllegalArgumentException if no importer is registered
*/
@SuppressWarnings("unchecked")
@@ -556,15 +558,16 @@ public abstract class CryptoAlgorithm { // NOPMD
}
/**
- * Returns the private-key importer registered for an exact specification
- * class.
+ * Returns the private-key importer registered for an exact specification class.
*
- * The returned implementation may be shared and invoked concurrently.
+ *
+ * The returned implementation may be shared and invoked concurrently.
+ *
*
* @param specType exact specification class; subclasses are not matched
- * @param specification type
+ * @param specification type
* @return registered importer
- * @throws NullPointerException if {@code specType} is {@code null}
+ * @throws NullPointerException if {@code specType} is {@code null}
* @throws IllegalArgumentException if no importer is registered
*/
@SuppressWarnings("unchecked")
@@ -581,12 +584,14 @@ public abstract class CryptoAlgorithm { // NOPMD
* Returns the symmetric-key generator registered for an exact specification
* class.
*
- * The returned implementation may be shared and invoked concurrently.
+ *
+ * The returned implementation may be shared and invoked concurrently.
+ *
*
* @param specType exact specification class; subclasses are not matched
- * @param specification type
+ * @param specification type
* @return registered generator
- * @throws NullPointerException if {@code specType} is {@code null}
+ * @throws NullPointerException if {@code specType} is {@code null}
* @throws IllegalArgumentException if no generator is registered
*/
@SuppressWarnings("unchecked")
@@ -603,12 +608,14 @@ public abstract class CryptoAlgorithm { // NOPMD
* Returns the symmetric-key importer registered for an exact specification
* class.
*
- * The returned implementation may be shared and invoked concurrently.
+ *
+ * The returned implementation may be shared and invoked concurrently.
+ *
*
* @param specType exact specification class; subclasses are not matched
- * @param specification type
+ * @param specification type
* @return registered importer
- * @throws NullPointerException if {@code specType} is {@code null}
+ * @throws NullPointerException if {@code specType} is {@code null}
* @throws IllegalArgumentException if no importer is registered
*/
@SuppressWarnings("unchecked")
@@ -628,14 +635,12 @@ public abstract class CryptoAlgorithm { // NOPMD
*/
public final List keyOperations() {
List result = new ArrayList<>();
- addOperationInfo(result, KeyOperation.ASYMMETRIC_KEY_PAIR_GENERATE, keyPairGenerators,
- asymmetricDefaults);
+ addOperationInfo(result, KeyOperation.ASYMMETRIC_KEY_PAIR_GENERATE, keyPairGenerators, asymmetricDefaults);
addOperationInfo(result, KeyOperation.ASYMMETRIC_PUBLIC_IMPORT, publicKeyImporters, Map.of());
addOperationInfo(result, KeyOperation.ASYMMETRIC_PRIVATE_IMPORT, privateKeyImporters, Map.of());
addOperationInfo(result, KeyOperation.SYMMETRIC_GENERATE, symmetricKeyGenerators, symmetricDefaults);
addOperationInfo(result, KeyOperation.SYMMETRIC_IMPORT, symmetricKeyImporters, Map.of());
- result.sort(Comparator.comparing(KeyOperationInfo::operation)
- .thenComparing(info -> info.specType().getName()));
+ result.sort(Comparator.comparing(KeyOperationInfo::operation).thenComparing(info -> info.specType().getName()));
return List.copyOf(result);
}
diff --git a/lib/src/main/java/zeroecho/core/CryptoAlgorithms.java b/lib/src/main/java/zeroecho/core/CryptoAlgorithms.java
index 61713be..058ba83 100644
--- a/lib/src/main/java/zeroecho/core/CryptoAlgorithms.java
+++ b/lib/src/main/java/zeroecho/core/CryptoAlgorithms.java
@@ -17,10 +17,12 @@ import java.util.TreeMap;
/**
* Immutable registry of {@link CryptoAlgorithm} providers.
*
- * Providers are discovered once through {@link ServiceLoader}, sorted by
+ *
+ * Providers are discovered once through {@link ServiceLoader}, sorted by
* canonical algorithm identifier, and retained in one immutable registry.
* Runtime policy and auditing belong exclusively to explicitly created
- * {@link zeroecho.sdk.ZeroEchoSession} instances.
+ * {@link zeroecho.sdk.ZeroEchoSession} instances.
+ *
*
* @since 1.0
*/
diff --git a/lib/src/main/java/zeroecho/core/CryptoCatalog.java b/lib/src/main/java/zeroecho/core/CryptoCatalog.java
index 86d5690..d038c25 100644
--- a/lib/src/main/java/zeroecho/core/CryptoCatalog.java
+++ b/lib/src/main/java/zeroecho/core/CryptoCatalog.java
@@ -93,9 +93,9 @@ public final class CryptoCatalog {
* {@link CryptoAlgorithms}.
*
*
- * Provider discovery, deterministic ordering, and duplicate checking occur
- * once in {@code CryptoAlgorithms}. This method neither scans providers nor
- * copies their collection.
+ * Provider discovery, deterministic ordering, and duplicate checking occur once
+ * in {@code CryptoAlgorithms}. This method neither scans providers nor copies
+ * their collection.
*
*
* @return an immutable {@code CryptoCatalog} with all discovered algorithms
@@ -158,40 +158,16 @@ public final class CryptoCatalog {
/**
* Serializes the catalog to a compact JSON document.
*
- *
- * The schema is:
- *
- * {@code
- * {
- * "algorithms": [
- * {
- * "id": "AES/GCM",
- * "displayName": "AES-GCM",
- * "capabilities": [
- * {
- * "family": "SYMMETRIC",
- * "role": "ENCRYPT",
- * "contextType": "AeadEncryptContext",
- * "keyType": "SecretKey",
- * "specType": "AeadSpec",
- * "defaultSpec": "Random nonce, 128-bit tag"
- * }
- * ],
- * "asymmetricKeyBuilders": [
- * { "specType": "Ed25519Spec", "defaultKeySpec": "Ed25519 default" }
- * ],
- * "symmetricKeyBuilders": [
- * { "specType": "AesKeySpec", "defaultKeySpec": "AES-256" }
- * ]
- * }
- * ]
- * }
- * }
+ * The schema is:
{@code { "algorithms": [ { "id": "AES/GCM",
+ * "displayName": "AES-GCM", "capabilities": [ { "family": "SYMMETRIC", "role":
+ * "ENCRYPT", "contextType": "AeadEncryptContext", "keyType": "SecretKey",
+ * "specType": "AeadSpec", "defaultSpec": "Random nonce, 128-bit tag" } ],
+ * "asymmetricKeyBuilders": [ { "specType": "Ed25519Spec", "defaultKeySpec":
+ * "Ed25519 default" } ], "symmetricKeyBuilders": [ { "specType": "AesKeySpec",
+ * "defaultKeySpec": "AES-256" } ] } ] } }
*
- *
- * String values are escaped for quotes and backslashes. The method does not
- * attempt to pretty-print; callers can format the output if needed.
- *
+ * String values are escaped for quotes and backslashes. The method does not
+ * attempt to pretty-print; callers can format the output if needed.
*
* @return a JSON string describing algorithms, capabilities, and key builders
*/
@@ -230,8 +206,7 @@ public final class CryptoCatalog {
}
firstOperation = false;
sb.append('{').append(jsonField("operation", operation.operation().name())).append(',')
- .append(jsonField("specType", operation.specType().getSimpleName()))
- .append(",\"defaultSpec\":")
+ .append(jsonField("specType", operation.specType().getSimpleName())).append(",\"defaultSpec\":")
.append(operation.defaultSpec() == null ? "null" : jsonString(labelOf(operation.defaultSpec())))
.append('}');
}
@@ -273,9 +248,8 @@ public final class CryptoCatalog {
}
sb.append("");
for (KeyOperationInfo operation : a.keyOperations()) {
- sb.append("")
+ sb.append("")
.append(operation.defaultSpec() == null ? "" : esc(labelOf(operation.defaultSpec())))
.append("");
}
diff --git a/lib/src/main/java/zeroecho/core/KeyOperationInfo.java b/lib/src/main/java/zeroecho/core/KeyOperationInfo.java
index 5126673..3c45210 100644
--- a/lib/src/main/java/zeroecho/core/KeyOperationInfo.java
+++ b/lib/src/main/java/zeroecho/core/KeyOperationInfo.java
@@ -14,20 +14,20 @@ import zeroecho.core.spec.AlgorithmKeySpec;
/**
* Immutable metadata for one exact key operation.
*
- * @param operation operation guaranteed by the associated lookup
- * @param specType exact accepted specification type
+ * @param operation operation guaranteed by the associated lookup
+ * @param specType exact accepted specification type
* @param defaultSpec resolved generation default, or {@code null} for import
* operations and generators without a default
* @since 1.0
*/
-public record KeyOperationInfo(KeyOperation operation,
- Class extends AlgorithmKeySpec> specType, AlgorithmKeySpec defaultSpec) {
+public record KeyOperationInfo(KeyOperation operation, Class extends AlgorithmKeySpec> specType,
+ AlgorithmKeySpec defaultSpec) {
/**
* Validates the metadata invariant.
*
- * @throws NullPointerException if {@code operation} or {@code specType} is
- * {@code null}
+ * @throws NullPointerException if {@code operation} or {@code specType} is
+ * {@code null}
* @throws IllegalArgumentException if a default is incompatible with
* {@code specType}, or an import operation
* declares a default
@@ -38,9 +38,9 @@ public record KeyOperationInfo(KeyOperation operation,
if (defaultSpec != null && !specType.isInstance(defaultSpec)) {
throw new IllegalArgumentException("defaultSpec must be an instance of " + specType.getName());
}
- if (defaultSpec != null && (operation == KeyOperation.SYMMETRIC_IMPORT
- || operation == KeyOperation.ASYMMETRIC_PUBLIC_IMPORT
- || operation == KeyOperation.ASYMMETRIC_PRIVATE_IMPORT)) {
+ if (defaultSpec != null
+ && (operation == KeyOperation.SYMMETRIC_IMPORT || operation == KeyOperation.ASYMMETRIC_PUBLIC_IMPORT
+ || operation == KeyOperation.ASYMMETRIC_PRIVATE_IMPORT)) {
throw new IllegalArgumentException("import operations cannot declare a default specification");
}
}
diff --git a/lib/src/main/java/zeroecho/core/alg/AbstractCryptoAlgorithm.java b/lib/src/main/java/zeroecho/core/alg/AbstractCryptoAlgorithm.java
index f451fd9..b38632f 100644
--- a/lib/src/main/java/zeroecho/core/alg/AbstractCryptoAlgorithm.java
+++ b/lib/src/main/java/zeroecho/core/alg/AbstractCryptoAlgorithm.java
@@ -147,8 +147,8 @@ public abstract class AbstractCryptoAlgorithm extends CryptoAlgorithm {
*
* Validation
Type checks happen at creation time (via {@code bind})
* and again when
- * {@link CryptoAlgorithm#createContext(KeyUsage, Key, ContextSpec)} is
- * called. If a factory returns a context not assignable to {@code ctxType}, an
+ * {@link CryptoAlgorithm#createContext(KeyUsage, Key, ContextSpec)} is called.
+ * If a factory returns a context not assignable to {@code ctxType}, an
* {@link IllegalStateException} will be thrown.
*
* @param family high-level algorithm family classification
diff --git a/lib/src/main/java/zeroecho/core/alg/aes/AesCipherContext.java b/lib/src/main/java/zeroecho/core/alg/aes/AesCipherContext.java
index 6f79e5b..debc5a5 100644
--- a/lib/src/main/java/zeroecho/core/alg/aes/AesCipherContext.java
+++ b/lib/src/main/java/zeroecho/core/alg/aes/AesCipherContext.java
@@ -63,9 +63,10 @@ import zeroecho.core.util.RandomSupport;
*
*
* IV and optional AAD are exchanged via a {@link conflux.CtxInterface} set with
- * {@link #setContext(conflux.CtxInterface)}. Encryption always generates a fresh
- * IV after atomically claiming the context; a caller-provided IV is never used
- * for encryption. Decryption requires the IV from the context or encoded header.
+ * {@link #setContext(conflux.CtxInterface)}. Encryption always generates a
+ * fresh IV after atomically claiming the context; a caller-provided IV is never
+ * used for encryption. Decryption requires the IV from the context or encoded
+ * header.
*
*
*
@@ -311,10 +312,7 @@ public final class AesCipherContext implements EncryptionContext, ContextAware {
/** Single-use encryption lifecycle states. */
private enum OperationState {
- NEW,
- ENCRYPTING,
- COMPLETED,
- FAILED
+ NEW, ENCRYPTING, COMPLETED, FAILED
}
/** Marks the owning encryption context terminal as its stream is consumed. */
diff --git a/lib/src/main/java/zeroecho/core/alg/aes/AesKeyImportSpec.java b/lib/src/main/java/zeroecho/core/alg/aes/AesKeyImportSpec.java
index bb3e828..9f8453b 100644
--- a/lib/src/main/java/zeroecho/core/alg/aes/AesKeyImportSpec.java
+++ b/lib/src/main/java/zeroecho/core/alg/aes/AesKeyImportSpec.java
@@ -60,8 +60,8 @@ import zeroecho.core.spec.AlgorithmKeySpec;
*
*
*
- * Objects of this type are thread-safe while active and may be destroyed to wipe
- * their owned key bytes. Access and marshalling fail after destruction.
+ * Objects of this type are thread-safe while active and may be destroyed to
+ * wipe their owned key bytes. Access and marshalling fail after destruction.
*
*
* @since 1.0
diff --git a/lib/src/main/java/zeroecho/core/alg/chacha/AbstractChaChaCipherContext.java b/lib/src/main/java/zeroecho/core/alg/chacha/AbstractChaChaCipherContext.java
index 9bda202..e4026b8 100644
--- a/lib/src/main/java/zeroecho/core/alg/chacha/AbstractChaChaCipherContext.java
+++ b/lib/src/main/java/zeroecho/core/alg/chacha/AbstractChaChaCipherContext.java
@@ -243,8 +243,8 @@ abstract class AbstractChaChaCipherContext implements
* Ensures a nonce is available in the context.
*
*
- * - For encryption, always generates a new nonce after the context has
- * been atomically claimed and stores a copy in the context.
+ * - For encryption, always generates a new nonce after the context has been
+ * atomically claimed and stores a copy in the context.
* - For decryption, validates presence and correct length.
*
*
@@ -283,10 +283,7 @@ abstract class AbstractChaChaCipherContext implements
/** Single-use encryption lifecycle states. */
private enum OperationState {
- NEW,
- ENCRYPTING,
- COMPLETED,
- FAILED
+ NEW, ENCRYPTING, COMPLETED, FAILED
}
/** Marks the owning encryption context terminal as its stream is consumed. */
diff --git a/lib/src/main/java/zeroecho/core/alg/chacha/ChaChaAlgorithm.java b/lib/src/main/java/zeroecho/core/alg/chacha/ChaChaAlgorithm.java
index 6dd61ad..eaafb0f 100644
--- a/lib/src/main/java/zeroecho/core/alg/chacha/ChaChaAlgorithm.java
+++ b/lib/src/main/java/zeroecho/core/alg/chacha/ChaChaAlgorithm.java
@@ -34,6 +34,7 @@
package zeroecho.core.alg.chacha;
import zeroecho.core.util.RandomSupport;
+
/**
* ChaCha20 (stream) algorithm
*
diff --git a/lib/src/main/java/zeroecho/core/alg/chacha/package-info.java b/lib/src/main/java/zeroecho/core/alg/chacha/package-info.java
index 0220272..d0f2cf7 100644
--- a/lib/src/main/java/zeroecho/core/alg/chacha/package-info.java
+++ b/lib/src/main/java/zeroecho/core/alg/chacha/package-info.java
@@ -39,10 +39,10 @@
* the stream cipher ChaCha20 and the AEAD construction ChaCha20-Poly1305. The
* module contains algorithm descriptors, streaming cipher contexts,
* configuration specifications, optional header codecs for runtime parameters,
- * and symmetric key import/generation specifications. Key import
- * specifications are destroyable. The design favors safe defaults
- * (12-byte nonces, 128-bit AEAD tag), explicit role-to-context binding, and a
- * clear separation between static configuration and per-operation parameters.
+ * and symmetric key import/generation specifications. Key import specifications
+ * are destroyable. The design favors safe defaults (12-byte nonces, 128-bit
+ * AEAD tag), explicit role-to-context binding, and a clear separation between
+ * static configuration and per-operation parameters.
*
*
* Components
diff --git a/lib/src/main/java/zeroecho/core/alg/common/agreement/GenericJcaAgreementContext.java b/lib/src/main/java/zeroecho/core/alg/common/agreement/GenericJcaAgreementContext.java
index 333759e..73264c1 100644
--- a/lib/src/main/java/zeroecho/core/alg/common/agreement/GenericJcaAgreementContext.java
+++ b/lib/src/main/java/zeroecho/core/alg/common/agreement/GenericJcaAgreementContext.java
@@ -44,9 +44,9 @@ import zeroecho.core.context.AgreementContext;
* Generic JCA-based Key Agreement Context
*
* An {@link AgreementContext} backed by the standard JCA key-agreement API.
- * This class supports elliptic-curve and modern Diffie-Hellman variants
- * such as ECDH, XDH (X25519, X448), and others provided by the runtime or
- * configured provider.
+ * This class supports elliptic-curve and modern Diffie-Hellman variants such as
+ * ECDH, XDH (X25519, X448), and others provided by the runtime or configured
+ * provider.
*
*
* Instances of this context are created with a local {@link PrivateKey}, and
diff --git a/lib/src/main/java/zeroecho/core/alg/common/eddsa/package-info.java b/lib/src/main/java/zeroecho/core/alg/common/eddsa/package-info.java
index 08621ad..ad8bb3b 100644
--- a/lib/src/main/java/zeroecho/core/alg/common/eddsa/package-info.java
+++ b/lib/src/main/java/zeroecho/core/alg/common/eddsa/package-info.java
@@ -99,9 +99,9 @@
* reconstructs public keys from X.509 encodings via
* {@link java.security.KeyFactory}.
*
Signature contexts:
- * {@link zeroecho.core.alg.common.eddsa.CommonEdDSASignatureContext}
- * delegates all operations to a generic JCA-backed signature adapter, enforcing
- * a fixed tag length for the selected EdDSA variant.
+ * {@link zeroecho.core.alg.common.eddsa.CommonEdDSASignatureContext} delegates
+ * all operations to a generic JCA-backed signature adapter, enforcing a fixed
+ * tag length for the selected EdDSA variant.
*
*
* Design notes
diff --git a/lib/src/main/java/zeroecho/core/alg/common/sig/SignatureInteropProfile.java b/lib/src/main/java/zeroecho/core/alg/common/sig/SignatureInteropProfile.java
index f2ebb2b..eaef5aa 100644
--- a/lib/src/main/java/zeroecho/core/alg/common/sig/SignatureInteropProfile.java
+++ b/lib/src/main/java/zeroecho/core/alg/common/sig/SignatureInteropProfile.java
@@ -116,7 +116,8 @@ public final class SignatureInteropProfile { // NOPMD
* @param keyAlgorithmId ZeroEcho key algorithm identifier used for key
* import and matching, such as {@code RSA}
* @param contextAlgorithmId ZeroEcho context algorithm identifier used
- * with {@code ZeroEchoSession.createContext(...)}
+ * with
+ * {@code ZeroEchoSession.createContext(...)}
* @param contextSpec explicit ZeroEcho context specification
* @param signatureRepresentation signature representation bridge between
* external bytes and internal ZeroEcho bytes
diff --git a/lib/src/main/java/zeroecho/core/alg/common/sig/package-info.java b/lib/src/main/java/zeroecho/core/alg/common/sig/package-info.java
index 9a618c9..5531503 100644
--- a/lib/src/main/java/zeroecho/core/alg/common/sig/package-info.java
+++ b/lib/src/main/java/zeroecho/core/alg/common/sig/package-info.java
@@ -60,9 +60,9 @@
* configured {@link java.security.Signature}, resolves a fixed tag length (via
* resolvers), and exposes a one-shot {@code wrap(InputStream)} API.
* Verification behavior is controlled by a pluggable comparison approach.
- * SignatureStream - internal passthrough input stream that feeds chunks to
- * the signature engine, emits the trailer in SIGN mode, and performs final
- * verification in VERIFY mode.
+ * SignatureStream - internal passthrough input stream that feeds
+ * chunks to the signature engine, emits the trailer in SIGN mode, and performs
+ * final verification in VERIFY mode.
*
*
* Length resolution
diff --git a/lib/src/main/java/zeroecho/core/alg/digest/Sha2Sha3Algorithm.java b/lib/src/main/java/zeroecho/core/alg/digest/Sha2Sha3Algorithm.java
index 3677b26..fb0871c 100644
--- a/lib/src/main/java/zeroecho/core/alg/digest/Sha2Sha3Algorithm.java
+++ b/lib/src/main/java/zeroecho/core/alg/digest/Sha2Sha3Algorithm.java
@@ -117,8 +117,8 @@ public final class Sha2Sha3Algorithm extends AbstractCryptoAlgorithm {
MessageDigest md = MessageDigest.getInstance(s.algorithm().jca());
return new JcaDigestContext(this, md, s);
} catch (GeneralSecurityException e) {
- throw new ProviderFailureException(
- "Failed to initialize MessageDigest " + s.algorithm().jca(), e);
+ throw new ProviderFailureException("Failed to initialize MessageDigest " + s.algorithm().jca(),
+ e);
}
}, DigestSpec::sha256 // default for catalog/tests
);
diff --git a/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhAlgorithm.java b/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhAlgorithm.java
index 087e4ac..79f48ae 100644
--- a/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhAlgorithm.java
+++ b/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhAlgorithm.java
@@ -160,8 +160,7 @@ public final class EcdhAlgorithm extends AbstractCryptoAlgorithm {
() -> EcdsaCurveSpec.P256);
// Reuse EC builders/importers
- registerAsymmetricKeyPairGenerator(EcdhCurveSpec.class, new EcdhKeyGenBuilder(),
- () -> EcdhCurveSpec.P256);
+ registerAsymmetricKeyPairGenerator(EcdhCurveSpec.class, new EcdhKeyGenBuilder(), () -> EcdhCurveSpec.P256);
registerPublicKeyImporter(EcdsaPublicKeySpec.class, new EcdsaPublicKeyBuilder());
registerPrivateKeyImporter(EcdsaPrivateKeySpec.class, new EcdsaPrivateKeyBuilder());
}
diff --git a/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhKeyGenBuilder.java b/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhKeyGenBuilder.java
index 451ac69..6943452 100644
--- a/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhKeyGenBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ecdh/EcdhKeyGenBuilder.java
@@ -45,8 +45,8 @@ import zeroecho.core.spi.AsymmetricKeyPairGenerator;
/**
* ECDH Key Pair Generator
*
- * Implementation of {@link zeroecho.core.spi.AsymmetricKeyPairGenerator} for elliptic curve
- * Diffie-Hellman (ECDH) key pairs.
+ * Implementation of {@link zeroecho.core.spi.AsymmetricKeyPairGenerator} for
+ * elliptic curve Diffie-Hellman (ECDH) key pairs.
*
*
* This builder generates fresh EC key pairs suitable for ECDH key agreement. It
diff --git a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaAlgorithm.java b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaAlgorithm.java
index 797630f..8985b11 100644
--- a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaAlgorithm.java
+++ b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaAlgorithm.java
@@ -103,8 +103,8 @@ public final class EcdsaAlgorithm extends AbstractCryptoAlgorithm {
*
* On construction, the algorithm declares its supported roles and registers
* builders with the {@link CryptoAlgorithm} infrastructure so they can be
- * discovered by the {@link CryptoCatalog} or invoked through the
- * session-bound {@link zeroecho.sdk.KeyBuilders} entry point.
+ * discovered by the {@link CryptoCatalog} or invoked through the session-bound
+ * {@link zeroecho.sdk.KeyBuilders} entry point.
*
*/
public EcdsaAlgorithm() {
@@ -134,8 +134,7 @@ public final class EcdsaAlgorithm extends AbstractCryptoAlgorithm {
}
}, () -> EcdsaCurveSpec.P256);
- registerAsymmetricKeyPairGenerator(EcdsaCurveSpec.class, new EcdsaKeyGenBuilder(),
- () -> EcdsaCurveSpec.P256);
+ registerAsymmetricKeyPairGenerator(EcdsaCurveSpec.class, new EcdsaKeyGenBuilder(), () -> EcdsaCurveSpec.P256);
registerPublicKeyImporter(EcdsaPublicKeySpec.class, new EcdsaPublicKeyBuilder());
registerPrivateKeyImporter(EcdsaPrivateKeySpec.class, new EcdsaPrivateKeyBuilder());
}
diff --git a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaKeyGenBuilder.java b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaKeyGenBuilder.java
index 7f628b5..06732b8 100644
--- a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaKeyGenBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaKeyGenBuilder.java
@@ -45,14 +45,14 @@ import zeroecho.core.spi.AsymmetricKeyPairGenerator;
* ECDSA Key Pair Generator
*
* Implementation of {@link zeroecho.core.spi.AsymmetricKeyPairGenerator} for
- * {@link EcdsaCurveSpec}.
- * This builder is responsible for generating new elliptic curve key pairs for
- * use with the {@link EcdsaAlgorithm}.
+ * {@link EcdsaCurveSpec}. This builder is responsible for generating new
+ * elliptic curve key pairs for use with the {@link EcdsaAlgorithm}.
*
- * The exact supported operation is
- * {@link #generateKeyPair(EcdsaCurveSpec)}. Public and private import are
- * registered separately through {@link EcdsaPublicKeyBuilder} and
- * {@link EcdsaPrivateKeyBuilder}.
+ *
+ * The exact supported operation is {@link #generateKeyPair(EcdsaCurveSpec)}.
+ * Public and private import are registered separately through
+ * {@link EcdsaPublicKeyBuilder} and {@link EcdsaPrivateKeyBuilder}.
+ *
*
* Usage
Typically accessed through the session key-operation API or
* {@link CryptoAlgorithm#asymmetricKeyPairGenerator(Class)}.
diff --git a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPrivateKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPrivateKeyBuilder.java
index ac05027..4289416 100644
--- a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPrivateKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPrivateKeyBuilder.java
@@ -49,9 +49,11 @@ import zeroecho.core.spi.PrivateKeyImporter;
* {@link EcdsaPrivateKeySpec}. This builder is responsible for importing ECDSA
* private keys from encoded representations.
*
- * The exact supported operation is
- * {@link #importPrivate(EcdsaPrivateKeySpec)}. Generation and public import are
- * registered through their own operation-specific implementations.
+ *
+ * The exact supported operation is {@link #importPrivate(EcdsaPrivateKeySpec)}.
+ * Generation and public import are registered through their own
+ * operation-specific implementations.
+ *
*
* Encoding
The {@link EcdsaPrivateKeySpec} stores the private key in
* PKCS#8 DER format. This builder delegates to a JCA {@link KeyFactory} for the
diff --git a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPublicKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPublicKeyBuilder.java
index c67dc3f..52ec0b2 100644
--- a/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPublicKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ecdsa/EcdsaPublicKeyBuilder.java
@@ -48,9 +48,11 @@ import zeroecho.core.spi.PublicKeyImporter;
* {@link EcdsaPublicKeySpec}. This builder is responsible for importing ECDSA
* public keys from X.509 SubjectPublicKeyInfo encodings.
*
- * The exact supported operation is
- * {@link #importPublic(EcdsaPublicKeySpec)}. Generation and private import are
- * registered through their own operation-specific implementations.
+ *
+ * The exact supported operation is {@link #importPublic(EcdsaPublicKeySpec)}.
+ * Generation and private import are registered through their own
+ * operation-specific implementations.
+ *
*
* Encoding
The {@link EcdsaPublicKeySpec} stores the public key in
* standard X.509 DER format. This builder delegates to a JCA {@link KeyFactory}
diff --git a/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519KeyGenBuilder.java b/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519KeyGenBuilder.java
index 50a11bc..77590fa 100644
--- a/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519KeyGenBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519KeyGenBuilder.java
@@ -38,8 +38,8 @@ import zeroecho.core.alg.common.eddsa.AbstractEdDSAKeyGenBuilder;
/**
* Key-pair builder for Ed25519
*
- * Concrete {@link zeroecho.core.spi.AsymmetricKeyPairGenerator} implementation for
- * generating Ed25519 key pairs.
+ * Concrete {@link zeroecho.core.spi.AsymmetricKeyPairGenerator} implementation
+ * for generating Ed25519 key pairs.
*
*
* This builder delegates to the JCA provider under the canonical algorithm name
diff --git a/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PrivateKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PrivateKeyBuilder.java
index 8e324f0..f3fec88 100644
--- a/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PrivateKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PrivateKeyBuilder.java
@@ -38,8 +38,8 @@ import zeroecho.core.alg.common.eddsa.AbstractEncodedPrivateKeyBuilder;
/**
*
Private key builder for Ed25519
*
- * Concrete {@link zeroecho.core.spi.PrivateKeyImporter} for importing
- * wrapping Ed25519 private keys.
+ * Concrete {@link zeroecho.core.spi.PrivateKeyImporter} for importing wrapping
+ * Ed25519 private keys.
*
*
* This builder integrates with the JCA under the canonical key factory
diff --git a/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PublicKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PublicKeyBuilder.java
index 886117e..579e55d 100644
--- a/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PublicKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ed25519/Ed25519PublicKeyBuilder.java
@@ -38,8 +38,8 @@ import zeroecho.core.alg.common.eddsa.AbstractEncodedPublicKeyBuilder;
/**
*
Public key builder for Ed25519
*
- * Concrete {@link zeroecho.core.spi.PublicKeyImporter} for importing
- * wrapping Ed25519 public keys.
+ * Concrete {@link zeroecho.core.spi.PublicKeyImporter} for importing wrapping
+ * Ed25519 public keys.
*
*
* This builder integrates with the JCA under the canonical key factory
diff --git a/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PrivateKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PrivateKeyBuilder.java
index 883339f..dba5047 100644
--- a/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PrivateKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PrivateKeyBuilder.java
@@ -66,8 +66,7 @@ import zeroecho.core.spec.AlgorithmKeySpec;
*
*
Thread-safety
Stateless and safe for concurrent use. Each call to
* {@link zeroecho.core.spi.PrivateKeyImporter#importPrivate(AlgorithmKeySpec)}
- * creates a new
- * {@link java.security.KeyFactory}.
+ * creates a new {@link java.security.KeyFactory}.
*
* @since 1.0
*/
diff --git a/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PublicKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PublicKeyBuilder.java
index bf6566f..7ff1f3b 100644
--- a/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PublicKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/ed448/Ed448PublicKeyBuilder.java
@@ -65,8 +65,7 @@ import zeroecho.core.spec.AlgorithmKeySpec;
*
* Thread-safety
Stateless and safe for concurrent use. Each call to
* {@link zeroecho.core.spi.PublicKeyImporter#importPublic(AlgorithmKeySpec)}
- * creates a new
- * {@link java.security.KeyFactory}.
+ * creates a new {@link java.security.KeyFactory}.
*
* @since 1.0
*/
diff --git a/lib/src/main/java/zeroecho/core/alg/kyber/KyberKeyGenSpec.java b/lib/src/main/java/zeroecho/core/alg/kyber/KyberKeyGenSpec.java
index a56a929..66df0e2 100644
--- a/lib/src/main/java/zeroecho/core/alg/kyber/KyberKeyGenSpec.java
+++ b/lib/src/main/java/zeroecho/core/alg/kyber/KyberKeyGenSpec.java
@@ -63,7 +63,8 @@ import zeroecho.core.spec.AlgorithmKeySpec;
*
*
* @see KyberAlgorithm
- * @see zeroecho.sdk.KeyBuilders.Asymmetric#generateKeyPair(String, AlgorithmKeySpec)
+ * @see zeroecho.sdk.KeyBuilders.Asymmetric#generateKeyPair(String,
+ * AlgorithmKeySpec)
*/
public final class KyberKeyGenSpec implements AlgorithmKeySpec, Describable {
/**
diff --git a/lib/src/main/java/zeroecho/core/alg/kyber/KyberPrivateKeySpec.java b/lib/src/main/java/zeroecho/core/alg/kyber/KyberPrivateKeySpec.java
index 5e088be..785c3ff 100644
--- a/lib/src/main/java/zeroecho/core/alg/kyber/KyberPrivateKeySpec.java
+++ b/lib/src/main/java/zeroecho/core/alg/kyber/KyberPrivateKeySpec.java
@@ -47,9 +47,9 @@ import zeroecho.core.spec.AlgorithmKeySpec;
* Specification wrapper for a Kyber (ML-KEM) private key encoded in PKCS#8.
*
*
- * Instances of this class carry an owned copy of the PKCS#8-encoded private
- * key bytes. They are used with {@link zeroecho.core.CryptoAlgorithm} key
- * builders to import keys into the provider’s native representation.
+ * Instances of this class carry an owned copy of the PKCS#8-encoded private key
+ * bytes. They are used with {@link zeroecho.core.CryptoAlgorithm} key builders
+ * to import keys into the provider’s native representation.
*
*
* Encoding
diff --git a/lib/src/main/java/zeroecho/core/alg/rsa/BlockGeometry.java b/lib/src/main/java/zeroecho/core/alg/rsa/BlockGeometry.java
index 81b6e55..214ceee 100644
--- a/lib/src/main/java/zeroecho/core/alg/rsa/BlockGeometry.java
+++ b/lib/src/main/java/zeroecho/core/alg/rsa/BlockGeometry.java
@@ -102,8 +102,7 @@ public record BlockGeometry(int inChunkSize, int outChunkSize, int finalizationO
"inChunkSize must not exceed outChunkSize: " + inChunkSize + " > " + outChunkSize);
}
if (finalizationOutputChunks != 0) {
- throw new IllegalArgumentException(
- "finalizationOutputChunks must be zero: " + finalizationOutputChunks);
+ throw new IllegalArgumentException("finalizationOutputChunks must be zero: " + finalizationOutputChunks);
}
}
diff --git a/lib/src/main/java/zeroecho/core/alg/saber/SaberKeyGenSpec.java b/lib/src/main/java/zeroecho/core/alg/saber/SaberKeyGenSpec.java
index ae2b067..6c5de5d 100644
--- a/lib/src/main/java/zeroecho/core/alg/saber/SaberKeyGenSpec.java
+++ b/lib/src/main/java/zeroecho/core/alg/saber/SaberKeyGenSpec.java
@@ -43,7 +43,8 @@ import zeroecho.core.spec.AlgorithmKeySpec;
* A {@code SaberKeyGenSpec} selects one of the SABER parameter variants
* standardized in round-3 submissions. Each variant balances performance,
* bandwidth, and security level. This spec is passed to a registered
- * {@link zeroecho.core.spi.AsymmetricKeyPairGenerator} to generate a SABER key pair.
+ * {@link zeroecho.core.spi.AsymmetricKeyPairGenerator} to generate a SABER key
+ * pair.
*
*
* Variants
The {@link Variant} enumeration identifies supported SABER
diff --git a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusKeyGenBuilder.java b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusKeyGenBuilder.java
index 8078506..94dade0 100644
--- a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusKeyGenBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusKeyGenBuilder.java
@@ -54,10 +54,12 @@ import zeroecho.core.spi.AsymmetricKeyPairGenerator;
* Reflection is used to avoid a hard dependency on all parameter variants.
*
*
- * The exact supported operation is
- * {@link #generateKeyPair(SphincsPlusKeyGenSpec)}. Public and private import are
- * registered separately for {@link SphincsPlusPublicKeySpec} and
- * {@link SphincsPlusPrivateKeySpec}.
+ *
+ * The exact supported operation is
+ * {@link #generateKeyPair(SphincsPlusKeyGenSpec)}. Public and private import
+ * are registered separately for {@link SphincsPlusPublicKeySpec} and
+ * {@link SphincsPlusPrivateKeySpec}.
+ *
*
* Example
{@code
* SphincsPlusKeyGenSpec spec =
diff --git a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeyBuilder.java
index d93cb1d..49338e1 100644
--- a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeyBuilder.java
@@ -51,9 +51,11 @@ import zeroecho.core.spi.PrivateKeyImporter;
* pairs but focuses solely on importing private key material.
*
*
- * The exact supported operation is
+ *
+ * The exact supported operation is
* {@link #importPrivate(SphincsPlusPrivateKeySpec)}. Other key operations are
- * registered through their own exact interfaces.
+ * registered through their own exact interfaces.
+ *
*
* Example
{@code
* // Assuming bytes contain a PKCS#8-encoded SPHINCS+ private key:
diff --git a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeySpec.java b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeySpec.java
index d45f4a5..582901c 100644
--- a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeySpec.java
+++ b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPrivateKeySpec.java
@@ -48,7 +48,8 @@ import zeroecho.core.spec.AlgorithmKeySpec;
*
* {@code SphincsPlusPrivateKeySpec} wraps a PKCS#8-encoded SPHINCS+ private key
* along with the provider name that should be used for import. It is a simple
- * destroyable holder designed for use with {@link SphincsPlusPrivateKeyBuilder}.
+ * destroyable holder designed for use with
+ * {@link SphincsPlusPrivateKeyBuilder}.
*
*
* Encoding
diff --git a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPublicKeyBuilder.java b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPublicKeyBuilder.java
index 5eef249..b657d80 100644
--- a/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPublicKeyBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/sphincsplus/SphincsPlusPublicKeyBuilder.java
@@ -50,9 +50,11 @@ import zeroecho.core.spi.PublicKeyImporter;
* pairs, but focuses solely on importing public key material.
*
*
- * The exact supported operation is
+ *
+ * The exact supported operation is
* {@link #importPublic(SphincsPlusPublicKeySpec)}. Other key operations are
- * registered through their own exact interfaces.
+ * registered through their own exact interfaces.
+ *
*
* Example
{@code
* // Assuming bytes contain an X.509-encoded SPHINCS+ public key:
diff --git a/lib/src/main/java/zeroecho/core/alg/xdh/XdhKeyGenBuilder.java b/lib/src/main/java/zeroecho/core/alg/xdh/XdhKeyGenBuilder.java
index 227bfb4..e5df7d9 100644
--- a/lib/src/main/java/zeroecho/core/alg/xdh/XdhKeyGenBuilder.java
+++ b/lib/src/main/java/zeroecho/core/alg/xdh/XdhKeyGenBuilder.java
@@ -51,7 +51,8 @@ import zeroecho.core.spi.AsymmetricKeyPairGenerator;
* Design and scope
*
* - Generation only: This implementation exposes only the exact
- * key-pair generation capability; import operations are registered separately.
+ * key-pair generation capability; import operations are registered
+ * separately.
* - Provider resolution: The default JCA provider selection is used.
* If a specific provider is required, supply or register one that exposes the
* requested XDH algorithm name.
diff --git a/lib/src/main/java/zeroecho/core/audit/AuditListeners.java b/lib/src/main/java/zeroecho/core/audit/AuditListeners.java
index 7edf79c..1376522 100644
--- a/lib/src/main/java/zeroecho/core/audit/AuditListeners.java
+++ b/lib/src/main/java/zeroecho/core/audit/AuditListeners.java
@@ -13,10 +13,12 @@ import java.util.Objects;
/**
* Utilities for enforcing the best-effort audit-listener contract.
*
- * The returned listener suppresses listener failures without logging callback
+ *
+ * The returned listener suppresses listener failures without logging callback
* arguments, because those arguments may refer to sensitive cryptographic
* objects. Cryptographic operation outcomes therefore never depend on an audit
- * sink's availability.
+ * sink's availability.
+ *
*
* @since 1.0
*/
@@ -36,8 +38,8 @@ public final class AuditListeners {
AuditListener target = Objects.requireNonNull(listener, "listener");
ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
ClassLoader loader = contextLoader == null ? ClassLoader.getSystemClassLoader() : contextLoader;
- return (AuditListener) Proxy.newProxyInstance(loader,
- new Class>[] { AuditListener.class }, (proxy, method, arguments) -> {
+ return (AuditListener) Proxy.newProxyInstance(loader, new Class>[] { AuditListener.class },
+ (proxy, method, arguments) -> {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(target, arguments);
}
diff --git a/lib/src/main/java/zeroecho/core/audit/AuditMode.java b/lib/src/main/java/zeroecho/core/audit/AuditMode.java
index fc374a7..299bf58 100644
--- a/lib/src/main/java/zeroecho/core/audit/AuditMode.java
+++ b/lib/src/main/java/zeroecho/core/audit/AuditMode.java
@@ -10,8 +10,10 @@ package zeroecho.core.audit;
/**
* Defines the session-owned automatic auditing strategy.
*
- * Audit listener failures are best-effort diagnostics and never change the
- * outcome of a cryptographic operation.
+ *
+ * Audit listener failures are best-effort diagnostics and never change the
+ * outcome of a cryptographic operation.
+ *
*
* @since 1.0
*/
diff --git a/lib/src/main/java/zeroecho/core/audit/AuditedContexts.java b/lib/src/main/java/zeroecho/core/audit/AuditedContexts.java
index 14b2ae5..6ab2a66 100644
--- a/lib/src/main/java/zeroecho/core/audit/AuditedContexts.java
+++ b/lib/src/main/java/zeroecho/core/audit/AuditedContexts.java
@@ -105,8 +105,8 @@ import zeroecho.core.spec.ContextSpec;
* - Counting is performed by decorating the returned {@code InputStream}s; no
* buffering beyond normal {@code FilterInputStream} forwarding is
* introduced.
- * - Idempotent wrapping: contexts already wrapped by this utility are returned
- * unchanged. Unrelated JDK proxies are wrapped normally.
+ * - Idempotent wrapping: contexts already wrapped by this utility are
+ * returned unchanged. Unrelated JDK proxies are wrapped normally.
*
*
* Usage example
{@code
@@ -190,8 +190,7 @@ public final class AuditedContexts {
}
private static boolean isAuditedProxy(CryptoContext context) {
- return Proxy.isProxyClass(context.getClass())
- && Proxy.getInvocationHandler(context) instanceof AuditingHandler;
+ return Proxy.isProxyClass(context.getClass()) && Proxy.getInvocationHandler(context) instanceof AuditingHandler;
}
@SuppressWarnings("unchecked")
@@ -242,8 +241,7 @@ public final class AuditedContexts {
}
safeAudit.onContextCreatedMeta(ctxId, algoId == null ? UNKNOWN : algoId,
- provider == null ? UNKNOWN : provider,
- role, keyFp, specMeta);
+ provider == null ? UNKNOWN : provider, role, keyFp, specMeta);
}
ClassLoader cl = ctx.getClass().getClassLoader(); // NOPMD
@@ -720,8 +718,7 @@ public final class AuditedContexts {
StringBuilder fingerprint = new StringBuilder(16);
for (int index = 0; index < Math.min(8, digest.length); index++) {
int value = digest[index] & 0xff;
- fingerprint.append(Character.forDigit(value >>> 4, 16))
- .append(Character.forDigit(value & 0x0f, 16));
+ fingerprint.append(Character.forDigit(value >>> 4, 16)).append(Character.forDigit(value & 0x0f, 16));
}
return key.getAlgorithm() + ":" + fingerprint;
} catch (NoSuchAlgorithmException exception) {
diff --git a/lib/src/main/java/zeroecho/core/audit/JulAuditListenerStd.java b/lib/src/main/java/zeroecho/core/audit/JulAuditListenerStd.java
index b586911..e661a76 100644
--- a/lib/src/main/java/zeroecho/core/audit/JulAuditListenerStd.java
+++ b/lib/src/main/java/zeroecho/core/audit/JulAuditListenerStd.java
@@ -204,9 +204,9 @@ public final class JulAuditListenerStd implements AuditListener {
* appends a stack trace in addition to the structured summary.
*
*
- * Stack traces may contain provider exception messages or application
- * values. Enabling them is an explicit diagnostic opt-in and requires a
- * suitably protected log destination.
+ * Stack traces may contain provider exception messages or application values.
+ * Enabling them is an explicit diagnostic opt-in and requires a suitably
+ * protected log destination.
*
*
* @param include true to include stack traces, false to omit them
@@ -600,8 +600,7 @@ public final class JulAuditListenerStd implements AuditListener {
StringBuilder sb = new StringBuilder(key.getAlgorithm()).append(':');
for (int i = 0; i < Math.min(8, digest.length); i++) {
int value = digest[i] & 0xff;
- sb.append(Character.forDigit(value >>> 4, 16))
- .append(Character.forDigit(value & 0x0f, 16));
+ sb.append(Character.forDigit(value >>> 4, 16)).append(Character.forDigit(value & 0x0f, 16));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
diff --git a/lib/src/main/java/zeroecho/core/err/UnsupportedRoleException.java b/lib/src/main/java/zeroecho/core/err/UnsupportedRoleException.java
index 3711286..2172948 100644
--- a/lib/src/main/java/zeroecho/core/err/UnsupportedRoleException.java
+++ b/lib/src/main/java/zeroecho/core/err/UnsupportedRoleException.java
@@ -46,13 +46,11 @@ package zeroecho.core.err;
* When it is thrown
*
* - During
- * {@link zeroecho.sdk.ZeroEchoSession#createContext(String,
- * zeroecho.core.KeyUsage, java.security.Key, zeroecho.core.spec.ContextSpec)}
+ * {@link zeroecho.sdk.ZeroEchoSession#createContext(String, zeroecho.core.KeyUsage, java.security.Key, zeroecho.core.spec.ContextSpec)}
* after policy validation, if the resolved algorithm exposes no bindings for
* the given role.
* - Directly from
- * {@link zeroecho.core.CryptoAlgorithm#createContext(zeroecho.core.KeyUsage,
- * java.security.Key, zeroecho.core.spec.ContextSpec)}
+ * {@link zeroecho.core.CryptoAlgorithm#createContext(zeroecho.core.KeyUsage, java.security.Key, zeroecho.core.spec.ContextSpec)}
* when no binding exists for the role.
*
*
diff --git a/lib/src/main/java/zeroecho/core/io/AbstractChunkTransformInputStream.java b/lib/src/main/java/zeroecho/core/io/AbstractChunkTransformInputStream.java
index bf3088b..0816e1b 100644
--- a/lib/src/main/java/zeroecho/core/io/AbstractChunkTransformInputStream.java
+++ b/lib/src/main/java/zeroecho/core/io/AbstractChunkTransformInputStream.java
@@ -157,8 +157,8 @@ public abstract class AbstractChunkTransformInputStream extends FilterInputStrea
* @param outChunkSize size of output chunks produced by the transform (must be
* > 0)
* @param chunks number of chunks buffered at once (must be > 0)
- * @throws IllegalArgumentException if a size is outside its documented range
- * or a buffer size overflows
+ * @throws IllegalArgumentException if a size is outside its documented range or
+ * a buffer size overflows
*/
protected AbstractChunkTransformInputStream(InputStream upstream, int inChunkSize, int outChunkSize, int chunks) {
super(upstream);
@@ -190,8 +190,8 @@ public abstract class AbstractChunkTransformInputStream extends FilterInputStrea
* steady-state (must be > 0)
* @param finalizationOutputChunks number of extra output chunks reserved for
* finalization (must be >= 0)
- * @throws IllegalArgumentException if a size is outside its documented range
- * or a buffer size overflows
+ * @throws IllegalArgumentException if a size is outside its documented range or
+ * a buffer size overflows
*/
protected AbstractChunkTransformInputStream(InputStream upstream, int inChunkSize, int outChunkSize, int chunks,
int finalizationOutputChunks) {
@@ -261,8 +261,7 @@ public abstract class AbstractChunkTransformInputStream extends FilterInputStrea
// EOF: run finalization exactly once, even if there's no remainder,
// and surface any produced bytes (e.g., padding block, GCM tag).
if (!eofSeen) {
- int finalOut = validateOutputCount(doFinal(inBuf, 0, 0, outBuf, 0), outBuf.length,
- "finalization");
+ int finalOut = validateOutputCount(doFinal(inBuf, 0, 0, outBuf, 0), outBuf.length, "finalization");
outPtr = 0;
outLen = finalOut;
eofSeen = true;
@@ -273,8 +272,7 @@ public abstract class AbstractChunkTransformInputStream extends FilterInputStrea
// all chunks are aligned to the specified boundary (inChunkSize) -> transform
// can be simply invoked
- outLen = validateOutputCount(transform(inBuf, 0, inLen / inChunkSize, outBuf), outBuf.length,
- "transformation");
+ outLen = validateOutputCount(transform(inBuf, 0, inLen / inChunkSize, outBuf), outBuf.length, "transformation");
outPtr = 0;
int left = inLen % inChunkSize;
@@ -291,8 +289,7 @@ public abstract class AbstractChunkTransformInputStream extends FilterInputStrea
return true;
}
- private static void validateGeometry(int inChunkSize, int outChunkSize, int chunks,
- int finalizationOutputChunks) {
+ private static void validateGeometry(int inChunkSize, int outChunkSize, int chunks, int finalizationOutputChunks) {
if (inChunkSize < MIN_INPUT_CHUNK_SIZE) {
throw new IllegalArgumentException("inChunkSize must be greater than 1");
}
diff --git a/lib/src/main/java/zeroecho/core/io/CipherTransformInputStreamBuilder.java b/lib/src/main/java/zeroecho/core/io/CipherTransformInputStreamBuilder.java
index c1ca971..1c92cd0 100644
--- a/lib/src/main/java/zeroecho/core/io/CipherTransformInputStreamBuilder.java
+++ b/lib/src/main/java/zeroecho/core/io/CipherTransformInputStreamBuilder.java
@@ -53,13 +53,12 @@ import javax.crypto.Cipher;
* block; a final partial block (if any) is processed by a single
* {@code doFinal}. This mode is restricted to RSA and ElGamal.
* Left-padded independent block stream - like the independent block
- * stream, but
- * left-pads each transformed output block with zeros up to
+ * stream, but left-pads each transformed output block with zeros up to
* {@code outChunkSize}. Final blocks must be complete; otherwise an
* {@link IllegalStateException} is thrown.
- * Continuous stream - uses
- * {@code Cipher.update(...)} for bulk bytes and a single {@code doFinal()} at
- * end of stream. This is suitable for CTR/CFB/OFB/GCM and padding modes.
+ * Continuous stream - uses {@code Cipher.update(...)} for bulk bytes
+ * and a single {@code doFinal()} at end of stream. This is suitable for
+ * CTR/CFB/OFB/GCM and padding modes.
*
*
* Block sizing
@@ -344,7 +343,8 @@ public final class CipherTransformInputStreamBuilder {
*
*
* @return a new InputStream that transforms bytes on the fly
- * @throws NullPointerException if {@code upstream} or {@code cipher} is null
+ * @throws NullPointerException if {@code upstream} or {@code cipher} is
+ * null
* @throws IllegalArgumentException if independent-block processing is selected
* for an unsupported algorithm or buffer
* geometry is invalid
diff --git a/lib/src/main/java/zeroecho/core/io/SmartBlockStream.java b/lib/src/main/java/zeroecho/core/io/SmartBlockStream.java
index 876c195..cb3fa10 100644
--- a/lib/src/main/java/zeroecho/core/io/SmartBlockStream.java
+++ b/lib/src/main/java/zeroecho/core/io/SmartBlockStream.java
@@ -58,6 +58,7 @@ final class SmartBlockStream extends AbstractChunkTransformInputStream {
private static final Logger LOG = Logger.getLogger(SmartBlockStream.class.getName());
private final Cipher cipher;
+
/* package */ SmartBlockStream(InputStream upstream, Cipher cipher, int inChunkSize, int outChunkSize,
int bufferedBlocks) {
super(upstream, inChunkSize, outChunkSize, bufferedBlocks);
diff --git a/lib/src/main/java/zeroecho/core/io/SmartPaddedBlockStream.java b/lib/src/main/java/zeroecho/core/io/SmartPaddedBlockStream.java
index 0087cbe..f48fce2 100644
--- a/lib/src/main/java/zeroecho/core/io/SmartPaddedBlockStream.java
+++ b/lib/src/main/java/zeroecho/core/io/SmartPaddedBlockStream.java
@@ -59,6 +59,7 @@ final class SmartPaddedBlockStream extends AbstractChunkTransformInputStream {
private static final Logger LOG = Logger.getLogger(SmartPaddedBlockStream.class.getName());
private final Cipher cipher;
+
/* package */ SmartPaddedBlockStream(InputStream upstream, Cipher cipher, int inChunkSize, int outChunkSize,
int bufferedBlocks) {
super(upstream, inChunkSize, outChunkSize, bufferedBlocks);
diff --git a/lib/src/main/java/zeroecho/core/io/package-info.java b/lib/src/main/java/zeroecho/core/io/package-info.java
index 09ed79a..2b088f3 100644
--- a/lib/src/main/java/zeroecho/core/io/package-info.java
+++ b/lib/src/main/java/zeroecho/core/io/package-info.java
@@ -54,12 +54,12 @@
* then calls {@code onCompleted()} exactly once at EOF.
* {@link CipherTransformInputStreamBuilder} - fluent builder that creates
* cipher-backed streams for RSA/ElGamal independent-block processing,
- * left-zero-padded independent blocks, or
- * continuous {@code update}+{@code doFinal} streaming.
+ * left-zero-padded independent blocks, or continuous
+ * {@code update}+{@code doFinal} streaming.
* {@link SmartBlockStream}, {@link SmartPaddedBlockStream},
* {@link SmartContinuousBlockStream} - internal cipher-backed stream variants;
- * the first two are restricted to independent RSA or ElGamal blocks
- * used by the builder.
+ * the first two are restricted to independent RSA or ElGamal blocks used by the
+ * builder.
* {@link TailStrippingInputStream} - withholds the last N bytes from the
* payload and delivers them to a callback at EOF (useful for tags, checksums,
* or footers).
diff --git a/lib/src/main/java/zeroecho/core/marshal/PairSeq.java b/lib/src/main/java/zeroecho/core/marshal/PairSeq.java
index b0a72fd..72a5385 100644
--- a/lib/src/main/java/zeroecho/core/marshal/PairSeq.java
+++ b/lib/src/main/java/zeroecho/core/marshal/PairSeq.java
@@ -61,8 +61,8 @@ import java.util.List;
*
* Serialization
*
- * - {@link #writeTo(Appendable)} outputs each pair as {@code k=v\n}
- * lines without escaping and reports checked I/O failures.
+ * - {@link #writeTo(Appendable)} outputs each pair as {@code k=v\n} lines
+ * without escaping and reports checked I/O failures.
* - {@link #readFrom(java.io.Reader)} parses lines in the same format,
* ignoring blank lines and comments starting with {@code #}.
*
@@ -99,8 +99,7 @@ public final class PairSeq {
if (kv[elementIndex] == null) {
int pairIndex = elementIndex >>> 1;
String role = (elementIndex & 1) == 0 ? "key" : "value";
- throw new IllegalArgumentException(
- "pair " + pairIndex + " " + role + " must not be null");
+ throw new IllegalArgumentException("pair " + pairIndex + " " + role + " must not be null");
}
}
return new PairSeq(kv.clone());
@@ -201,8 +200,8 @@ public final class PairSeq {
}
/**
- * Appends all pairs to the target as {@code key=value} lines, reporting
- * checked I/O failures directly.
+ * Appends all pairs to the target as {@code key=value} lines, reporting checked
+ * I/O failures directly.
*
*
* No escaping is performed; callers must ensure keys and values do not contain
diff --git a/lib/src/main/java/zeroecho/core/marshal/PairSeqCodec.java b/lib/src/main/java/zeroecho/core/marshal/PairSeqCodec.java
index c6e280f..1628b8c 100644
--- a/lib/src/main/java/zeroecho/core/marshal/PairSeqCodec.java
+++ b/lib/src/main/java/zeroecho/core/marshal/PairSeqCodec.java
@@ -101,9 +101,9 @@ import java.util.function.Supplier;
* }
*
*
Thread-safety
Instances are immutable and thread-safe. Public
- * accessors are resolved once per runtime class and operation type, then invoked
- * through cached method handles. The unload-safe {@link ClassValue} caches do
- * not retain otherwise unreachable class loaders.
+ * accessors are resolved once per runtime class and operation type, then
+ * invoked through cached method handles. The unload-safe {@link ClassValue}
+ * caches do not retain otherwise unreachable class loaders.
*
* @param domain type that follows the marshalling and unmarshalling
* conventions
@@ -274,8 +274,7 @@ public final class PairSeqCodec implements Codec {
try {
Method method = runtimeType.getMethod("marshal");
if (!PairSeq.class.isAssignableFrom(method.getReturnType())) {
- return new MarshalPlan(null,
- "marshal() must return PairSeq in " + runtimeType.getName(), null);
+ return new MarshalPlan(null, "marshal() must return PairSeq in " + runtimeType.getName(), null);
}
MethodHandle handle = MethodHandles.lookup().unreflect(method);
return new MarshalPlan(handle, null, null);
@@ -327,14 +326,14 @@ public final class PairSeqCodec implements Codec {
"static unmarshal(PairSeq) must return " + runtimeType.getName(), null);
}
MethodHandle handle = MethodHandles.lookup().unreflect(method);
- return new UnmarshalPlan(handle,
- "static unmarshal(PairSeq) failed for " + runtimeType.getName(), null, null);
+ return new UnmarshalPlan(handle, "static unmarshal(PairSeq) failed for " + runtimeType.getName(),
+ null, null);
}
} catch (NoSuchMethodException ignored) {
// Resolve the constructor fallback below.
} catch (IllegalAccessException exception) {
- return new UnmarshalPlan(null, null,
- "static unmarshal(PairSeq) failed for " + runtimeType.getName(), exception);
+ return new UnmarshalPlan(null, null, "static unmarshal(PairSeq) failed for " + runtimeType.getName(),
+ exception);
}
try {
diff --git a/lib/src/main/java/zeroecho/core/spec/AlgorithmKeySpec.java b/lib/src/main/java/zeroecho/core/spec/AlgorithmKeySpec.java
index c7eaf76..f59bcaf 100644
--- a/lib/src/main/java/zeroecho/core/spec/AlgorithmKeySpec.java
+++ b/lib/src/main/java/zeroecho/core/spec/AlgorithmKeySpec.java
@@ -33,7 +33,6 @@
******************************************************************************/
package zeroecho.core.spec;
-
/**
* Marker interface for algorithm-specific key specifications.
*
diff --git a/lib/src/main/java/zeroecho/core/spi/AsymmetricKeyPairGenerator.java b/lib/src/main/java/zeroecho/core/spi/AsymmetricKeyPairGenerator.java
index 804d81d..232cca5 100644
--- a/lib/src/main/java/zeroecho/core/spi/AsymmetricKeyPairGenerator.java
+++ b/lib/src/main/java/zeroecho/core/spi/AsymmetricKeyPairGenerator.java
@@ -11,7 +11,8 @@ import zeroecho.core.spec.AlgorithmKeySpec;
/**
* Generates asymmetric key pairs for one exact specification type.
- * Implementations must be stateless or otherwise safe for concurrent invocation.
+ * Implementations must be stateless or otherwise safe for concurrent
+ * invocation.
*
* @param specification type
* @since 1.0
diff --git a/lib/src/main/java/zeroecho/core/spi/ContextFactoryKS.java b/lib/src/main/java/zeroecho/core/spi/ContextFactoryKS.java
index 2af71e3..81db075 100644
--- a/lib/src/main/java/zeroecho/core/spi/ContextFactoryKS.java
+++ b/lib/src/main/java/zeroecho/core/spi/ContextFactoryKS.java
@@ -15,11 +15,13 @@ import zeroecho.core.spec.ContextSpec;
/**
* Creates a cryptographic context from a key and a context specification.
*
- *
Implementations report provider and parameter failures with unchecked
+ *
+ * Implementations report provider and parameter failures with unchecked
* exceptions; context construction is a pure in-memory operation and does not
* expose an I/O failure contract. Factories must be stateless or otherwise safe
* for concurrent invocation; returned contexts retain their own documented
- * thread-safety contracts.
+ * thread-safety contracts.
+ *
*
* @param context type produced
* @param key type accepted
@@ -31,7 +33,7 @@ public interface ContextFactoryKSOwnership of the returned object transfers to the receiver, which must
+ *
+ * Ownership of the returned object transfers to the receiver, which must
* destroy it in a {@code finally} block immediately after the keyring has been
* opened. Implementations must not source passwords from immutable strings,
* process arguments, system properties, environment fallbacks, persistent
- * files, or global mutable state.
+ * files, or global mutable state.
+ *
*/
@FunctionalInterface
public interface KeyringUnlockProvider {
diff --git a/lib/src/main/java/zeroecho/core/spi/PrivateKeyImporter.java b/lib/src/main/java/zeroecho/core/spi/PrivateKeyImporter.java
index 6cb7c44..f05ffd0 100644
--- a/lib/src/main/java/zeroecho/core/spi/PrivateKeyImporter.java
+++ b/lib/src/main/java/zeroecho/core/spi/PrivateKeyImporter.java
@@ -10,8 +10,8 @@ import java.security.PrivateKey;
import zeroecho.core.spec.AlgorithmKeySpec;
/**
- * Imports private keys for one exact specification type. Implementations must be
- * stateless or otherwise safe for concurrent invocation.
+ * Imports private keys for one exact specification type. Implementations must
+ * be stateless or otherwise safe for concurrent invocation.
*
* @param specification type
* @since 1.0
diff --git a/lib/src/main/java/zeroecho/core/spi/package-info.java b/lib/src/main/java/zeroecho/core/spi/package-info.java
index 896d4bf..f4071e0 100644
--- a/lib/src/main/java/zeroecho/core/spi/package-info.java
+++ b/lib/src/main/java/zeroecho/core/spi/package-info.java
@@ -34,20 +34,26 @@
/**
* Provider contracts for context construction and exact key operations.
*
- * Algorithms bind each supported role to a {@link ContextFactoryKS}. Context
+ *
+ * Algorithms bind each supported role to a {@link ContextFactoryKS}. Context
* construction is an in-memory operation; stream attachment and processing are
- * responsible for reporting {@link java.io.IOException}.
+ * responsible for reporting {@link java.io.IOException}.
+ *
*
- * Key capabilities are registered independently through
+ *
+ * Key capabilities are registered independently through
* {@link SymmetricKeyGenerator}, {@link SymmetricKeyImporter},
* {@link AsymmetricKeyPairGenerator}, {@link PublicKeyImporter}, and
* {@link PrivateKeyImporter}. A provider registers only the operations it
* implements, so capability lookup fails before invocation instead of returning
- * an object with unsupported methods.
+ * an object with unsupported methods.
+ *
*
- * SPI implementations should be stateless or otherwise safe for concurrent
+ *
+ * SPI implementations should be stateless or otherwise safe for concurrent
* lookup and invocation. Created cryptographic contexts remain operation-local
- * and are not necessarily thread-safe.
+ * and are not necessarily thread-safe.
+ *
*
* @since 1.0
*/
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringException.java b/lib/src/main/java/zeroecho/core/storage/KeyringException.java
index a8c4133..6fb1d8d 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringException.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringException.java
@@ -10,9 +10,11 @@ import java.util.Objects;
/**
* Redacted checked failure raised by encrypted keyring operations.
*
- * The public message contains only the stable error code. Filesystem paths,
+ *
+ * The public message contains only the stable error code. Filesystem paths,
* aliases, key material, ciphertext, and provider-controlled messages are
- * deliberately excluded.
+ * deliberately excluded.
+ *
*/
public final class KeyringException extends IOException {
private static final long serialVersionUID = 1L;
@@ -21,17 +23,9 @@ public final class KeyringException extends IOException {
* Stable keyring failure categories.
*/
public enum Code {
- KEYRING_ALREADY_OPEN,
- KEYRING_FILESYSTEM_UNSUPPORTED,
- KEYRING_FORMAT_INVALID,
- KEYRING_LIMIT_EXCEEDED,
- KEYRING_UNLOCK_FAILED,
- KEYRING_IO_FAILED,
- KEYRING_DURABILITY_UNCONFIRMED,
- KEYRING_CLOSED,
- KEYRING_NON_EXPORTABLE_KEY,
- KEYRING_IMPORT_MAPPING_INVALID,
- KEYRING_IMPORT_METADATA_INVALID,
+ KEYRING_ALREADY_OPEN, KEYRING_FILESYSTEM_UNSUPPORTED, KEYRING_FORMAT_INVALID, KEYRING_LIMIT_EXCEEDED,
+ KEYRING_UNLOCK_FAILED, KEYRING_IO_FAILED, KEYRING_DURABILITY_UNCONFIRMED, KEYRING_CLOSED,
+ KEYRING_NON_EXPORTABLE_KEY, KEYRING_IMPORT_MAPPING_INVALID, KEYRING_IMPORT_METADATA_INVALID,
KEYRING_KEY_NOT_CANONICALIZABLE
}
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringFileOperations.java b/lib/src/main/java/zeroecho/core/storage/KeyringFileOperations.java
index 957185e..1d9567a 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringFileOperations.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringFileOperations.java
@@ -24,8 +24,7 @@ interface KeyringFileOperations {
/** Atomic persistence destination. */
enum Target {
- MAIN_IMAGE,
- NONCE_RESERVATION
+ MAIN_IMAGE, NONCE_RESERVATION
}
/** Creates one owner-only temporary file beside its destination. */
@@ -57,10 +56,8 @@ final class NioKeyringFileOperations implements KeyringFileOperations {
}
@Override
- public void writeTemporary(Target target, Path temporary, byte[] image)
- throws IOException {
- try (FileChannel channel = FileChannel.open(temporary,
- StandardOpenOption.WRITE, LinkOption.NOFOLLOW_LINKS)) {
+ public void writeTemporary(Target target, Path temporary, byte[] image) throws IOException {
+ try (FileChannel channel = FileChannel.open(temporary, StandardOpenOption.WRITE, LinkOption.NOFOLLOW_LINKS)) {
ByteBuffer buffer = ByteBuffer.wrap(image);
while (buffer.hasRemaining()) {
channel.write(buffer);
@@ -70,17 +67,14 @@ final class NioKeyringFileOperations implements KeyringFileOperations {
@Override
public void forceTemporary(Target target, Path temporary) throws IOException {
- try (FileChannel channel = FileChannel.open(temporary,
- StandardOpenOption.WRITE, LinkOption.NOFOLLOW_LINKS)) {
+ try (FileChannel channel = FileChannel.open(temporary, StandardOpenOption.WRITE, LinkOption.NOFOLLOW_LINKS)) {
channel.force(true);
}
}
@Override
- public void atomicReplace(Target target, Path temporary, Path destination)
- throws IOException {
- Files.move(temporary, destination, StandardCopyOption.ATOMIC_MOVE,
- StandardCopyOption.REPLACE_EXISTING);
+ public void atomicReplace(Target target, Path temporary, Path destination) throws IOException {
+ Files.move(temporary, destination, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING);
}
@Override
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringImportRegistry.java b/lib/src/main/java/zeroecho/core/storage/KeyringImportRegistry.java
index 552a313..dfdf37b 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringImportRegistry.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringImportRegistry.java
@@ -71,18 +71,18 @@ import zeroecho.core.spi.SymmetricKeyImporter;
* Closed trusted mapping from persistent key identities to canonical registered
* import operations.
*
- * Provider identity is deliberately absent. Standard encoded key material
- * is reconstructed by the current runtime's canonical ZeroEcho importer. The
- * original JCA provider is neither persisted nor reproduced.
+ *
+ * Provider identity is deliberately absent. Standard encoded key material is
+ * reconstructed by the current runtime's canonical ZeroEcho importer. The
+ * original JCA provider is neither persisted nor reproduced.
+ *
*/
final class KeyringImportRegistry {
private static final String ALGORITHM_AES = "AES";
private static final String ALGORITHM_HMAC = "HMAC";
private static final String ALGORITHM_CHACHA20 = "CHACHA20";
private static final String ALGORITHM_CHACHA20_POLY1305 = "CHACHA20-POLY1305";
- private static final Map,
- Function> SPEC_FACTORIES =
- createSpecFactories();
+ private static final Map, Function> SPEC_FACTORIES = createSpecFactories();
private static final Map MAPPINGS = createMappings();
private KeyringImportRegistry() {
@@ -93,10 +93,7 @@ final class KeyringImportRegistry {
*/
/* default */
enum HmacVariant {
- NONE(0, null),
- SHA256(1, "HmacSHA256"),
- SHA384(2, "HmacSHA384"),
- SHA512(3, "HmacSHA512");
+ NONE(0, null), SHA256(1, "HmacSHA256"), SHA384(2, "HmacSHA384"), SHA512(3, "HmacSHA512");
private final int code;
private final String jcaName;
@@ -123,8 +120,7 @@ final class KeyringImportRegistry {
throw new KeyringException(KeyringException.Code.KEYRING_IMPORT_METADATA_INVALID);
}
- /* default */ static HmacVariant forStoredKey(String algorithmId, Key key)
- throws KeyringException {
+ /* default */ static HmacVariant forStoredKey(String algorithmId, Key key) throws KeyringException {
if (!ALGORITHM_HMAC.equals(algorithmId)) {
return NONE;
}
@@ -142,21 +138,19 @@ final class KeyringImportRegistry {
* Immutable description used by the finite importer-matrix test.
*
* @param algorithmId canonical ZeroEcho algorithm identifier
- * @param kind key kind
- * @param encoding standard encoding
+ * @param kind key kind
+ * @param encoding standard encoding
* @param hmacVariant closed HMAC variant, or {@link HmacVariant#NONE}
- * @param specType exact registered importer specification type
+ * @param specType exact registered importer specification type
*/
/* default */
- record PersistentMapping(String algorithmId, KeyringStore.Kind kind,
- KeyringStore.Encoding encoding, HmacVariant hmacVariant,
- Class extends AlgorithmKeySpec> specType) {
+ record PersistentMapping(String algorithmId, KeyringStore.Kind kind, KeyringStore.Encoding encoding,
+ HmacVariant hmacVariant, Class extends AlgorithmKeySpec> specType) {
}
@SuppressWarnings("PMD.AvoidCatchingGenericException")
- /* default */ static Key importKey(String algorithmId, KeyringStore.Kind kind,
- KeyringStore.Encoding encoding, HmacVariant hmacVariant, byte[] encoded)
- throws GeneralSecurityException, KeyringException {
+ /* default */ static Key importKey(String algorithmId, KeyringStore.Kind kind, KeyringStore.Encoding encoding,
+ HmacVariant hmacVariant, byte[] encoded) throws GeneralSecurityException, KeyringException {
PersistentMapping mapping = requireMapping(algorithmId, kind, encoding, hmacVariant);
CryptoAlgorithm algorithm = requireAlgorithm(mapping.algorithmId);
AlgorithmKeySpec spec = createSpec(mapping, encoded);
@@ -172,8 +166,7 @@ final class KeyringImportRegistry {
}
/* default */ static void validateMapping(String algorithmId, KeyringStore.Kind kind,
- KeyringStore.Encoding encoding, HmacVariant hmacVariant)
- throws KeyringException {
+ KeyringStore.Encoding encoding, HmacVariant hmacVariant) throws KeyringException {
PersistentMapping mapping = requireMapping(algorithmId, kind, encoding, hmacVariant);
CryptoAlgorithm algorithm = requireAlgorithm(mapping.algorithmId);
List operations = matchingOperations(algorithm, kind);
@@ -184,27 +177,23 @@ final class KeyringImportRegistry {
@SuppressWarnings({ "PMD.PreserveStackTrace", "PMD.AvoidCatchingGenericException" })
/* default */ static void validateCanonical(String algorithmId, KeyringStore.Kind kind,
- KeyringStore.Encoding encoding, HmacVariant hmacVariant, Key source,
- byte[] encoded)
+ KeyringStore.Encoding encoding, HmacVariant hmacVariant, Key source, byte[] encoded)
throws KeyringException {
Key imported = null;
byte[] canonical = null;
try {
if (!matchesSourceAlgorithm(source, algorithmId, hmacVariant)) {
- throw new KeyringException(
- KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE);
+ throw new KeyringException(KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE);
}
imported = importKey(algorithmId, kind, encoding, hmacVariant, encoded);
canonical = imported.getEncoded();
if (canonical == null || !matchesFormat(imported.getFormat(), encoding)
|| !MessageDigest.isEqual(encoded, canonical)
|| !matchesAlgorithm(imported, algorithmId, hmacVariant)) {
- throw new KeyringException(
- KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE);
+ throw new KeyringException(KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE);
}
} catch (GeneralSecurityException | RuntimeException exception) {
- throw new KeyringException(
- KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE);
+ throw new KeyringException(KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE);
} finally {
if (canonical != null) {
Arrays.fill(canonical, (byte) 0);
@@ -217,11 +206,9 @@ final class KeyringImportRegistry {
return List.copyOf(MAPPINGS.values());
}
- private static PersistentMapping requireMapping(String algorithmId,
- KeyringStore.Kind kind, KeyringStore.Encoding encoding,
- HmacVariant hmacVariant) throws KeyringException {
- PersistentMapping mapping = MAPPINGS.get(
- new Tuple(algorithmId, kind, encoding, hmacVariant));
+ private static PersistentMapping requireMapping(String algorithmId, KeyringStore.Kind kind,
+ KeyringStore.Encoding encoding, HmacVariant hmacVariant) throws KeyringException {
+ PersistentMapping mapping = MAPPINGS.get(new Tuple(algorithmId, kind, encoding, hmacVariant));
if (mapping == null) {
throw new KeyringException(KeyringException.Code.KEYRING_IMPORT_MAPPING_INVALID);
}
@@ -229,8 +216,7 @@ final class KeyringImportRegistry {
}
@SuppressWarnings("PMD.PreserveStackTrace")
- private static CryptoAlgorithm requireAlgorithm(String algorithmId)
- throws KeyringException {
+ private static CryptoAlgorithm requireAlgorithm(String algorithmId) throws KeyringException {
try {
return CryptoAlgorithms.require(algorithmId);
} catch (IllegalArgumentException exception) {
@@ -238,11 +224,8 @@ final class KeyringImportRegistry {
}
}
- private static List matchingOperations(CryptoAlgorithm algorithm,
- KeyringStore.Kind kind) {
- return algorithm.keyOperations().stream()
- .filter(info -> info.operation() == operation(kind))
- .toList();
+ private static List matchingOperations(CryptoAlgorithm algorithm, KeyringStore.Kind kind) {
+ return algorithm.keyOperations().stream().filter(info -> info.operation() == operation(kind)).toList();
}
private static KeyOperation operation(KeyringStore.Kind kind) {
@@ -254,25 +237,22 @@ final class KeyringImportRegistry {
}
@SuppressWarnings({ "rawtypes", "unchecked" })
- private static Key invokeImporter(CryptoAlgorithm algorithm, KeyringStore.Kind kind,
- AlgorithmKeySpec spec) throws GeneralSecurityException {
+ private static Key invokeImporter(CryptoAlgorithm algorithm, KeyringStore.Kind kind, AlgorithmKeySpec spec)
+ throws GeneralSecurityException {
return switch (kind) {
- case PUBLIC_KEY -> ((PublicKeyImporter) algorithm.publicKeyImporter(spec.getClass()))
- .importPublic(spec);
- case PRIVATE_KEY -> ((PrivateKeyImporter) algorithm.privateKeyImporter(spec.getClass()))
- .importPrivate(spec);
- case SECRET_KEY -> ((SymmetricKeyImporter) algorithm.symmetricKeyImporter(spec.getClass()))
- .importSecret(spec);
+ case PUBLIC_KEY -> ((PublicKeyImporter) algorithm.publicKeyImporter(spec.getClass())).importPublic(spec);
+ case PRIVATE_KEY ->
+ ((PrivateKeyImporter) algorithm.privateKeyImporter(spec.getClass())).importPrivate(spec);
+ case SECRET_KEY ->
+ ((SymmetricKeyImporter) algorithm.symmetricKeyImporter(spec.getClass())).importSecret(spec);
};
}
- private static AlgorithmKeySpec createSpec(PersistentMapping mapping, byte[] encoded)
- throws KeyringException {
+ private static AlgorithmKeySpec createSpec(PersistentMapping mapping, byte[] encoded) throws KeyringException {
if (mapping.specType == HmacKeyImportSpec.class) {
return new HmacKeyImportSpec(mapping.hmacVariant.jcaName, encoded);
}
- Function factory =
- SPEC_FACTORIES.get(mapping.specType);
+ Function factory = SPEC_FACTORIES.get(mapping.specType);
AlgorithmKeySpec result = factory == null ? null : factory.apply(encoded);
if (result == null) {
throw new KeyringException(KeyringException.Code.KEYRING_IMPORT_MAPPING_INVALID);
@@ -288,31 +268,27 @@ final class KeyringImportRegistry {
};
}
- private static boolean matchesAlgorithm(Key imported, String algorithmId,
- HmacVariant hmacVariant) {
+ private static boolean matchesAlgorithm(Key imported, String algorithmId, HmacVariant hmacVariant) {
if (ALGORITHM_HMAC.equals(algorithmId)) {
return hmacVariant.jcaName.equals(imported.getAlgorithm());
}
if (ALGORITHM_AES.equals(algorithmId)) {
return ALGORITHM_AES.equals(imported.getAlgorithm());
}
- if (ALGORITHM_CHACHA20.equals(algorithmId)
- || ALGORITHM_CHACHA20_POLY1305.equals(algorithmId)) {
+ if (ALGORITHM_CHACHA20.equals(algorithmId) || ALGORITHM_CHACHA20_POLY1305.equals(algorithmId)) {
return "ChaCha20".equals(imported.getAlgorithm());
}
return true;
}
- private static boolean matchesSourceAlgorithm(Key source, String algorithmId,
- HmacVariant hmacVariant) {
+ private static boolean matchesSourceAlgorithm(Key source, String algorithmId, HmacVariant hmacVariant) {
if (ALGORITHM_HMAC.equals(algorithmId)) {
return hmacVariant.jcaName.equals(source.getAlgorithm());
}
if (ALGORITHM_AES.equals(algorithmId)) {
return ALGORITHM_AES.equals(source.getAlgorithm());
}
- if (ALGORITHM_CHACHA20.equals(algorithmId)
- || ALGORITHM_CHACHA20_POLY1305.equals(algorithmId)) {
+ if (ALGORITHM_CHACHA20.equals(algorithmId) || ALGORITHM_CHACHA20_POLY1305.equals(algorithmId)) {
return "ChaCha20".equals(source.getAlgorithm());
}
return true;
@@ -329,10 +305,8 @@ final class KeyringImportRegistry {
}
}
- private static Map,
- Function> createSpecFactories() {
- return Map.ofEntries(
- Map.entry(AesKeyImportSpec.class, AesKeyImportSpec::fromRaw),
+ private static Map, Function> createSpecFactories() {
+ return Map.ofEntries(Map.entry(AesKeyImportSpec.class, AesKeyImportSpec::fromRaw),
Map.entry(ChaChaKeyImportSpec.class, ChaChaKeyImportSpec::fromRaw),
Map.entry(BikePublicKeySpec.class, BikePublicKeySpec::new),
Map.entry(BikePrivateKeySpec.class, BikePrivateKeySpec::new),
@@ -380,73 +354,54 @@ final class KeyringImportRegistry {
addAsymmetric(mappings, "CMCE", CmcePublicKeySpec.class, CmcePrivateKeySpec.class);
addAsymmetric(mappings, "DH", DhPublicKeySpec.class, DhPrivateKeySpec.class);
addAsymmetric(mappings, "ECDSA", EcdsaPublicKeySpec.class, EcdsaPrivateKeySpec.class);
- addAsymmetric(mappings, "Ed25519", Ed25519PublicKeySpec.class,
- Ed25519PrivateKeySpec.class);
- addAsymmetric(mappings, "Ed448", Ed448PublicKeySpec.class,
- Ed448PrivateKeySpec.class);
- addAsymmetric(mappings, "ElGamal", ElgamalPublicKeySpec.class,
- ElgamalPrivateKeySpec.class);
- addAsymmetric(mappings, "Frodo", FrodoPublicKeySpec.class,
- FrodoPrivateKeySpec.class);
+ addAsymmetric(mappings, "Ed25519", Ed25519PublicKeySpec.class, Ed25519PrivateKeySpec.class);
+ addAsymmetric(mappings, "Ed448", Ed448PublicKeySpec.class, Ed448PrivateKeySpec.class);
+ addAsymmetric(mappings, "ElGamal", ElgamalPublicKeySpec.class, ElgamalPrivateKeySpec.class);
+ addAsymmetric(mappings, "Frodo", FrodoPublicKeySpec.class, FrodoPrivateKeySpec.class);
addAsymmetric(mappings, "HQC", HqcPublicKeySpec.class, HqcPrivateKeySpec.class);
- addAsymmetric(mappings, "ML-KEM", KyberPublicKeySpec.class,
- KyberPrivateKeySpec.class);
- addAsymmetric(mappings, "ML-DSA", MldsaPublicKeySpec.class,
- MldsaPrivateKeySpec.class);
+ addAsymmetric(mappings, "ML-KEM", KyberPublicKeySpec.class, KyberPrivateKeySpec.class);
+ addAsymmetric(mappings, "ML-DSA", MldsaPublicKeySpec.class, MldsaPrivateKeySpec.class);
addAsymmetric(mappings, "NTRU", NtruPublicKeySpec.class, NtruPrivateKeySpec.class);
- addAsymmetric(mappings, "NTRULPRime", NtrulPrimePublicKeySpec.class,
- NtrulPrimePrivateKeySpec.class);
- addAsymmetric(mappings, "SNTRUPrime", SntruPrimePublicKeySpec.class,
- SntruPrimePrivateKeySpec.class);
+ addAsymmetric(mappings, "NTRULPRime", NtrulPrimePublicKeySpec.class, NtrulPrimePrivateKeySpec.class);
+ addAsymmetric(mappings, "SNTRUPrime", SntruPrimePublicKeySpec.class, SntruPrimePrivateKeySpec.class);
addAsymmetric(mappings, "RSA", RsaPublicKeySpec.class, RsaPrivateKeySpec.class);
- addAsymmetric(mappings, "SABER", SaberPublicKeySpec.class,
- SaberPrivateKeySpec.class);
- addAsymmetric(mappings, "SLH-DSA", SlhDsaPublicKeySpec.class,
- SlhDsaPrivateKeySpec.class);
- addAsymmetric(mappings, "SPHINCS+", SphincsPlusPublicKeySpec.class,
- SphincsPlusPrivateKeySpec.class);
+ addAsymmetric(mappings, "SABER", SaberPublicKeySpec.class, SaberPrivateKeySpec.class);
+ addAsymmetric(mappings, "SLH-DSA", SlhDsaPublicKeySpec.class, SlhDsaPrivateKeySpec.class);
+ addAsymmetric(mappings, "SPHINCS+", SphincsPlusPublicKeySpec.class, SphincsPlusPrivateKeySpec.class);
addAsymmetric(mappings, "Xdh", XdhPublicKeySpec.class, XdhPrivateKeySpec.class);
- add(mappings, ALGORITHM_AES, KeyringStore.Kind.SECRET_KEY,
- KeyringStore.Encoding.RAW,
- HmacVariant.NONE, AesKeyImportSpec.class);
- add(mappings, ALGORITHM_CHACHA20, KeyringStore.Kind.SECRET_KEY,
- KeyringStore.Encoding.RAW,
+ add(mappings, ALGORITHM_AES, KeyringStore.Kind.SECRET_KEY, KeyringStore.Encoding.RAW, HmacVariant.NONE,
+ AesKeyImportSpec.class);
+ add(mappings, ALGORITHM_CHACHA20, KeyringStore.Kind.SECRET_KEY, KeyringStore.Encoding.RAW, HmacVariant.NONE,
+ ChaChaKeyImportSpec.class);
+ add(mappings, ALGORITHM_CHACHA20_POLY1305, KeyringStore.Kind.SECRET_KEY, KeyringStore.Encoding.RAW,
HmacVariant.NONE, ChaChaKeyImportSpec.class);
- add(mappings, ALGORITHM_CHACHA20_POLY1305, KeyringStore.Kind.SECRET_KEY,
- KeyringStore.Encoding.RAW, HmacVariant.NONE, ChaChaKeyImportSpec.class);
- add(mappings, ALGORITHM_HMAC, KeyringStore.Kind.SECRET_KEY,
- KeyringStore.Encoding.RAW,
- HmacVariant.SHA256, HmacKeyImportSpec.class);
- add(mappings, ALGORITHM_HMAC, KeyringStore.Kind.SECRET_KEY,
- KeyringStore.Encoding.RAW,
- HmacVariant.SHA384, HmacKeyImportSpec.class);
- add(mappings, ALGORITHM_HMAC, KeyringStore.Kind.SECRET_KEY,
- KeyringStore.Encoding.RAW,
- HmacVariant.SHA512, HmacKeyImportSpec.class);
+ add(mappings, ALGORITHM_HMAC, KeyringStore.Kind.SECRET_KEY, KeyringStore.Encoding.RAW, HmacVariant.SHA256,
+ HmacKeyImportSpec.class);
+ add(mappings, ALGORITHM_HMAC, KeyringStore.Kind.SECRET_KEY, KeyringStore.Encoding.RAW, HmacVariant.SHA384,
+ HmacKeyImportSpec.class);
+ add(mappings, ALGORITHM_HMAC, KeyringStore.Kind.SECRET_KEY, KeyringStore.Encoding.RAW, HmacVariant.SHA512,
+ HmacKeyImportSpec.class);
return Collections.unmodifiableMap(mappings);
}
- private static void addAsymmetric(Map mappings,
- String algorithmId, Class extends AlgorithmKeySpec> publicSpec,
- Class extends AlgorithmKeySpec> privateSpec) {
- add(mappings, algorithmId, KeyringStore.Kind.PUBLIC_KEY,
- KeyringStore.Encoding.X509, HmacVariant.NONE, publicSpec);
- add(mappings, algorithmId, KeyringStore.Kind.PRIVATE_KEY,
- KeyringStore.Encoding.PKCS8, HmacVariant.NONE, privateSpec);
+ private static void addAsymmetric(Map mappings, String algorithmId,
+ Class extends AlgorithmKeySpec> publicSpec, Class extends AlgorithmKeySpec> privateSpec) {
+ add(mappings, algorithmId, KeyringStore.Kind.PUBLIC_KEY, KeyringStore.Encoding.X509, HmacVariant.NONE,
+ publicSpec);
+ add(mappings, algorithmId, KeyringStore.Kind.PRIVATE_KEY, KeyringStore.Encoding.PKCS8, HmacVariant.NONE,
+ privateSpec);
}
- private static void add(Map mappings, String algorithmId,
- KeyringStore.Kind kind, KeyringStore.Encoding encoding,
- HmacVariant hmacVariant, Class extends AlgorithmKeySpec> specType) {
+ private static void add(Map mappings, String algorithmId, KeyringStore.Kind kind,
+ KeyringStore.Encoding encoding, HmacVariant hmacVariant, Class extends AlgorithmKeySpec> specType) {
Tuple tuple = new Tuple(algorithmId, kind, encoding, hmacVariant);
- PersistentMapping mapping = new PersistentMapping(algorithmId, kind,
- encoding, hmacVariant, specType);
+ PersistentMapping mapping = new PersistentMapping(algorithmId, kind, encoding, hmacVariant, specType);
if (mappings.put(tuple, mapping) != null) {
throw new IllegalStateException("Duplicate persistent key importer tuple");
}
}
- private record Tuple(String algorithmId, KeyringStore.Kind kind,
- KeyringStore.Encoding encoding, HmacVariant hmacVariant) {
+ private record Tuple(String algorithmId, KeyringStore.Kind kind, KeyringStore.Encoding encoding,
+ HmacVariant hmacVariant) {
}
}
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringNonceReservationKdf.java b/lib/src/main/java/zeroecho/core/storage/KeyringNonceReservationKdf.java
index ff0872b..959a35e 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringNonceReservationKdf.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringNonceReservationKdf.java
@@ -19,8 +19,7 @@ final class KeyringNonceReservationKdf {
private static final int STORE_ID_BYTES = 16;
private static final int OUTPUT_BYTES = 32;
private static final String HMAC_SHA256 = "HmacSHA256";
- private static final String DOMAIN_LABEL =
- "zeroecho:keyring:nonce-reservation-mac:v1";
+ private static final String DOMAIN_LABEL = "zeroecho:keyring:nonce-reservation-mac:v1";
private KeyringNonceReservationKdf() {
}
@@ -29,14 +28,13 @@ final class KeyringNonceReservationKdf {
* Derives the store-specific nonce-reservation MAC key.
*
* @param masterKey borrowed 256-bit store master key
- * @param storeId borrowed canonical 128-bit binary store UUID
+ * @param storeId borrowed canonical 128-bit binary store UUID
* @return newly owned 256-bit derived key
* @throws GeneralSecurityException if HMAC-SHA-256 is unavailable
*/
- /* default */ static byte[] derive(byte[] masterKey, byte[] storeId)
- throws GeneralSecurityException {
- if (masterKey == null || masterKey.length != MASTER_KEY_BYTES
- || storeId == null || storeId.length != STORE_ID_BYTES) {
+ /* default */ static byte[] derive(byte[] masterKey, byte[] storeId) throws GeneralSecurityException {
+ if (masterKey == null || masterKey.length != MASTER_KEY_BYTES || storeId == null
+ || storeId.length != STORE_ID_BYTES) {
throw new IllegalArgumentException("Invalid keyring derivation input");
}
byte[] salt = storeId.clone();
@@ -61,8 +59,7 @@ final class KeyringNonceReservationKdf {
}
}
- private static byte[] hmac(byte[] key, byte[] input)
- throws GeneralSecurityException {
+ private static byte[] hmac(byte[] key, byte[] input) throws GeneralSecurityException {
Mac mac = Mac.getInstance(HMAC_SHA256);
mac.init(new SecretKeySpec(key, HMAC_SHA256));
return mac.doFinal(input);
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringPassword.java b/lib/src/main/java/zeroecho/core/storage/KeyringPassword.java
index 2eb7049..437164c 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringPassword.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringPassword.java
@@ -14,14 +14,18 @@ import javax.security.auth.Destroyable;
/**
* Destroyable owner of a keyring password.
*
- * The constructor and {@link #copy()} use defensive copies. Callers retain
+ *
+ * The constructor and {@link #copy()} use defensive copies. Callers retain
* ownership of the array supplied to the constructor and must clear it. The
* returned copy belongs to the receiver and must be cleared immediately after
* key derivation. This object never creates an immutable password
- * {@link String}.
+ * {@link String}.
+ *
*
- * Instances are thread-safe. Destruction is idempotent and makes subsequent
- * access fail deterministically.
+ *
+ * Instances are thread-safe. Destruction is idempotent and makes subsequent
+ * access fail deterministically.
+ *
*/
public final class KeyringPassword implements Destroyable, AutoCloseable {
private final ReentrantLock lifecycleLock = new ReentrantLock();
@@ -32,7 +36,7 @@ public final class KeyringPassword implements Destroyable, AutoCloseable {
* Creates a password owner.
*
* @param password password characters, which are defensively copied
- * @throws NullPointerException if {@code password} is {@code null}
+ * @throws NullPointerException if {@code password} is {@code null}
* @throws IllegalArgumentException if {@code password} is empty
*/
@SuppressWarnings("PMD.UseVarargs")
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringProtection.java b/lib/src/main/java/zeroecho/core/storage/KeyringProtection.java
index bfea301..26362f8 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringProtection.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringProtection.java
@@ -8,7 +8,8 @@ package zeroecho.core.storage;
* Operational limits applied while opening an encrypted software keyring.
*
* @param operationalIterationMaximum maximum accepted PBKDF2 iteration count;
- * it may restrict but never exceed the absolute decoded maximum
+ * it may restrict but never exceed the
+ * absolute decoded maximum
*/
public record KeyringProtection(int operationalIterationMaximum) {
/** Iterations used when a new keyring is created. */
@@ -21,8 +22,8 @@ public record KeyringProtection(int operationalIterationMaximum) {
/**
* Validates the operational limit.
*
- * @throws IllegalArgumentException if the limit is below the creation
- * setting or above the absolute operational maximum
+ * @throws IllegalArgumentException if the limit is below the creation setting
+ * or above the absolute operational maximum
*/
public KeyringProtection {
if (operationalIterationMaximum < CREATION_ITERATIONS
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringRandomBytes.java b/lib/src/main/java/zeroecho/core/storage/KeyringRandomBytes.java
index 7223bc3..2eb7b68 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringRandomBytes.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringRandomBytes.java
@@ -7,8 +7,10 @@ package zeroecho.core.storage;
/**
* Fills keyring randomness buffers.
*
- * This package-private seam supports deterministic format tests; production
- * creation uses the authoritative shared secure random source.
+ *
+ * This package-private seam supports deterministic format tests; production
+ * creation uses the authoritative shared secure random source.
+ *
*/
@FunctionalInterface
interface KeyringRandomBytes {
diff --git a/lib/src/main/java/zeroecho/core/storage/KeyringStore.java b/lib/src/main/java/zeroecho/core/storage/KeyringStore.java
index 310fa6e..dae4c4d 100644
--- a/lib/src/main/java/zeroecho/core/storage/KeyringStore.java
+++ b/lib/src/main/java/zeroecho/core/storage/KeyringStore.java
@@ -65,35 +65,44 @@ import zeroecho.core.util.RandomSupport;
/**
* Path-bound encrypted local software keystore.
*
- * A keyring uses PBKDF2-HMAC-SHA-256 to unwrap one random 256-bit store
- * master key. Every entry and the ordered manifest are independently protected
- * by AES-256-GCM. Java class names are neither persisted nor resolved. Import
+ *
+ * A keyring uses PBKDF2-HMAC-SHA-256 to unwrap one random 256-bit store master
+ * key. Every entry and the ordered manifest are independently protected by
+ * AES-256-GCM. Java class names are neither persisted nor resolved. Import
* mappings come exclusively from a closed mapping to the immutable algorithm
* registry. Provider names are not persisted: standard key encodings are
* reconstructed by the current runtime's canonical importer. HMAC persistence
- * admits only HmacSHA256, HmacSHA384, and HmacSHA512.
+ * admits only HmacSHA256, HmacSHA384, and HmacSHA512.
+ *
*
- * The keyring exclusively owns its filesystem path from successful
+ *
+ * The keyring exclusively owns its filesystem path from successful
* {@link #create(Path, KeyringPassword)} or
* {@link #open(Path, KeyringPassword)} until {@link #close()}. Only POSIX
* filesystems on which owner-only permissions and ownership can be verified are
- * supported. Mutations replace a complete encrypted image atomically.
+ * supported. Mutations replace a complete encrypted image atomically.
+ *
*
- * The nonce-reservation sidecar is authenticated independently from AES
- * entry and manifest encryption. Its 256-bit MAC key is derived from the store
- * master key and binary store UUID with HKDF-HMAC-SHA-256 and the fixed domain
- * label {@code zeroecho:keyring:nonce-reservation-mac:v1}. The derived key is
+ *
+ * The nonce-reservation sidecar is authenticated independently from AES entry
+ * and manifest encryption. Its 256-bit MAC key is derived from the store master
+ * key and binary store UUID with HKDF-HMAC-SHA-256 and the fixed domain label
+ * {@code zeroecho:keyring:nonce-reservation-mac:v1}. The derived key is
* retained only while the store is open and is cleared on close. Previous
- * sidecar versions are rejected.
+ * sidecar versions are rejected.
+ *
*
- * Instances are thread-safe. Reads may proceed concurrently; mutations and
+ *
+ * Instances are thread-safe. Reads may proceed concurrently; mutations and
* close are exclusive. Closing clears the master and sidecar MAC keys and makes
* all subsequent operations fail. The pre-release plaintext format is rejected
- * and is not migrated.
+ * and is not migrated.
+ *
*/
// The store intentionally centralizes its closed format, crypto, and lifecycle types.
@SuppressWarnings("PMD.CouplingBetweenObjects")
-public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
+public final class KeyringStore implements AutoCloseable, Destroyable {
+ // NOPMD
/* default */ static final byte[] MAGIC = { 'Z', 'E', 'K', 'R', 'I', 'N', 'G', '2' };
/* default */ static final int FORMAT_VERSION = 2;
/* default */ static final int ENTRY_FORMAT_VERSION = 1;
@@ -113,8 +122,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/* default */ static final int SHA256_BYTES = 32;
/* default */ static final byte KDF_PBKDF2_SHA256 = 1;
/* default */ static final byte AEAD_AES_256_GCM = 1;
- private static final byte[] NONCE_RESERVATION_MAGIC =
- { 'Z', 'E', 'K', 'N', 'O', 'N', 'C', '2' };
+ private static final byte[] NONCE_RESERVATION_MAGIC = { 'Z', 'E', 'K', 'N', 'O', 'N', 'C', '2' };
private static final int NONCE_RESERVATION_VERSION = 2;
private static final int NONCE_RESERVATION_TAG_BYTES = 32;
private static final byte MASTER_WRAP_NONCE_DOMAIN = 1;
@@ -123,17 +131,16 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
private static final String SUFFIX_PUBLIC = ".pub";
private static final String SUFFIX_PRIVATE = ".priv";
private static final long MIN_NONCE_HIGH_WATER = 1L;
- private static final Set DIRECTORY_PERMISSIONS =
- EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE,
- PosixFilePermission.OWNER_EXECUTE);
- private static final Set FILE_PERMISSIONS =
- EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE);
- private static final FileAttribute> DIRECTORY_ATTRIBUTE =
- PosixFilePermissions.asFileAttribute(DIRECTORY_PERMISSIONS);
- private static final FileAttribute> FILE_ATTRIBUTE =
- PosixFilePermissions.asFileAttribute(FILE_PERMISSIONS);
- private static final KeyringRandomBytes SYSTEM_RANDOM = destination ->
- RandomSupport.getRandom().nextBytes(destination);
+ private static final Set DIRECTORY_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
+ PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);
+ private static final Set FILE_PERMISSIONS = EnumSet.of(PosixFilePermission.OWNER_READ,
+ PosixFilePermission.OWNER_WRITE);
+ private static final FileAttribute> DIRECTORY_ATTRIBUTE = PosixFilePermissions
+ .asFileAttribute(DIRECTORY_PERMISSIONS);
+ private static final FileAttribute> FILE_ATTRIBUTE = PosixFilePermissions
+ .asFileAttribute(FILE_PERMISSIONS);
+ private static final KeyringRandomBytes SYSTEM_RANDOM = destination -> RandomSupport.getRandom()
+ .nextBytes(destination);
private final Path path;
private final Path nonceReservationPath;
private final Ownership ownership;
@@ -157,9 +164,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
* Standard encoded key forms supported by the encrypted store.
*/
public enum Encoding {
- X509(1),
- PKCS8(2),
- RAW(3);
+ X509(1), PKCS8(2), RAW(3);
private final int code;
@@ -181,9 +186,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
* Key classifications supported by the encrypted store.
*/
public enum Kind {
- PUBLIC_KEY(1),
- PRIVATE_KEY(2),
- SECRET_KEY(3);
+ PUBLIC_KEY(1), PRIVATE_KEY(2), SECRET_KEY(3);
private final int code;
@@ -201,11 +204,9 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private KeyringStore(Path path, Ownership ownership,
- KeyringRandomBytes random, KeyringFileOperations fileOperations,
- Header header, byte[] masterKey,
- byte[] nonceReservationMacKey, Manifest manifest,
- Map entries) {
+ private KeyringStore(Path path, Ownership ownership, KeyringRandomBytes random,
+ KeyringFileOperations fileOperations, Header header, byte[] masterKey, byte[] nonceReservationMacKey,
+ Manifest manifest, Map entries) {
this.path = path;
this.nonceReservationPath = nonceReservationPath(path);
this.ownership = ownership;
@@ -226,11 +227,12 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/**
* Creates a new encrypted keyring with the standard protection policy.
*
- * @param path new keyring file
- * @param password borrowed unlock password; the caller remains responsible
- * for destroying it
+ * @param path new keyring file
+ * @param password borrowed unlock password; the caller remains responsible for
+ * destroying it
* @return open encrypted keyring
- * @throws IOException if secure creation or durable persistence fails
+ * @throws IOException if secure creation or durable persistence
+ * fails
* @throws GeneralSecurityException if cryptographic initialization fails
*/
public static KeyringStore create(Path path, KeyringPassword password)
@@ -241,28 +243,27 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/**
* Creates a new encrypted keyring.
*
- * @param path new keyring file
- * @param password borrowed unlock password
+ * @param path new keyring file
+ * @param password borrowed unlock password
* @param protection operational protection policy
* @return open encrypted keyring
- * @throws IOException if secure creation or durable persistence fails
+ * @throws IOException if secure creation or durable persistence
+ * fails
* @throws GeneralSecurityException if cryptographic initialization fails
*/
- public static KeyringStore create(Path path, KeyringPassword password,
- KeyringProtection protection) throws IOException, GeneralSecurityException {
+ public static KeyringStore create(Path path, KeyringPassword password, KeyringProtection protection)
+ throws IOException, GeneralSecurityException {
return create(path, password, protection, SYSTEM_RANDOM);
}
- /* default */ static KeyringStore create(Path path, KeyringPassword password,
- KeyringProtection protection, KeyringRandomBytes random)
- throws IOException, GeneralSecurityException {
+ /* default */ static KeyringStore create(Path path, KeyringPassword password, KeyringProtection protection,
+ KeyringRandomBytes random) throws IOException, GeneralSecurityException {
return create(path, password, protection, random, KeyringFileOperations.NIO);
}
@SuppressWarnings({ "PMD.CloseResource", "PMD.UseTryWithResources" })
- /* default */ static KeyringStore create(Path path, KeyringPassword password,
- KeyringProtection protection, KeyringRandomBytes random,
- KeyringFileOperations fileOperations)
+ /* default */ static KeyringStore create(Path path, KeyringPassword password, KeyringProtection protection,
+ KeyringRandomBytes random, KeyringFileOperations fileOperations)
throws IOException, GeneralSecurityException {
Objects.requireNonNull(password, "password must not be null");
Objects.requireNonNull(protection, "protection must not be null");
@@ -287,19 +288,18 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
random.nextBytes(masterKey);
random.nextBytes(salt);
random.nextBytes(storeId);
- nonceReservationMacKey =
- KeyringNonceReservationKdf.derive(masterKey, storeId);
+ nonceReservationMacKey = KeyringNonceReservationKdf.derive(masterKey, storeId);
fillMasterWrapNonce(random, wrapNonce);
int prefix = randomPrefix(random);
- Header provisional = new Header(storeId, KeyringProtection.CREATION_ITERATIONS,
- salt, wrapNonce, new byte[0]);
+ Header provisional = new Header(storeId, KeyringProtection.CREATION_ITERATIONS, salt, wrapNonce,
+ new byte[0]);
aad = masterWrapAad(provisional);
kek = deriveKek(password, salt, provisional.iterations);
wrapped = crypt(Cipher.ENCRYPT_MODE, kek, wrapNonce, aad, masterKey);
Header header = new Header(storeId, provisional.iterations, salt, wrapNonce, wrapped);
Manifest initial = new Manifest(prefix, 0, List.of());
- store = new KeyringStore(normalized, ownership, random, fileOperations, header,
- masterKey, nonceReservationMacKey, initial, new LinkedHashMap<>());
+ store = new KeyringStore(normalized, ownership, random, fileOperations, header, masterKey,
+ nonceReservationMacKey, initial, new LinkedHashMap<>());
store.persistSnapshot(new LinkedHashMap<>());
success = true;
return store;
@@ -325,44 +325,41 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/**
* Opens an encrypted keyring with the standard protection policy.
*
- * @param path keyring file
+ * @param path keyring file
* @param password borrowed unlock password
* @return open encrypted keyring
- * @throws IOException if the format, filesystem, or authentication check
- * fails
+ * @throws IOException if the format, filesystem, or authentication
+ * check fails
* @throws GeneralSecurityException if cryptographic initialization fails
*/
- public static KeyringStore open(Path path, KeyringPassword password)
- throws IOException, GeneralSecurityException {
+ public static KeyringStore open(Path path, KeyringPassword password) throws IOException, GeneralSecurityException {
return open(path, password, KeyringProtection.standard());
}
/**
* Opens an encrypted keyring.
*
- * @param path keyring file
- * @param password borrowed unlock password
+ * @param path keyring file
+ * @param password borrowed unlock password
* @param protection operational protection policy
* @return open encrypted keyring
- * @throws IOException if the format, filesystem, or authentication check
- * fails
+ * @throws IOException if the format, filesystem, or authentication
+ * check fails
* @throws GeneralSecurityException if cryptographic initialization fails
*/
- public static KeyringStore open(Path path, KeyringPassword password,
- KeyringProtection protection) throws IOException, GeneralSecurityException {
+ public static KeyringStore open(Path path, KeyringPassword password, KeyringProtection protection)
+ throws IOException, GeneralSecurityException {
return open(path, password, protection, SYSTEM_RANDOM);
}
- /* default */ static KeyringStore open(Path path, KeyringPassword password,
- KeyringProtection protection, KeyringRandomBytes random)
- throws IOException, GeneralSecurityException {
+ /* default */ static KeyringStore open(Path path, KeyringPassword password, KeyringProtection protection,
+ KeyringRandomBytes random) throws IOException, GeneralSecurityException {
return open(path, password, protection, random, KeyringFileOperations.NIO);
}
@SuppressWarnings({ "PMD.CloseResource", "PMD.UseTryWithResources" })
- /* default */ static KeyringStore open(Path path, KeyringPassword password,
- KeyringProtection protection, KeyringRandomBytes random,
- KeyringFileOperations fileOperations)
+ /* default */ static KeyringStore open(Path path, KeyringPassword password, KeyringProtection protection,
+ KeyringRandomBytes random, KeyringFileOperations fileOperations)
throws IOException, GeneralSecurityException {
Objects.requireNonNull(password, "password must not be null");
Objects.requireNonNull(protection, "protection must not be null");
@@ -379,19 +376,16 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
image = readStoreImage(normalized);
Decoded decoded = decodeImage(image, password, protection);
masterKey = decoded.masterKey;
- nonceReservationMacKey = KeyringNonceReservationKdf.derive(
- masterKey, decoded.header.storeId);
- long reservedHighWater = readNonceReservation(normalized, ownership.owner(),
- decoded.header.storeId, decoded.manifest.noncePrefix,
- nonceReservationMacKey);
+ nonceReservationMacKey = KeyringNonceReservationKdf.derive(masterKey, decoded.header.storeId);
+ long reservedHighWater = readNonceReservation(normalized, ownership.owner(), decoded.header.storeId,
+ decoded.manifest.noncePrefix, nonceReservationMacKey);
if (reservedHighWater < decoded.manifest.highWater) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
- Manifest effectiveManifest = new Manifest(decoded.manifest.noncePrefix,
- reservedHighWater, decoded.manifest.entries);
- KeyringStore store = new KeyringStore(normalized, ownership,
- random, fileOperations, decoded.header, masterKey, nonceReservationMacKey,
- effectiveManifest, decoded.entries);
+ Manifest effectiveManifest = new Manifest(decoded.manifest.noncePrefix, reservedHighWater,
+ decoded.manifest.entries);
+ KeyringStore store = new KeyringStore(normalized, ownership, random, fileOperations, decoded.header,
+ masterKey, nonceReservationMacKey, effectiveManifest, decoded.entries);
success = true;
return store;
} finally {
@@ -407,10 +401,10 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/**
* Adds or replaces an encoded public key and persists the mutation.
*
- * @param alias logical alias
+ * @param alias logical alias
* @param algorithmId canonical registered algorithm identifier
- * @param key exportable public key
- * @throws IOException if validation or durable persistence fails
+ * @param key exportable public key
+ * @throws IOException if validation or durable persistence fails
* @throws GeneralSecurityException if entry encryption fails
*/
public void putPublic(String alias, String algorithmId, PublicKey key)
@@ -422,10 +416,10 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/**
* Adds or replaces an encoded private key and persists the mutation.
*
- * @param alias logical alias
+ * @param alias logical alias
* @param algorithmId canonical registered algorithm identifier
- * @param key exportable private key
- * @throws IOException if validation or durable persistence fails
+ * @param key exportable private key
+ * @throws IOException if validation or durable persistence fails
* @throws GeneralSecurityException if entry encryption fails
*/
public void putPrivate(String alias, String algorithmId, PrivateKey key)
@@ -437,17 +431,17 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/**
* Adds or replaces an encoded secret key and persists the mutation.
*
- * @param alias logical alias
+ * @param alias logical alias
* @param algorithmId canonical registered algorithm identifier
- * @param key exportable secret key
- * @throws IOException if validation or durable persistence fails
+ * @param key exportable secret key
+ * @throws IOException if validation or durable persistence fails
* @throws GeneralSecurityException if entry encryption fails
*/
public void putSecret(String alias, String algorithmId, SecretKey key)
throws IOException, GeneralSecurityException {
Objects.requireNonNull(key, "key must not be null");
- KeyringImportRegistry.HmacVariant hmacVariant =
- KeyringImportRegistry.HmacVariant.forStoredKey(algorithmId, key);
+ KeyringImportRegistry.HmacVariant hmacVariant = KeyringImportRegistry.HmacVariant.forStoredKey(algorithmId,
+ key);
put(alias, algorithmId, Kind.SECRET_KEY, Encoding.RAW, key, hmacVariant);
}
@@ -497,7 +491,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
*
* @param alias logical alias
* @return imported key and algorithm
- * @throws IOException if the entry cannot be authenticated
+ * @throws IOException if the entry cannot be authenticated
* @throws GeneralSecurityException if decryption or import fails
*/
public PublicWithId getPublicWithId(String alias) throws IOException, GeneralSecurityException {
@@ -510,7 +504,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
*
* @param alias logical alias
* @return imported key and algorithm
- * @throws IOException if the entry cannot be authenticated
+ * @throws IOException if the entry cannot be authenticated
* @throws GeneralSecurityException if decryption or import fails
*/
public PrivateWithId getPrivateWithId(String alias) throws IOException, GeneralSecurityException {
@@ -523,7 +517,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
*
* @param alias logical alias
* @return imported key and algorithm
- * @throws IOException if the entry cannot be authenticated
+ * @throws IOException if the entry cannot be authenticated
* @throws GeneralSecurityException if decryption or import fails
*/
public SecretWithId getSecretWithId(String alias) throws IOException, GeneralSecurityException {
@@ -536,7 +530,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
*
* @param alias logical alias
* @return imported public key
- * @throws IOException if the entry cannot be authenticated
+ * @throws IOException if the entry cannot be authenticated
* @throws GeneralSecurityException if decryption or import fails
*/
public PublicKey getPublic(String alias) throws IOException, GeneralSecurityException {
@@ -548,7 +542,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
*
* @param alias logical alias
* @return imported private key
- * @throws IOException if the entry cannot be authenticated
+ * @throws IOException if the entry cannot be authenticated
* @throws GeneralSecurityException if decryption or import fails
*/
public PrivateKey getPrivate(String alias) throws IOException, GeneralSecurityException {
@@ -560,7 +554,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
*
* @param alias logical alias
* @return imported secret key
- * @throws IOException if the entry cannot be authenticated
+ * @throws IOException if the entry cannot be authenticated
* @throws GeneralSecurityException if decryption or import fails
*/
public SecretKey getSecret(String alias) throws IOException, GeneralSecurityException {
@@ -571,7 +565,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
* Algorithm identifier paired with an imported public key.
*
* @param algorithm canonical algorithm identifier
- * @param key imported key
+ * @param key imported key
*/
public record PublicWithId(String algorithm, PublicKey key) {
}
@@ -580,7 +574,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
* Algorithm identifier paired with an imported private key.
*
* @param algorithm canonical algorithm identifier
- * @param key imported key
+ * @param key imported key
*/
public record PrivateWithId(String algorithm, PrivateKey key) {
}
@@ -589,7 +583,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
* Algorithm identifier paired with an imported secret key.
*
* @param algorithm canonical algorithm identifier
- * @param key imported key
+ * @param key imported key
*/
public record SecretWithId(String algorithm, SecretKey key) {
}
@@ -598,7 +592,9 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
* Clears the master and nonce-reservation MAC keys and releases filesystem
* ownership.
*
- * Concurrent calls are safe and cleanup occurs exactly once.
+ *
+ * Concurrent calls are safe and cleanup occurs exactly once.
+ *
*
* @throws DestroyFailedException if resource release fails
*/
@@ -647,9 +643,8 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private void put(String alias, String algorithmId, Kind kind, Encoding encoding,
- Key key, KeyringImportRegistry.HmacVariant hmacVariant)
- throws IOException, GeneralSecurityException {
+ private void put(String alias, String algorithmId, Kind kind, Encoding encoding, Key key,
+ KeyringImportRegistry.HmacVariant hmacVariant) throws IOException, GeneralSecurityException {
Objects.requireNonNull(key, "key must not be null");
validateString(alias, MAX_ALIAS_BYTES);
validateString(algorithmId, MAX_METADATA_BYTES);
@@ -663,8 +658,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
throw new KeyringException(Code.KEYRING_NON_EXPORTABLE_KEY);
}
try {
- KeyringImportRegistry.validateCanonical(algorithmId, kind, encoding,
- hmacVariant, key, encoded);
+ KeyringImportRegistry.validateCanonical(algorithmId, kind, encoding, hmacVariant, key, encoded);
lifecycleLock.writeLock().lock();
try {
ensureOpen();
@@ -680,16 +674,14 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
byte[] aad = null;
byte[] ciphertext = null;
try {
- plaintext = encodeEntryPlaintext(alias, algorithmId, kind, encoding,
- hmacVariant, encoded);
+ plaintext = encodeEntryPlaintext(alias, algorithmId, kind, encoding, hmacVariant, encoded);
aad = entryAad(entryId, position);
ciphertext = crypt(Cipher.ENCRYPT_MODE, masterKey, nonce, aad, plaintext);
if (ciphertext.length > MAX_ENTRY_CIPHERTEXT_BYTES) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
}
- EncryptedEntry entry = new EncryptedEntry(entryId, position, alias,
- algorithmId, kind, encoding, hmacVariant, nonce, ciphertext,
- digest(ciphertext));
+ EncryptedEntry entry = new EncryptedEntry(entryId, position, alias, algorithmId, kind, encoding,
+ hmacVariant, nonce, ciphertext, digest(ciphertext));
candidate.put(alias, entry);
persistSnapshot(candidate);
entries = candidate;
@@ -709,8 +701,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
@SuppressWarnings("PMD.PreserveStackTrace")
- private Imported importEntry(String alias, Kind expected)
- throws IOException, GeneralSecurityException {
+ private Imported importEntry(String alias, Kind expected) throws IOException, GeneralSecurityException {
lifecycleLock.readLock().lock();
try {
ensureOpen();
@@ -726,8 +717,8 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
plaintext = crypt(Cipher.DECRYPT_MODE, masterKey, entry.nonce, aad, entry.ciphertext);
decoded = decodeEntryPlaintext(plaintext);
validateEntryBinding(entry, decoded);
- Key key = KeyringImportRegistry.importKey(decoded.algorithm, decoded.kind,
- decoded.encoding, decoded.hmacVariant, decoded.encoded);
+ Key key = KeyringImportRegistry.importKey(decoded.algorithm, decoded.kind, decoded.encoding,
+ decoded.hmacVariant, decoded.encoded);
return new Imported(decoded.algorithm, key);
} catch (AEADBadTagException exception) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
@@ -743,8 +734,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private void persistSnapshot(Map candidate)
- throws IOException, GeneralSecurityException {
+ private void persistSnapshot(Map candidate) throws IOException, GeneralSecurityException {
byte[] manifestNonce = null;
byte[] manifestPlain = null;
byte[] manifestAad = null;
@@ -754,8 +744,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
manifestNonce = nextNonce();
manifestPlain = encodeManifest(candidate);
manifestAad = manifestAad(candidate.size());
- manifestCipher = crypt(Cipher.ENCRYPT_MODE, masterKey, manifestNonce,
- manifestAad, manifestPlain);
+ manifestCipher = crypt(Cipher.ENCRYPT_MODE, masterKey, manifestNonce, manifestAad, manifestPlain);
image = encodeImage(candidate, manifestNonce, manifestCipher);
writeAtomically(image);
} catch (IOException | GeneralSecurityException exception) {
@@ -780,15 +769,14 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
@SuppressWarnings({ "PMD.PreserveStackTrace", "PMD.ExceptionAsFlowControl" })
- private void writeAtomically(Target target, Path destination, byte[] image)
- throws IOException {
+ private void writeAtomically(Target target, Path destination, byte[] image) throws IOException {
Path parent = destination.getParent();
Path temporary = null;
boolean moved = false;
IOException primary = null;
try {
- temporary = fileOperations.createTemporary(target, parent,
- "." + destination.getFileName() + ".", ".tmp", FILE_ATTRIBUTE);
+ temporary = fileOperations.createTemporary(target, parent, "." + destination.getFileName() + ".", ".tmp",
+ FILE_ATTRIBUTE);
validateOwnerOnly(temporary, false);
fileOperations.writeTemporary(target, temporary, image);
fileOperations.forceTemporary(target, temporary);
@@ -844,15 +832,13 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private void writeNonceReservation(long highWater)
- throws IOException, GeneralSecurityException {
+ private void writeNonceReservation(long highWater) throws IOException, GeneralSecurityException {
byte[] authenticated = encodeNonceReservation(storeId, noncePrefix, highWater);
byte[] tag = null;
byte[] image = null;
try {
tag = hmac(nonceReservationMacKey, authenticated);
- image = ByteBuffer.allocate(authenticated.length + tag.length)
- .put(authenticated).put(tag).array();
+ image = ByteBuffer.allocate(authenticated.length + tag.length).put(authenticated).put(tag).array();
writeSidecarAtomically(nonceReservationPath, image);
} finally {
wipe(authenticated);
@@ -861,19 +847,14 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private static long readNonceReservation(Path keyring, UserPrincipal owner,
- byte[] expectedStoreId, int expectedPrefix,
- byte[] nonceReservationMacKey)
- throws IOException, GeneralSecurityException {
+ private static long readNonceReservation(Path keyring, UserPrincipal owner, byte[] expectedStoreId,
+ int expectedPrefix, byte[] nonceReservationMacKey) throws IOException, GeneralSecurityException {
Path reservation = nonceReservationPath(keyring);
validateExistingFile(reservation, owner);
- byte[] image = readFixedImage(reservation,
- NONCE_RESERVATION_MAGIC.length + Integer.BYTES + UUID_BYTES
- + Integer.BYTES + Long.BYTES + NONCE_RESERVATION_TAG_BYTES);
- byte[] authenticated = Arrays.copyOf(image,
- image.length - NONCE_RESERVATION_TAG_BYTES);
- byte[] actualTag = Arrays.copyOfRange(image,
- authenticated.length, image.length);
+ byte[] image = readFixedImage(reservation, NONCE_RESERVATION_MAGIC.length + Integer.BYTES + UUID_BYTES
+ + Integer.BYTES + Long.BYTES + NONCE_RESERVATION_TAG_BYTES);
+ byte[] authenticated = Arrays.copyOf(image, image.length - NONCE_RESERVATION_TAG_BYTES);
+ byte[] actualTag = Arrays.copyOfRange(image, authenticated.length, image.length);
byte[] expectedTag = null;
try {
expectedTag = hmac(nonceReservationMacKey, authenticated);
@@ -889,11 +870,10 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
int prefix = buffer.getInt();
long highWater = buffer.getLong();
if (!MessageDigest.isEqual(magic, NONCE_RESERVATION_MAGIC)
- || ByteBuffer.wrap(authenticated,
- NONCE_RESERVATION_MAGIC.length, Integer.BYTES).getInt()
- != NONCE_RESERVATION_VERSION
- || !MessageDigest.isEqual(storeId, expectedStoreId)
- || prefix != expectedPrefix || highWater < MIN_NONCE_HIGH_WATER) {
+ || ByteBuffer.wrap(authenticated, NONCE_RESERVATION_MAGIC.length, Integer.BYTES)
+ .getInt() != NONCE_RESERVATION_VERSION
+ || !MessageDigest.isEqual(storeId, expectedStoreId) || prefix != expectedPrefix
+ || highWater < MIN_NONCE_HIGH_WATER) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
return highWater;
@@ -905,20 +885,14 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private static byte[] encodeNonceReservation(byte[] storeId, int prefix,
- long highWater) {
- return ByteBuffer.allocate(NONCE_RESERVATION_MAGIC.length + Integer.BYTES
- + UUID_BYTES + Integer.BYTES + Long.BYTES)
- .put(NONCE_RESERVATION_MAGIC)
- .putInt(NONCE_RESERVATION_VERSION)
- .put(storeId)
- .putInt(prefix)
- .putLong(highWater)
- .array();
+ private static byte[] encodeNonceReservation(byte[] storeId, int prefix, long highWater) {
+ return ByteBuffer
+ .allocate(NONCE_RESERVATION_MAGIC.length + Integer.BYTES + UUID_BYTES + Integer.BYTES + Long.BYTES)
+ .put(NONCE_RESERVATION_MAGIC).putInt(NONCE_RESERVATION_VERSION).put(storeId).putInt(prefix)
+ .putLong(highWater).array();
}
- private static byte[] hmac(byte[] key, byte[] input)
- throws GeneralSecurityException {
+ private static byte[] hmac(byte[] key, byte[] input) throws GeneralSecurityException {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(key, "HmacSHA256"));
return mac.doFinal(input);
@@ -928,8 +902,8 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
writeAtomically(Target.NONCE_RESERVATION, target, image);
}
- private byte[] encodeImage(Map candidate,
- byte[] manifestNonce, byte[] manifestCipher) throws IOException, KeyringException {
+ private byte[] encodeImage(Map candidate, byte[] manifestNonce, byte[] manifestCipher)
+ throws IOException, KeyringException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (DataOutputStream out = new DataOutputStream(bytes)) {
out.write(MAGIC);
@@ -963,8 +937,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
return result;
}
- private byte[] encodeManifest(Map candidate)
- throws IOException {
+ private byte[] encodeManifest(Map candidate) throws IOException {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (DataOutputStream out = new DataOutputStream(bytes)) {
out.writeInt(MANIFEST_FORMAT_VERSION);
@@ -987,11 +960,10 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
return bytes.toByteArray();
}
- @SuppressWarnings({ "PMD.NcssCount", "PMD.CyclomaticComplexity",
- "PMD.PreserveStackTrace", "PMD.ExceptionAsFlowControl",
- "PMD.AvoidCatchingGenericException" })
- private static Decoded decodeImage(byte[] image, KeyringPassword password,
- KeyringProtection protection) throws IOException, GeneralSecurityException {
+ @SuppressWarnings({ "PMD.NcssCount", "PMD.CyclomaticComplexity", "PMD.PreserveStackTrace",
+ "PMD.ExceptionAsFlowControl", "PMD.AvoidCatchingGenericException" })
+ private static Decoded decodeImage(byte[] image, KeyringPassword password, KeyringProtection protection)
+ throws IOException, GeneralSecurityException {
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(image))) {
byte[] magic = readFixed(in, MAGIC.length);
if (!MessageDigest.isEqual(MAGIC, magic)) {
@@ -1014,8 +986,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
if (wrapNonce[0] != MASTER_WRAP_NONCE_DOMAIN) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
- byte[] wrapped = readBoundedBytes(in, MASTER_KEY_BYTES + GCM_TAG_BYTES,
- MASTER_KEY_BYTES + GCM_TAG_BYTES);
+ byte[] wrapped = readBoundedBytes(in, MASTER_KEY_BYTES + GCM_TAG_BYTES, MASTER_KEY_BYTES + GCM_TAG_BYTES);
if (wrapped.length != MASTER_KEY_BYTES + GCM_TAG_BYTES) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
@@ -1047,8 +1018,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
for (int index = 0; index < count; index++) {
byte[] entryId = readFixed(in, UUID_BYTES);
byte[] nonce = readFixed(in, NONCE_BYTES);
- byte[] ciphertext = readBoundedBytes(in, MAX_ENTRY_CIPHERTEXT_BYTES,
- MAX_ENTRY_CIPHERTEXT_BYTES);
+ byte[] ciphertext = readBoundedBytes(in, MAX_ENTRY_CIPHERTEXT_BYTES, MAX_ENTRY_CIPHERTEXT_BYTES);
wireEntries.add(new EncryptedWireEntry(entryId, nonce, ciphertext));
}
byte[] manifestNonce = readFixed(in, NONCE_BYTES);
@@ -1061,14 +1031,12 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
try {
aad = manifestAad(storeId, count);
try {
- manifestPlain = crypt(Cipher.DECRYPT_MODE, masterKey,
- manifestNonce, aad, manifestCipher);
+ manifestPlain = crypt(Cipher.DECRYPT_MODE, masterKey, manifestNonce, aad, manifestCipher);
} catch (AEADBadTagException exception) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
Manifest manifest = decodeManifest(manifestPlain, count);
- Map entries =
- bindManifest(manifest, wireEntries, manifestNonce);
+ Map entries = bindManifest(manifest, wireEntries, manifestNonce);
return new Decoded(header, masterKey, manifest, entries);
} finally {
wipe(aad);
@@ -1086,8 +1054,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
@SuppressWarnings("PMD.PreserveStackTrace")
- private static Manifest decodeManifest(byte[] plaintext, int expectedCount)
- throws IOException {
+ private static Manifest decodeManifest(byte[] plaintext, int expectedCount) throws IOException {
try (DataInputStream in = new DataInputStream(new ByteArrayInputStream(plaintext))) {
if (in.readInt() != MANIFEST_FORMAT_VERSION) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
@@ -1109,16 +1076,16 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
String algorithm = readString(in, MAX_METADATA_BYTES);
Kind kind = Kind.fromCode(in.readUnsignedByte());
Encoding encoding = Encoding.fromCode(in.readUnsignedByte());
- KeyringImportRegistry.HmacVariant hmacVariant =
- KeyringImportRegistry.HmacVariant.fromCode(in.readUnsignedByte());
+ KeyringImportRegistry.HmacVariant hmacVariant = KeyringImportRegistry.HmacVariant
+ .fromCode(in.readUnsignedByte());
byte[] nonce = readFixed(in, NONCE_BYTES);
int length = in.readInt();
if (length < GCM_TAG_BYTES || length > MAX_ENTRY_CIPHERTEXT_BYTES) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
}
byte[] digest = readFixed(in, SHA256_BYTES);
- descriptors.add(new ManifestEntry(entryId, position, alias, algorithm,
- kind, encoding, hmacVariant, nonce, length, digest));
+ descriptors.add(new ManifestEntry(entryId, position, alias, algorithm, kind, encoding, hmacVariant,
+ nonce, length, digest));
}
if (in.read() != -1) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
@@ -1130,9 +1097,8 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
- private static Map bindManifest(Manifest manifest,
- List wireEntries, byte[] manifestNonce)
- throws KeyringException {
+ private static Map bindManifest(Manifest manifest, List wireEntries,
+ byte[] manifestNonce) throws KeyringException {
if (manifest.entries.size() != wireEntries.size()) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
@@ -1145,44 +1111,38 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
for (int index = 0; index < wireEntries.size(); index++) {
ManifestEntry descriptor = manifest.entries.get(index);
EncryptedWireEntry wire = wireEntries.get(index);
- if (descriptor.position != index
- || !MessageDigest.isEqual(descriptor.entryId, wire.entryId)
+ if (descriptor.position != index || !MessageDigest.isEqual(descriptor.entryId, wire.entryId)
|| !MessageDigest.isEqual(descriptor.nonce, wire.nonce)
|| descriptor.ciphertextLength != wire.ciphertext.length
|| !MessageDigest.isEqual(descriptor.digest, digest(wire.ciphertext))) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
validateNonce(wire.nonce, manifest.noncePrefix, manifest.highWater);
- if (!aliases.add(descriptor.alias)
- || !ids.add(uuid(descriptor.entryId))
+ if (!aliases.add(descriptor.alias) || !ids.add(uuid(descriptor.entryId))
|| !nonces.add(new Nonce(wire.nonce))) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
- KeyringImportRegistry.validateMapping(descriptor.algorithm,
- descriptor.kind, descriptor.encoding, descriptor.hmacVariant);
- result.put(descriptor.alias, new EncryptedEntry(wire.entryId, index,
- descriptor.alias, descriptor.algorithm, descriptor.kind,
- descriptor.encoding, descriptor.hmacVariant, wire.nonce,
- wire.ciphertext, descriptor.digest));
+ KeyringImportRegistry.validateMapping(descriptor.algorithm, descriptor.kind, descriptor.encoding,
+ descriptor.hmacVariant);
+ result.put(descriptor.alias,
+ new EncryptedEntry(wire.entryId, index, descriptor.alias, descriptor.algorithm, descriptor.kind,
+ descriptor.encoding, descriptor.hmacVariant, wire.nonce, wire.ciphertext,
+ descriptor.digest));
}
return result;
}
@SuppressWarnings("PMD.PreserveStackTrace")
- private static byte[] encodeEntryPlaintext(String alias, String algorithm,
- Kind kind, Encoding encoding, KeyringImportRegistry.HmacVariant hmacVariant,
- byte[] encoded)
- throws KeyringException {
+ private static byte[] encodeEntryPlaintext(String alias, String algorithm, Kind kind, Encoding encoding,
+ KeyringImportRegistry.HmacVariant hmacVariant, byte[] encoded) throws KeyringException {
if (encoded.length <= 0 || encoded.length > MAX_ENTRY_CIPHERTEXT_BYTES - GCM_TAG_BYTES) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
}
byte[] aliasBytes = alias.getBytes(StandardCharsets.UTF_8);
byte[] algorithmBytes = algorithm.getBytes(StandardCharsets.UTF_8);
try {
- int size = Math.addExact(Integer.BYTES + 3,
- Math.addExact(lengthPrefixedSize(aliasBytes),
- Math.addExact(lengthPrefixedSize(algorithmBytes),
- lengthPrefixedSize(encoded))));
+ int size = Math.addExact(Integer.BYTES + 3, Math.addExact(lengthPrefixedSize(aliasBytes),
+ Math.addExact(lengthPrefixedSize(algorithmBytes), lengthPrefixedSize(encoded))));
if (size > MAX_ENTRY_CIPHERTEXT_BYTES - GCM_TAG_BYTES) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
}
@@ -1222,10 +1182,9 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
String algorithm = readString(in, MAX_METADATA_BYTES);
Kind kind = Kind.fromCode(in.readUnsignedByte());
Encoding encoding = Encoding.fromCode(in.readUnsignedByte());
- KeyringImportRegistry.HmacVariant hmacVariant =
- KeyringImportRegistry.HmacVariant.fromCode(in.readUnsignedByte());
- byte[] encoded = readBoundedBytes(in,
- MAX_ENTRY_CIPHERTEXT_BYTES - GCM_TAG_BYTES,
+ KeyringImportRegistry.HmacVariant hmacVariant = KeyringImportRegistry.HmacVariant
+ .fromCode(in.readUnsignedByte());
+ byte[] encoded = readBoundedBytes(in, MAX_ENTRY_CIPHERTEXT_BYTES - GCM_TAG_BYTES,
MAX_ENTRY_CIPHERTEXT_BYTES - GCM_TAG_BYTES);
if (in.read() != -1) {
wipe(encoded);
@@ -1237,8 +1196,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private static void validateEntryBinding(EncryptedEntry entry, EntryPlain decoded)
- throws KeyringException {
+ private static void validateEntryBinding(EncryptedEntry entry, EntryPlain decoded) throws KeyringException {
if (!entry.alias.equals(decoded.alias) || !entry.algorithm.equals(decoded.algorithm)
|| entry.kind != decoded.kind || entry.encoding != decoded.encoding
|| entry.hmacVariant != decoded.hmacVariant) {
@@ -1305,8 +1263,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
return buffer.array();
}
- private static void validateNonce(byte[] nonce, int prefix, long highWater)
- throws KeyringException {
+ private static void validateNonce(byte[] nonce, int prefix, long highWater) throws KeyringException {
if (nonce.length != NONCE_BYTES) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
@@ -1325,8 +1282,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
byte[] prefix = new byte[3];
try {
random.nextBytes(prefix);
- return (Byte.toUnsignedInt(prefix[0]) << 16)
- | (Byte.toUnsignedInt(prefix[1]) << 8)
+ return (Byte.toUnsignedInt(prefix[0]) << 16) | (Byte.toUnsignedInt(prefix[1]) << 8)
| Byte.toUnsignedInt(prefix[2]);
} finally {
wipe(prefix);
@@ -1351,8 +1307,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
private static int readThreeBytePrefix(ByteBuffer buffer) {
- return (Byte.toUnsignedInt(buffer.get()) << 16)
- | (Byte.toUnsignedInt(buffer.get()) << 8)
+ return (Byte.toUnsignedInt(buffer.get()) << 16) | (Byte.toUnsignedInt(buffer.get()) << 8)
| Byte.toUnsignedInt(buffer.get());
}
@@ -1362,18 +1317,16 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
PBEKeySpec spec = new PBEKeySpec(chars, salt, iterations, KEK_BYTES * Byte.SIZE);
Arrays.fill(chars, '\0');
try {
- return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
- .generateSecret(spec).getEncoded();
+ return SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256").generateSecret(spec).getEncoded();
} finally {
spec.clearPassword();
}
}
- private static byte[] crypt(int mode, byte[] key, byte[] nonce, byte[] aad,
- byte[] input) throws GeneralSecurityException {
+ private static byte[] crypt(int mode, byte[] key, byte[] nonce, byte[] aad, byte[] input)
+ throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
- cipher.init(mode, new SecretKeySpec(key, "AES"),
- new GCMParameterSpec(GCM_TAG_BITS, nonce));
+ cipher.init(mode, new SecretKeySpec(key, "AES"), new GCMParameterSpec(GCM_TAG_BITS, nonce));
cipher.updateAAD(aad);
return cipher.doFinal(input);
}
@@ -1387,10 +1340,8 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private static void validateIterations(int iterations, KeyringProtection protection)
- throws KeyringException {
- if (iterations < KeyringProtection.CREATION_ITERATIONS
- || iterations > KeyringProtection.MAX_DECODED_ITERATIONS
+ private static void validateIterations(int iterations, KeyringProtection protection) throws KeyringException {
+ if (iterations < KeyringProtection.CREATION_ITERATIONS || iterations > KeyringProtection.MAX_DECODED_ITERATIONS
|| iterations > protection.operationalIterationMaximum()) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
}
@@ -1404,8 +1355,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
};
}
- private static int positionFor(Map values,
- String alias) {
+ private static int positionFor(Map values, String alias) {
int index = 0;
for (String current : values.keySet()) {
if (current.equals(alias)) {
@@ -1442,10 +1392,8 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private static void validateString(String value, int maximumBytes)
- throws KeyringException {
- if (value == null || value.isBlank()
- || value.getBytes(StandardCharsets.UTF_8).length > maximumBytes) {
+ private static void validateString(String value, int maximumBytes) throws KeyringException {
+ if (value == null || value.isBlank() || value.getBytes(StandardCharsets.UTF_8).length > maximumBytes) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
}
}
@@ -1485,11 +1433,9 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
return value;
}
- private static byte[] readBoundedBytes(DataInputStream in, int maximum,
- int exactOrMaximum) throws IOException {
+ private static byte[] readBoundedBytes(DataInputStream in, int maximum, int exactOrMaximum) throws IOException {
int length = in.readInt();
- if (length < 0 || length > maximum
- || exactOrMaximum < maximum && length != exactOrMaximum) {
+ if (length < 0 || length > maximum || exactOrMaximum < maximum && length != exactOrMaximum) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
}
byte[] value = new byte[length];
@@ -1512,10 +1458,8 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
byte[] encoded = readBoundedBytes(in, maximum, maximum);
try {
try {
- return StandardCharsets.UTF_8.newDecoder()
- .onMalformedInput(CodingErrorAction.REPORT)
- .onUnmappableCharacter(CodingErrorAction.REPORT)
- .decode(ByteBuffer.wrap(encoded)).toString();
+ return StandardCharsets.UTF_8.newDecoder().onMalformedInput(CodingErrorAction.REPORT)
+ .onUnmappableCharacter(CodingErrorAction.REPORT).decode(ByteBuffer.wrap(encoded)).toString();
} catch (CharacterCodingException exception) {
throw new KeyringException(Code.KEYRING_FORMAT_INVALID);
}
@@ -1541,8 +1485,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
@SuppressWarnings("PMD.PreserveStackTrace")
private static byte[] readStoreImage(Path source) throws IOException {
- try (FileChannel channel = FileChannel.open(source,
- StandardOpenOption.READ, LinkOption.NOFOLLOW_LINKS)) {
+ try (FileChannel channel = FileChannel.open(source, StandardOpenOption.READ, LinkOption.NOFOLLOW_LINKS)) {
long size = channel.size();
if (size <= 0 || size > MAX_FILE_BYTES) {
throw new KeyringException(Code.KEYRING_LIMIT_EXCEEDED);
@@ -1576,8 +1519,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
@SuppressWarnings("PMD.PreserveStackTrace")
- private static Path securePath(Path requested, boolean createParent)
- throws IOException {
+ private static Path securePath(Path requested, boolean createParent) throws IOException {
Objects.requireNonNull(requested, "path must not be null");
Path absolute = requested.toAbsolutePath().normalize();
Path parent = absolute.getParent();
@@ -1609,15 +1551,13 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
@SuppressWarnings("PMD.PreserveStackTrace")
- private static void validateExistingFile(Path file, UserPrincipal expectedOwner)
- throws IOException {
- if (!Files.isRegularFile(file, LinkOption.NOFOLLOW_LINKS)
- || Files.isSymbolicLink(file)) {
+ private static void validateExistingFile(Path file, UserPrincipal expectedOwner) throws IOException {
+ if (!Files.isRegularFile(file, LinkOption.NOFOLLOW_LINKS) || Files.isSymbolicLink(file)) {
throw new KeyringException(Code.KEYRING_FILESYSTEM_UNSUPPORTED);
}
validateOwnerOnly(file, false);
- PosixFileAttributes attributes = Files.readAttributes(file,
- PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
+ PosixFileAttributes attributes = Files.readAttributes(file, PosixFileAttributes.class,
+ LinkOption.NOFOLLOW_LINKS);
if (!attributes.owner().equals(expectedOwner)) {
throw new KeyringException(Code.KEYRING_FILESYSTEM_UNSUPPORTED);
}
@@ -1631,10 +1571,9 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private static void validateOwnerOnly(Path path, boolean directory)
- throws IOException {
- PosixFileAttributes attributes = Files.readAttributes(path,
- PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
+ private static void validateOwnerOnly(Path path, boolean directory) throws IOException {
+ PosixFileAttributes attributes = Files.readAttributes(path, PosixFileAttributes.class,
+ LinkOption.NOFOLLOW_LINKS);
Set expected = directory ? DIRECTORY_PERMISSIONS : FILE_PERMISSIONS;
if (!attributes.permissions().equals(expected)) {
throw new KeyringException(Code.KEYRING_FILESYSTEM_UNSUPPORTED);
@@ -1642,8 +1581,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
@SuppressWarnings("PMD.PreserveStackTrace")
- /* default */ static void destroyTemporarySpec(
- zeroecho.core.spec.AlgorithmKeySpec spec, Throwable primary)
+ /* default */ static void destroyTemporarySpec(zeroecho.core.spec.AlgorithmKeySpec spec, Throwable primary)
throws GeneralSecurityException {
if (!(spec instanceof Destroyable destroyable)) {
return;
@@ -1667,22 +1605,19 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private record Header(byte[] storeId, int iterations, byte[] salt,
- byte[] masterWrapNonce, byte[] wrappedMasterKey) {
+ private record Header(byte[] storeId, int iterations, byte[] salt, byte[] masterWrapNonce,
+ byte[] wrappedMasterKey) {
}
- private record Manifest(int noncePrefix, long highWater,
- List entries) {
+ private record Manifest(int noncePrefix, long highWater, List entries) {
}
- private record ManifestEntry(byte[] entryId, int position, String alias,
- String algorithm, Kind kind, Encoding encoding,
- KeyringImportRegistry.HmacVariant hmacVariant,
- byte[] nonce, int ciphertextLength, byte[] digest) {
+ private record ManifestEntry(byte[] entryId, int position, String alias, String algorithm, Kind kind,
+ Encoding encoding, KeyringImportRegistry.HmacVariant hmacVariant, byte[] nonce, int ciphertextLength,
+ byte[] digest) {
}
- private record EncryptedWireEntry(byte[] entryId, byte[] nonce,
- byte[] ciphertext) {
+ private record EncryptedWireEntry(byte[] entryId, byte[] nonce, byte[] ciphertext) {
}
/** Immutable encrypted entry retained while the store is open. */
@@ -1698,10 +1633,9 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
private final byte[] ciphertext;
private final byte[] digest;
- private EncryptedEntry(byte[] entryId, int position, String alias,
- String algorithm, Kind kind, Encoding encoding,
- KeyringImportRegistry.HmacVariant hmacVariant,
- byte[] nonce, byte[] ciphertext, byte[] digest) {
+ private EncryptedEntry(byte[] entryId, int position, String alias, String algorithm, Kind kind,
+ Encoding encoding, KeyringImportRegistry.HmacVariant hmacVariant, byte[] nonce, byte[] ciphertext,
+ byte[] digest) {
this.entryId = entryId.clone();
this.position = position;
this.alias = alias;
@@ -1715,16 +1649,14 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
- private record EntryPlain(String alias, String algorithm, Kind kind,
- Encoding encoding, KeyringImportRegistry.HmacVariant hmacVariant,
- byte[] encoded) {
+ private record EntryPlain(String alias, String algorithm, Kind kind, Encoding encoding,
+ KeyringImportRegistry.HmacVariant hmacVariant, byte[] encoded) {
}
private record Imported(String algorithm, Key key) {
}
- private record Decoded(Header header, byte[] masterKey, Manifest manifest,
- Map entries) {
+ private record Decoded(Header header, byte[] masterKey, Manifest manifest, Map entries) {
}
/** Value-semantic nonce used only for duplicate detection. */
@@ -1764,8 +1696,9 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
/* default */ static Ownership acquire(Path keyring) throws IOException {
Path lockPath = keyring.resolveSibling(keyring.getFileName() + ".lock");
try {
- UserPrincipal expectedOwner = Files.readAttributes(lockPath.getParent(),
- PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS).owner();
+ UserPrincipal expectedOwner = Files
+ .readAttributes(lockPath.getParent(), PosixFileAttributes.class, LinkOption.NOFOLLOW_LINKS)
+ .owner();
if (!Files.exists(lockPath, LinkOption.NOFOLLOW_LINKS)) {
try {
Files.createFile(lockPath, FILE_ATTRIBUTE);
@@ -1774,8 +1707,7 @@ public final class KeyringStore implements AutoCloseable, Destroyable { // NOPMD
}
}
validateExistingFile(lockPath, expectedOwner);
- FileChannel channel = FileChannel.open(lockPath,
- StandardOpenOption.WRITE, LinkOption.NOFOLLOW_LINKS);
+ FileChannel channel = FileChannel.open(lockPath, StandardOpenOption.WRITE, LinkOption.NOFOLLOW_LINKS);
try {
FileLock lock;
try {
diff --git a/lib/src/main/java/zeroecho/core/storage/package-info.java b/lib/src/main/java/zeroecho/core/storage/package-info.java
index dc0c316..28e5d65 100644
--- a/lib/src/main/java/zeroecho/core/storage/package-info.java
+++ b/lib/src/main/java/zeroecho/core/storage/package-info.java
@@ -53,15 +53,15 @@
*
*
*
- * Unlock passwords are destroyable, transfer ownership to the receiver, and
- * are destroyed immediately after the master key is unwrapped. The unlocked
- * store retains the master key, its domain-separated nonce-reservation MAC
- * key, and encrypted entry records; closing the store clears this material.
- * The store requires a POSIX filesystem on which owner-only permissions can be
- * verified. A directory-force failure after atomic replacement makes the open
- * instance unusable until close and authenticated reopen resolves which
- * complete image is current. Non-exportable keys must remain behind an
- * external provider reference.
+ * Unlock passwords are destroyable, transfer ownership to the receiver, and are
+ * destroyed immediately after the master key is unwrapped. The unlocked store
+ * retains the master key, its domain-separated nonce-reservation MAC key, and
+ * encrypted entry records; closing the store clears this material. The store
+ * requires a POSIX filesystem on which owner-only permissions can be verified.
+ * A directory-force failure after atomic replacement makes the open instance
+ * unusable until close and authenticated reopen resolves which complete image
+ * is current. Non-exportable keys must remain behind an external provider
+ * reference.
*
*
*
diff --git a/lib/src/main/java/zeroecho/core/tag/TagEngineBuilder.java b/lib/src/main/java/zeroecho/core/tag/TagEngineBuilder.java
index 8541749..cd579b6 100644
--- a/lib/src/main/java/zeroecho/core/tag/TagEngineBuilder.java
+++ b/lib/src/main/java/zeroecho/core/tag/TagEngineBuilder.java
@@ -124,8 +124,7 @@ public final class TagEngineBuilder implements Supplier> {
public static TagEngineBuilder digest(final ZeroEchoSession session, final DigestSpec spec) {
Objects.requireNonNull(session, "session");
final DigestSpec s = spec == null ? DigestSpec.sha256() : spec;
- return new TagEngineBuilder<>(
- () -> session.createContext("DIGEST", KeyUsage.DIGEST, NullKey.INSTANCE, s));
+ return new TagEngineBuilder<>(() -> session.createContext("DIGEST", KeyUsage.DIGEST, NullKey.INSTANCE, s));
}
/**
@@ -193,8 +192,7 @@ public final class TagEngineBuilder implements Supplier> {
* @return a builder that produces Ed25519 signature engines in SIGN mode
* @throws NullPointerException if {@code privateKey} is {@code null}
*/
- public static TagEngineBuilder ed25519Sign(final ZeroEchoSession session,
- final PrivateKey privateKey) {
+ public static TagEngineBuilder ed25519Sign(final ZeroEchoSession session, final PrivateKey privateKey) {
Objects.requireNonNull(privateKey, PRIVATE_KEY);
return signature(session, "Ed25519", privateKey, VoidSpec.INSTANCE);
}
@@ -206,8 +204,7 @@ public final class TagEngineBuilder implements Supplier> {
* @return a builder that produces Ed25519 signature engines in VERIFY mode
* @throws NullPointerException if {@code publicKey} is {@code null}
*/
- public static TagEngineBuilder ed25519Verify(final ZeroEchoSession session,
- final PublicKey publicKey) {
+ public static TagEngineBuilder ed25519Verify(final ZeroEchoSession session, final PublicKey publicKey) {
Objects.requireNonNull(publicKey, PUBLIC_KEY);
return signature(session, "Ed25519", publicKey, VoidSpec.INSTANCE);
}
@@ -229,8 +226,7 @@ public final class TagEngineBuilder implements Supplier> {
public static TagEngineBuilder rsaSign(final ZeroEchoSession session, final PrivateKey privateKey,
final RsaSigSpec spec) {
Objects.requireNonNull(privateKey, PRIVATE_KEY);
- return signature(session, "RSA", privateKey,
- spec == null ? RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32) : spec);
+ return signature(session, "RSA", privateKey, spec == null ? RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32) : spec);
}
/**
@@ -250,8 +246,7 @@ public final class TagEngineBuilder implements Supplier> {
public static TagEngineBuilder rsaVerify(final ZeroEchoSession session, final PublicKey publicKey,
final RsaSigSpec spec) {
Objects.requireNonNull(publicKey, PUBLIC_KEY);
- return signature(session, "RSA", publicKey,
- spec == null ? RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32) : spec);
+ return signature(session, "RSA", publicKey, spec == null ? RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32) : spec);
}
/**
@@ -369,8 +364,7 @@ public final class TagEngineBuilder implements Supplier> {
* @return a builder that produces SLH-DSA signature engines in SIGN mode
* @throws NullPointerException if {@code privateKey} is {@code null}
*/
- public static TagEngineBuilder slhDsaSign(final ZeroEchoSession session,
- final PrivateKey privateKey) {
+ public static TagEngineBuilder slhDsaSign(final ZeroEchoSession session, final PrivateKey privateKey) {
Objects.requireNonNull(privateKey, PRIVATE_KEY);
return signature(session, "SLH-DSA", privateKey, VoidSpec.INSTANCE);
}
@@ -388,8 +382,7 @@ public final class TagEngineBuilder implements Supplier> {
* @return a builder that produces SLH-DSA signature engines in VERIFY mode
* @throws NullPointerException if {@code publicKey} is {@code null}
*/
- public static TagEngineBuilder slhDsaVerify(final ZeroEchoSession session,
- final PublicKey publicKey) {
+ public static TagEngineBuilder slhDsaVerify(final ZeroEchoSession session, final PublicKey publicKey) {
Objects.requireNonNull(publicKey, PUBLIC_KEY);
return signature(session, "SLH-DSA", publicKey, VoidSpec.INSTANCE);
}
@@ -408,8 +401,7 @@ public final class TagEngineBuilder implements Supplier> {
* @return a builder that produces ML-DSA signature engines in SIGN mode
* @throws NullPointerException if {@code privateKey} is {@code null}
*/
- public static TagEngineBuilder mldsaSign(final ZeroEchoSession session,
- final PrivateKey privateKey) {
+ public static TagEngineBuilder mldsaSign(final ZeroEchoSession session, final PrivateKey privateKey) {
Objects.requireNonNull(privateKey, PRIVATE_KEY);
return signature(session, "ML-DSA", privateKey, VoidSpec.INSTANCE);
}
@@ -428,8 +420,7 @@ public final class TagEngineBuilder implements Supplier> {
* @return a builder that produces ML-DSA signature engines in VERIFY mode
* @throws NullPointerException if {@code publicKey} is {@code null}
*/
- public static TagEngineBuilder mldsaVerify(final ZeroEchoSession session,
- final PublicKey publicKey) {
+ public static TagEngineBuilder mldsaVerify(final ZeroEchoSession session, final PublicKey publicKey) {
Objects.requireNonNull(publicKey, PUBLIC_KEY);
return signature(session, "ML-DSA", publicKey, VoidSpec.INSTANCE);
}
diff --git a/lib/src/main/java/zeroecho/sdk/KeyBuilders.java b/lib/src/main/java/zeroecho/sdk/KeyBuilders.java
index 978d91e..305fa67 100644
--- a/lib/src/main/java/zeroecho/sdk/KeyBuilders.java
+++ b/lib/src/main/java/zeroecho/sdk/KeyBuilders.java
@@ -25,9 +25,11 @@ import zeroecho.core.spi.SymmetricKeyImporter;
/**
* Session-bound entry point for exact key-material operations.
*
- * Capability lookup fails before an operation object is returned. Returned
+ *
+ * Capability lookup fails before an operation object is returned. Returned
* objects guarantee the requested operation and report successful execution to
- * the owning session's audit listener on a best-effort basis.
+ * the owning session's audit listener on a best-effort basis.
+ *
*
* @since 1.0
*/
@@ -69,13 +71,12 @@ public final class KeyBuilders {
* Resolves an exact symmetric generator.
*
* @param algorithmId canonical algorithm identifier
- * @param specType exact specification class
- * @param specification type
+ * @param specType exact specification class
+ * @param specification type
* @return guaranteed generator
* @throws IllegalArgumentException if the capability is absent
*/
- public SymmetricKeyGenerator generator(String algorithmId,
- Class specType) {
+ public SymmetricKeyGenerator generator(String algorithmId, Class specType) {
CryptoAlgorithm algorithm = session.require(algorithmId);
SymmetricKeyGenerator delegate = algorithm.symmetricKeyGenerator(specType);
return spec -> {
@@ -89,13 +90,12 @@ public final class KeyBuilders {
* Resolves an exact symmetric importer.
*
* @param algorithmId canonical algorithm identifier
- * @param specType exact specification class
- * @param specification type
+ * @param specType exact specification class
+ * @param specification type
* @return guaranteed importer
* @throws IllegalArgumentException if the capability is absent
*/
- public SymmetricKeyImporter importer(String algorithmId,
- Class specType) {
+ public SymmetricKeyImporter importer(String algorithmId, Class specType) {
CryptoAlgorithm algorithm = session.require(algorithmId);
SymmetricKeyImporter delegate = algorithm.symmetricKeyImporter(specType);
return spec -> {
@@ -109,12 +109,13 @@ public final class KeyBuilders {
* Generates a symmetric key using the exact runtime specification type.
*
* @param algorithmId canonical algorithm identifier
- * @param spec generation specification
- * @param specification type
+ * @param spec generation specification
+ * @param specification type
* @return generated secret key
* @throws java.security.GeneralSecurityException if generation fails
- * @throws IllegalArgumentException if the capability is absent
- * @throws NullPointerException if {@code spec} is {@code null}
+ * @throws IllegalArgumentException if the capability is absent
+ * @throws NullPointerException if {@code spec} is
+ * {@code null}
*/
public SecretKey generate(String algorithmId, S spec)
throws java.security.GeneralSecurityException {
@@ -128,12 +129,13 @@ public final class KeyBuilders {
* Imports a symmetric key using the exact runtime specification type.
*
* @param algorithmId canonical algorithm identifier
- * @param spec import specification
- * @param specification type
+ * @param spec import specification
+ * @param specification type
* @return imported secret key
* @throws java.security.GeneralSecurityException if import fails
- * @throws IllegalArgumentException if the capability is absent
- * @throws NullPointerException if {@code spec} is {@code null}
+ * @throws IllegalArgumentException if the capability is absent
+ * @throws NullPointerException if {@code spec} is
+ * {@code null}
*/
public SecretKey importKey(String algorithmId, S spec)
throws java.security.GeneralSecurityException {
@@ -155,8 +157,8 @@ public final class KeyBuilders {
* Resolves an exact key-pair generator.
*
* @param algorithmId canonical algorithm identifier
- * @param specType exact specification class
- * @param specification type
+ * @param specType exact specification class
+ * @param specification type
* @return guaranteed generator
* @throws IllegalArgumentException if the capability is absent
*/
@@ -175,13 +177,12 @@ public final class KeyBuilders {
* Resolves an exact public-key importer.
*
* @param algorithmId canonical algorithm identifier
- * @param specType exact specification class
- * @param specification type
+ * @param specType exact specification class
+ * @param specification type
* @return guaranteed importer
* @throws IllegalArgumentException if the capability is absent
*/
- public PublicKeyImporter publicImporter(String algorithmId,
- Class specType) {
+ public PublicKeyImporter publicImporter(String algorithmId, Class specType) {
CryptoAlgorithm algorithm = session.require(algorithmId);
PublicKeyImporter delegate = algorithm.publicKeyImporter(specType);
return spec -> {
@@ -195,8 +196,8 @@ public final class KeyBuilders {
* Resolves an exact private-key importer.
*
* @param algorithmId canonical algorithm identifier
- * @param specType exact specification class
- * @param specification type
+ * @param specType exact specification class
+ * @param specification type
* @return guaranteed importer
* @throws IllegalArgumentException if the capability is absent
*/
@@ -215,12 +216,13 @@ public final class KeyBuilders {
* Generates a key pair using the exact runtime specification type.
*
* @param algorithmId canonical algorithm identifier
- * @param spec generation specification
- * @param specification type
+ * @param spec generation specification
+ * @param specification type
* @return generated key pair
* @throws java.security.GeneralSecurityException if generation fails
- * @throws IllegalArgumentException if the capability is absent
- * @throws NullPointerException if {@code spec} is {@code null}
+ * @throws IllegalArgumentException if the capability is absent
+ * @throws NullPointerException if {@code spec} is
+ * {@code null}
*/
public KeyPair generateKeyPair(String algorithmId, S spec)
throws java.security.GeneralSecurityException {
@@ -234,12 +236,13 @@ public final class KeyBuilders {
* Imports a public key using the exact runtime specification type.
*
* @param algorithmId canonical algorithm identifier
- * @param spec public-key import specification
- * @param specification type
+ * @param spec public-key import specification
+ * @param specification type
* @return imported public key
* @throws java.security.GeneralSecurityException if import fails
- * @throws IllegalArgumentException if the capability is absent
- * @throws NullPointerException if {@code spec} is {@code null}
+ * @throws IllegalArgumentException if the capability is absent
+ * @throws NullPointerException if {@code spec} is
+ * {@code null}
*/
public PublicKey importPublic(String algorithmId, S spec)
throws java.security.GeneralSecurityException {
@@ -253,12 +256,13 @@ public final class KeyBuilders {
* Imports a private key using the exact runtime specification type.
*
* @param algorithmId canonical algorithm identifier
- * @param spec private-key import specification
- * @param specification type
+ * @param spec private-key import specification
+ * @param specification type
* @return imported private key
* @throws java.security.GeneralSecurityException if import fails
- * @throws IllegalArgumentException if the capability is absent
- * @throws NullPointerException if {@code spec} is {@code null}
+ * @throws IllegalArgumentException if the capability is absent
+ * @throws NullPointerException if {@code spec} is
+ * {@code null}
*/
public PrivateKey importPrivate(String algorithmId, S spec)
throws java.security.GeneralSecurityException {
diff --git a/lib/src/main/java/zeroecho/sdk/Pbkdf2Limits.java b/lib/src/main/java/zeroecho/sdk/Pbkdf2Limits.java
index 3cb708d..cc3681c 100644
--- a/lib/src/main/java/zeroecho/sdk/Pbkdf2Limits.java
+++ b/lib/src/main/java/zeroecho/sdk/Pbkdf2Limits.java
@@ -8,10 +8,11 @@
package zeroecho.sdk;
/**
- * Explicit PBKDF2 work-factor limits for trusted configuration and decoded data.
+ * Explicit PBKDF2 work-factor limits for trusted configuration and decoded
+ * data.
*
- * @param operationalMaximum largest iteration count accepted from trusted local
- * configuration
+ * @param operationalMaximum largest iteration count accepted from trusted
+ * local configuration
* @param absoluteDecodedMaximum hard safety ceiling for untrusted decoded data
* @since 1.0
*/
@@ -41,8 +42,8 @@ public record Pbkdf2Limits(int operationalMaximum, int absoluteDecodedMaximum) {
*/
public void validateTrusted(int iterations) {
if (iterations < MINIMUM || iterations > operationalMaximum) {
- throw new IllegalArgumentException("PBKDF2 iterations must be in range " + MINIMUM + ".."
- + operationalMaximum + ": " + iterations);
+ throw new IllegalArgumentException(
+ "PBKDF2 iterations must be in range " + MINIMUM + ".." + operationalMaximum + ": " + iterations);
}
}
diff --git a/lib/src/main/java/zeroecho/sdk/ZeroEchoSession.java b/lib/src/main/java/zeroecho/sdk/ZeroEchoSession.java
index f359c83..1237d4f 100644
--- a/lib/src/main/java/zeroecho/sdk/ZeroEchoSession.java
+++ b/lib/src/main/java/zeroecho/sdk/ZeroEchoSession.java
@@ -108,8 +108,8 @@ public final class ZeroEchoSession {
this(CryptoPolicy.permissive(), AuditListener.noop(), AuditMode.OFF, null);
}
- private ZeroEchoSession(CryptoPolicy policy, AuditListener auditListener,
- AuditMode auditMode, Pbkdf2Limits pbkdf2Limits) {
+ private ZeroEchoSession(CryptoPolicy policy, AuditListener auditListener, AuditMode auditMode,
+ Pbkdf2Limits pbkdf2Limits) {
this.policy = Objects.requireNonNull(policy, "policy must not be null");
this.auditListener = Objects.requireNonNull(auditListener, "auditListener must not be null");
this.auditSink = AuditListeners.bestEffort(auditListener);
@@ -143,8 +143,7 @@ public final class ZeroEchoSession {
*/
public ZeroEchoSession withAuditListener(AuditListener newAuditListener) {
return new ZeroEchoSession(policy,
- Objects.requireNonNull(newAuditListener, "newAuditListener must not be null"), auditMode,
- pbkdf2Limits);
+ Objects.requireNonNull(newAuditListener, "newAuditListener must not be null"), auditMode, pbkdf2Limits);
}
/**
@@ -198,8 +197,8 @@ public final class ZeroEchoSession {
* Returns the audit listener owned by this session.
*
*
- * The returned listener is the configured strategy, not mutable session
- * state. It is exposed to support manual audit mode.
+ * The returned listener is the configured strategy, not mutable session state.
+ * It is exposed to support manual audit mode.
*
*
* @return the non-null audit listener
@@ -254,8 +253,8 @@ public final class ZeroEchoSession {
* @param id canonical algorithm identifier
* @param role intended key usage
* @param key key compatible with the selected algorithm and role
- * @param spec optional context specification, or {@code null} for the
- * algorithm default
+ * @param spec optional context specification, or {@code null} for the algorithm
+ * default
* @param context type
* @param key type
* @param context specification type
@@ -275,8 +274,8 @@ public final class ZeroEchoSession {
return finishContext(algorithm, context, role, spec);
}
- private C finishContext(CryptoAlgorithm algorithm,
- C context, KeyUsage role, S spec) {
+ private C finishContext(CryptoAlgorithm algorithm, C context,
+ KeyUsage role, S spec) {
if (auditMode == AuditMode.OFF) {
notifyContextCreated(algorithm, role, spec);
return context;
@@ -321,14 +320,15 @@ public final class ZeroEchoSession {
* Destroys a key and verifies that it entered the destroyed state.
*
* @param algorithmId algorithm identifier used as audit metadata
- * @param provider provider name used as audit metadata
- * @param key key to destroy; must not be {@code null}
+ * @param provider provider name used as audit metadata
+ * @param key key to destroy; must not be {@code null}
* @return {@code true} only when this call transitions the key to destroyed;
* {@code false} for a non-destroyable or already destroyed key
- * @throws NullPointerException if {@code key} is {@code null}
+ * @throws NullPointerException if {@code key} is {@code null}
* @throws DestroyFailedException if destruction fails or the key does not
* report itself destroyed afterward
- * @throws RuntimeException if the key's lifecycle implementation throws one
+ * @throws RuntimeException if the key's lifecycle implementation throws
+ * one
*/
public boolean destroyKey(String algorithmId, String provider, Key key) throws DestroyFailedException {
Objects.requireNonNull(key, "key must not be null");
@@ -352,12 +352,10 @@ public final class ZeroEchoSession {
return true;
}
- private void notifyContextCreated(CryptoAlgorithm algorithm,
- KeyUsage role, S spec) {
- Map metadata = spec == null ? Map.of()
- : Map.of("specType", spec.getClass().getName());
- auditSink.onContextCreatedMeta(UUID.randomUUID().toString(), algorithm.id(), algorithm.providerName(),
- role, "n/a", metadata);
+ private void notifyContextCreated(CryptoAlgorithm algorithm, KeyUsage role, S spec) {
+ Map metadata = spec == null ? Map.of() : Map.of("specType", spec.getClass().getName());
+ auditSink.onContextCreatedMeta(UUID.randomUUID().toString(), algorithm.id(), algorithm.providerName(), role,
+ "n/a", metadata);
}
/* default */ void notifyKeyPairGenerated(CryptoAlgorithm algorithm, AlgorithmKeySpec spec, KeyPair keyPair) {
diff --git a/lib/src/main/java/zeroecho/sdk/builders/HybridKexBuilder.java b/lib/src/main/java/zeroecho/sdk/builders/HybridKexBuilder.java
index 817fcff..f224d01 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/HybridKexBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/HybridKexBuilder.java
@@ -342,10 +342,8 @@ public final class HybridKexBuilder {
if (pqcAlgId == null) {
throw new IllegalStateException("pqc algorithm id must be set");
}
- if (classicMode == ClassicMode.CLASSIC_AGREEMENT
- && (classicPrivate == null || classicPeerPublic == null)) {
- throw new IllegalStateException(
- "classic private key and peer public must be set for CLASSIC_AGREEMENT");
+ if (classicMode == ClassicMode.CLASSIC_AGREEMENT && (classicPrivate == null || classicPeerPublic == null)) {
+ throw new IllegalStateException("classic private key and peer public must be set for CLASSIC_AGREEMENT");
}
if (classicMode == ClassicMode.PAIR_MESSAGE && classicKeyPair == null) {
throw new IllegalStateException("classic key pair must be set for PAIR_MESSAGE");
diff --git a/lib/src/main/java/zeroecho/sdk/builders/SignatureTrailerDataContentBuilder.java b/lib/src/main/java/zeroecho/sdk/builders/SignatureTrailerDataContentBuilder.java
index f6c32f0..2996a72 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/SignatureTrailerDataContentBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/SignatureTrailerDataContentBuilder.java
@@ -77,12 +77,13 @@ import zeroecho.sdk.hybrid.signature.HybridSignatureProfile;
* {@link #single(ZeroEchoSession)}: constructs a non-hybrid
* {@code SignatureContext}.
* {@link #hybrid(ZeroEchoSession)}: constructs a hybrid
- * {@code SignatureContext} via
- * {@link HybridSignatureContexts}.
+ * {@code SignatureContext} via {@link HybridSignatureContexts}.
*
*
- * Context construction is in-memory. Checked I/O failures arise only when a
- * built stream is attached or processed.
+ *
+ * Context construction is in-memory. Checked I/O failures arise only when a
+ * built stream is attached or processed.
+ *
*
* @since 1.0
*/
@@ -253,8 +254,8 @@ public final class SignatureTrailerDataContentBuilder implements DataContentBuil
Objects.requireNonNull(algorithmId, "algorithmId");
Objects.requireNonNull(privateKey, "privateKey");
- Supplier> factory = () -> session.createContext(algorithmId, KeyUsage.SIGN,
- privateKey, spec);
+ Supplier> factory = () -> session.createContext(algorithmId, KeyUsage.SIGN, privateKey,
+ spec);
return core(factory);
}
@@ -293,8 +294,8 @@ public final class SignatureTrailerDataContentBuilder implements DataContentBuil
Objects.requireNonNull(algorithmId, "algorithmId");
Objects.requireNonNull(publicKey, "publicKey");
- Supplier> factory = () -> session.createContext(algorithmId,
- KeyUsage.VERIFY, publicKey, spec);
+ Supplier> factory = () -> session.createContext(algorithmId, KeyUsage.VERIFY,
+ publicKey, spec);
return core(factory);
}
diff --git a/lib/src/main/java/zeroecho/sdk/builders/alg/ChaChaDataContentBuilder.java b/lib/src/main/java/zeroecho/sdk/builders/alg/ChaChaDataContentBuilder.java
index c70fa84..f83a6ba 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/alg/ChaChaDataContentBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/alg/ChaChaDataContentBuilder.java
@@ -567,8 +567,7 @@ public final class ChaChaDataContentBuilder implements DataContentBuilder
* The actual cipher work is delegated to an
* {@link zeroecho.core.context.EncryptionContext} created through
- * {@link zeroecho.sdk.ZeroEchoSession#createContext(String,
- * zeroecho.core.KeyUsage, java.security.Key, zeroecho.core.spec.ContextSpec)}.
+ * {@link zeroecho.sdk.ZeroEchoSession#createContext(String, zeroecho.core.KeyUsage, java.security.Key, zeroecho.core.spec.ContextSpec)}.
* If the created context implements {@code ContextAware}, the configured
* context is injected before the stream is attached.
*
@@ -638,8 +637,7 @@ public final class ChaChaDataContentBuilder implements DataContentBuilder
* The actual cipher work is delegated to an
* {@link zeroecho.core.context.EncryptionContext} created through
- * {@link zeroecho.sdk.ZeroEchoSession#createContext(String,
- * zeroecho.core.KeyUsage, java.security.Key, zeroecho.core.spec.ContextSpec)}.
+ * {@link zeroecho.sdk.ZeroEchoSession#createContext(String, zeroecho.core.KeyUsage, java.security.Key, zeroecho.core.spec.ContextSpec)}.
* If the created context implements {@code ContextAware}, the configured
* context is injected before the stream is attached.
*
diff --git a/lib/src/main/java/zeroecho/sdk/builders/alg/DigestDataContentBuilder.java b/lib/src/main/java/zeroecho/sdk/builders/alg/DigestDataContentBuilder.java
index 3d30bf3..3d89508 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/alg/DigestDataContentBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/alg/DigestDataContentBuilder.java
@@ -113,6 +113,7 @@ import zeroecho.sdk.content.api.PlainContent;
*/
public final class DigestDataContentBuilder implements DataContentBuilder {
private final ZeroEchoSession session;
+
/**
* OutputMode selects how the digest-computing pipeline presents its result to
* callers.
diff --git a/lib/src/main/java/zeroecho/sdk/builders/alg/ElgamalEncDataContentBuilder.java b/lib/src/main/java/zeroecho/sdk/builders/alg/ElgamalEncDataContentBuilder.java
index f329801..560c18d 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/alg/ElgamalEncDataContentBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/alg/ElgamalEncDataContentBuilder.java
@@ -361,8 +361,7 @@ public final class ElgamalEncDataContentBuilder implements DataContentBuilder
@@ -426,8 +425,7 @@ public final class ElgamalEncDataContentBuilder implements DataContentBuilder
diff --git a/lib/src/main/java/zeroecho/sdk/builders/alg/HmacDataContentBuilder.java b/lib/src/main/java/zeroecho/sdk/builders/alg/HmacDataContentBuilder.java
index a7413d2..613e560 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/alg/HmacDataContentBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/alg/HmacDataContentBuilder.java
@@ -91,6 +91,7 @@ import zeroecho.sdk.content.api.PlainContent;
public final class HmacDataContentBuilder implements DataContentBuilder {
private static final String ALGORITHM_ID = "HMAC";
private final ZeroEchoSession session;
+
/**
* Mode selects whether the pipeline computes an HMAC tag or verifies one.
*
@@ -622,8 +623,7 @@ public final class HmacDataContentBuilder implements DataContentBuilder
@@ -407,8 +406,7 @@ public final class RsaEncDataContentBuilder implements DataContentBuilder
diff --git a/lib/src/main/java/zeroecho/sdk/builders/alg/RsaSigDataContentBuilder.java b/lib/src/main/java/zeroecho/sdk/builders/alg/RsaSigDataContentBuilder.java
index 227f7f0..55a0b75 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/alg/RsaSigDataContentBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/alg/RsaSigDataContentBuilder.java
@@ -109,6 +109,7 @@ import zeroecho.sdk.content.api.PlainContent;
public final class RsaSigDataContentBuilder implements DataContentBuilder {
private static final String ALGORITHM_ID = "RSA";
private final ZeroEchoSession session;
+
/**
* Mode selects whether the builder signs or verifies.
*/
diff --git a/lib/src/main/java/zeroecho/sdk/builders/package-info.java b/lib/src/main/java/zeroecho/sdk/builders/package-info.java
index f94557d..a500988 100644
--- a/lib/src/main/java/zeroecho/sdk/builders/package-info.java
+++ b/lib/src/main/java/zeroecho/sdk/builders/package-info.java
@@ -70,7 +70,8 @@
* {@link zeroecho.sdk.builders.alg.ElgamalEncDataContentBuilder}.
* RSA signatures:
* {@link zeroecho.sdk.builders.alg.RsaSigDataContentBuilder}; generic signature
- * trailers use {@link zeroecho.sdk.builders.SignatureTrailerDataContentBuilder}.
+ * trailers use
+ * {@link zeroecho.sdk.builders.SignatureTrailerDataContentBuilder}.
* MAC and digest: {@link zeroecho.sdk.builders.alg.HmacDataContentBuilder},
* {@link zeroecho.sdk.builders.alg.DigestDataContentBuilder}.
* KEM envelopes: {@link zeroecho.sdk.builders.alg.KemDataContentBuilder}
diff --git a/lib/src/main/java/zeroecho/sdk/content/builtin/SecretPassword.java b/lib/src/main/java/zeroecho/sdk/content/builtin/SecretPassword.java
index 7b67abe..a77cb3c 100644
--- a/lib/src/main/java/zeroecho/sdk/content/builtin/SecretPassword.java
+++ b/lib/src/main/java/zeroecho/sdk/content/builtin/SecretPassword.java
@@ -85,8 +85,8 @@ public final class SecretPassword implements SecretContent, Destroyable {
}
/**
- * Constructs a password from a caller-owned character array. The supplied
- * array is cloned and remains owned by the caller.
+ * Constructs a password from a caller-owned character array. The supplied array
+ * is cloned and remains owned by the caller.
*
* @param password password characters; must not be {@code null}
* @throws NullPointerException if {@code password} is {@code null}
diff --git a/lib/src/main/java/zeroecho/sdk/guard/Decryptor.java b/lib/src/main/java/zeroecho/sdk/guard/Decryptor.java
index 8b29b09..ad3fb5a 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/Decryptor.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/Decryptor.java
@@ -148,8 +148,7 @@ final class Decryptor implements PlainContent, MultiRecipientContent {
} catch (AEADBadTagException ex) {
// wrong key/password for that entry, continue scanning
if (LOG.isLoggable(Level.FINE)) {
- LOG.log(Level.FINE, "recipient authentication failed: {0}",
- ex.getClass().getSimpleName());
+ LOG.log(Level.FINE, "recipient authentication failed: {0}", ex.getClass().getSimpleName());
}
} catch (GeneralSecurityException | IOException | IllegalArgumentException ex) {
// entry not applicable to this opener/material; ignore and continue
@@ -198,8 +197,7 @@ final class Decryptor implements PlainContent, MultiRecipientContent {
}
}
- private void closeAfterAttempt(InputStream input, boolean transferred, Throwable primary)
- throws IOException {
+ private void closeAfterAttempt(InputStream input, boolean transferred, Throwable primary) throws IOException {
IOException cleanupFailure = null;
if (!transferred) {
try {
@@ -282,8 +280,7 @@ final class Decryptor implements PlainContent, MultiRecipientContent {
closeOpeners(openers, primary);
}
- /* default */ static void closeOpeners(List ownedOpeners, Throwable primary)
- throws IOException {
+ /* default */ static void closeOpeners(List ownedOpeners, Throwable primary) throws IOException {
IOException cleanupFailure = null;
for (RecipientOpener opener : ownedOpeners) { // NOPMD - each opener is closed in this loop
try {
@@ -309,14 +306,13 @@ final class Decryptor implements PlainContent, MultiRecipientContent {
}
}
- private void rejectOversizedCek(byte[] candidate, int fieldIndex, String recipientId,
- RecipientOpener opener) {
+ private void rejectOversizedCek(byte[] candidate, int fieldIndex, String recipientId, RecipientOpener opener) {
try {
if (LOG.isLoggable(Level.WARNING)) {
LOG.log(Level.WARNING,
"Suspicious material in field {0}: {1}/{2} returned length {3}, while {4} is the limit. Ignoring.",
- new Object[] { fieldIndex, recipientId, opener.getClass().getName(),
- candidate.length, keyBytes });
+ new Object[] { fieldIndex, recipientId, opener.getClass().getName(), candidate.length,
+ keyBytes });
}
} finally {
Arrays.fill(candidate, (byte) 0);
diff --git a/lib/src/main/java/zeroecho/sdk/guard/Encryptor.java b/lib/src/main/java/zeroecho/sdk/guard/Encryptor.java
index ad19aff..69f9249 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/Encryptor.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/Encryptor.java
@@ -84,8 +84,7 @@ final class Encryptor implements EncryptedContent, MultiRecipientContent {
this.keyBytes = keyBytes;
this.maxRecipients = maxRecipients;
this.maxEntryLen = maxEntryLen;
- this.randomBytesFactory = Objects.requireNonNull(randomBytesFactory,
- "randomBytesFactory must not be null");
+ this.randomBytesFactory = Objects.requireNonNull(randomBytesFactory, "randomBytesFactory must not be null");
}
/**
@@ -232,8 +231,7 @@ final class Encryptor implements EncryptedContent, MultiRecipientContent {
return key;
}
- /* default */ static void closeRecipients(List ownedRecipients, Throwable primary)
- throws IOException {
+ /* default */ static void closeRecipients(List ownedRecipients, Throwable primary) throws IOException {
IOException cleanupFailure = null;
for (Recipient recipient : ownedRecipients) {
try {
diff --git a/lib/src/main/java/zeroecho/sdk/guard/KemCtxRecipient.java b/lib/src/main/java/zeroecho/sdk/guard/KemCtxRecipient.java
index 348c13e..336fc42 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/KemCtxRecipient.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/KemCtxRecipient.java
@@ -82,8 +82,7 @@ public final class KemCtxRecipient implements Recipient, AutoCloseable {
* @param kekBytes KEK length; exactly 16 or 32 bytes
* @param saltLen length of the random salt to apply during HKDF
* @throws NullPointerException if {@code ctx} is {@code null}
- * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or
- * 32
+ * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or 32
*/
public KemCtxRecipient(KemContext ctx, int kekBytes, int saltLen) {
this(ctx, kekBytes, saltLen, false);
@@ -107,8 +106,7 @@ public final class KemCtxRecipient implements Recipient, AutoCloseable {
* @param decoy {@code true} if this recipient is a decoy (fake entry that
* cannot unwrap a CEK); {@code false} if it is a real recipient
* @throws NullPointerException if {@code ctx} is {@code null}
- * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or
- * 32
+ * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or 32
*/
public KemCtxRecipient(KemContext ctx, int kekBytes, int saltLen, boolean decoy) {
int validatedKekBytes = RecipientKekSizes.requireSupported(kekBytes);
diff --git a/lib/src/main/java/zeroecho/sdk/guard/KemKeyDerivation.java b/lib/src/main/java/zeroecho/sdk/guard/KemKeyDerivation.java
index 1d091bf..f10b215 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/KemKeyDerivation.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/KemKeyDerivation.java
@@ -23,9 +23,9 @@ final class KemKeyDerivation {
* Derives a KEK bound to the KEM algorithm identifier.
*
* @param sharedSecret KEM shared secret
- * @param salt HKDF salt
- * @param algorithmId canonical KEM algorithm identifier
- * @param outputBytes requested KEK size
+ * @param salt HKDF salt
+ * @param algorithmId canonical KEM algorithm identifier
+ * @param outputBytes requested KEK size
* @return newly allocated KEK bytes
* @throws GeneralSecurityException if HKDF fails
*/
diff --git a/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientContent.java b/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientContent.java
index 69a108f..782d99f 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientContent.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientContent.java
@@ -46,17 +46,17 @@ import zeroecho.sdk.content.api.DataContent;
* resources until processing or explicit cleanup.
*
*
- * Callers must invoke {@link #close()} when a built instance is abandoned before
- * {@link #getStream()} is called. Successful or failed stream construction also
- * releases the owned recipient resources. Unlocking keys and password material
- * supplied separately remain caller-owned and are never destroyed by this
- * content.
+ * Callers must invoke {@link #close()} when a built instance is abandoned
+ * before {@link #getStream()} is called. Successful or failed stream
+ * construction also releases the owned recipient resources. Unlocking keys and
+ * password material supplied separately remain caller-owned and are never
+ * destroyed by this content.
*
*
*
- * Implementations are not thread-safe. Cleanup is idempotent, and content cannot
- * be used after cleanup. Calling {@link #getStream()} is terminal even when stream
- * construction fails.
+ * Implementations are not thread-safe. Cleanup is idempotent, and content
+ * cannot be used after cleanup. Calling {@link #getStream()} is terminal even
+ * when stream construction fails.
*
*/
public interface MultiRecipientContent extends DataContent, Destroyable, AutoCloseable {
diff --git a/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientDataSourceBuilder.java b/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientDataSourceBuilder.java
index dcadd2d..d9fe14e 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientDataSourceBuilder.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/MultiRecipientDataSourceBuilder.java
@@ -215,8 +215,8 @@ public final class MultiRecipientDataSourceBuilder
ensureOpen();
RecipientKekSizes.requireSupported(kekBytes);
session.pbkdf2Limits().validateTrusted(iterations);
- this.recipients.add(new PasswordRecipient(password, iterations, saltLen, kekBytes, false,
- session.pbkdf2Limits()));
+ this.recipients
+ .add(new PasswordRecipient(password, iterations, saltLen, kekBytes, false, session.pbkdf2Limits()));
return this;
}
@@ -236,8 +236,7 @@ public final class MultiRecipientDataSourceBuilder
* @param saltLen HKDF salt length in bytes
* @return this builder
* @throws NullPointerException if {@code kem} is {@code null}
- * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or
- * 32
+ * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or 32
*/
public MultiRecipientDataSourceBuilder addRecipient(KemContext kem, int kekBytes, int saltLen) {
ensureOpen();
@@ -292,8 +291,8 @@ public final class MultiRecipientDataSourceBuilder
ensureOpen();
RecipientKekSizes.requireSupported(kekBytes);
session.pbkdf2Limits().validateTrusted(iterations);
- this.recipients.add(new PasswordRecipient(password, iterations, saltLen, kekBytes, true,
- session.pbkdf2Limits()));
+ this.recipients
+ .add(new PasswordRecipient(password, iterations, saltLen, kekBytes, true, session.pbkdf2Limits()));
return this;
}
@@ -314,8 +313,7 @@ public final class MultiRecipientDataSourceBuilder
* @param saltLen HKDF salt length in bytes
* @return this builder
* @throws NullPointerException if {@code kem} is {@code null}
- * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or
- * 32
+ * @throws IllegalArgumentException if {@code kekBytes} is not exactly 16 or 32
*/
public MultiRecipientDataSourceBuilder addRecipientDecoy(KemContext kem, int kekBytes, int saltLen) {
ensureOpen();
@@ -384,9 +382,9 @@ public final class MultiRecipientDataSourceBuilder
*
*
*
- * The builder takes ownership of the opener. The opener must be reusable
- * across all recipient entries and is closed after scanning or when the built
- * content is abandoned.
+ * The builder takes ownership of the opener. The opener must be reusable across
+ * all recipient entries and is closed after scanning or when the built content
+ * is abandoned.
*
*
* @param opener reusable opener to add
@@ -479,8 +477,10 @@ public final class MultiRecipientDataSourceBuilder
/**
* Destroys recipient secrets still owned by this builder.
*
- * Recipients transferred to a successfully built encrypting content object
- * are owned and destroyed by that object instead.
+ *
+ * Recipients transferred to a successfully built encrypting content object are
+ * owned and destroyed by that object instead.
+ *
*
* @throws DestroyFailedException if recipient cleanup fails
*/
diff --git a/lib/src/main/java/zeroecho/sdk/guard/PasswordOpener.java b/lib/src/main/java/zeroecho/sdk/guard/PasswordOpener.java
index ffc0520..54a7f6a 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/PasswordOpener.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/PasswordOpener.java
@@ -58,6 +58,7 @@ public final class PasswordOpener implements RecipientOpener {
public PasswordOpener(Pbkdf2Limits limits) {
this.limits = java.util.Objects.requireNonNull(limits, "limits must not be null");
}
+
/**
* Attempts to open a password-based recipient entry using a password unlock
* material.
diff --git a/lib/src/main/java/zeroecho/sdk/guard/PasswordRecipient.java b/lib/src/main/java/zeroecho/sdk/guard/PasswordRecipient.java
index 61fee1d..04d67c3 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/PasswordRecipient.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/PasswordRecipient.java
@@ -76,8 +76,8 @@ public final class PasswordRecipient implements Recipient, Destroyable, AutoClos
* The caller should clear the {@code password} array after constructing the
* recipient to minimize exposure in memory.
* Choose an iteration count appropriate to the target platform to balance
- * password-guessing resistance against recipient creation and opening
- * latency. Counts below {@value Pbkdf2Limits#MINIMUM} are rejected.
+ * password-guessing resistance against recipient creation and opening latency.
+ * Counts below {@value Pbkdf2Limits#MINIMUM} are rejected.
* Decoy recipients increase confidentiality by hiding the number of real
* recipients but cannot successfully unwrap the CEK.
*
diff --git a/lib/src/main/java/zeroecho/sdk/guard/RecipientKekSizes.java b/lib/src/main/java/zeroecho/sdk/guard/RecipientKekSizes.java
index f4c671a..4ea24f9 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/RecipientKekSizes.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/RecipientKekSizes.java
@@ -8,9 +8,11 @@ package zeroecho.sdk.guard;
* Defines the KEK sizes supported by recipient entries without an encoded size
* discriminator.
*
- * The current recipient format permits AES-128 and AES-256 wrapping only.
+ *
+ * The current recipient format permits AES-128 and AES-256 wrapping only.
* Validation must occur before an entry is registered so every emitted entry
- * remains openable by the corresponding recipient opener.
+ * remains openable by the corresponding recipient opener.
+ *
*
* @since 1.0
*/
diff --git a/lib/src/main/java/zeroecho/sdk/guard/UnlockMaterial.java b/lib/src/main/java/zeroecho/sdk/guard/UnlockMaterial.java
index cbb04fa..5d78e12 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/UnlockMaterial.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/UnlockMaterial.java
@@ -18,9 +18,11 @@ import zeroecho.core.annotation.Describable;
/**
* Caller-owned session-operation input used to unlock a recipient entry.
*
- * Components accepting an {@code UnlockMaterial} borrow it and do not destroy
+ *
+ * Components accepting an {@code UnlockMaterial} borrow it and do not destroy
* it. The caller must keep it usable until the operation completes and destroy
- * password material afterwards.
+ * password material afterwards.
+ *
*/
public sealed interface UnlockMaterial extends Describable {
/**
@@ -44,8 +46,10 @@ public sealed interface UnlockMaterial extends Describable {
/**
* Destroyable password unlocking material backed by an owned character array.
*
- * Construction and access use defensive copies. Destruction is idempotent
- * and prevents subsequent access.
+ *
+ * Construction and access use defensive copies. Destruction is idempotent and
+ * prevents subsequent access.
+ *
*/
final class Password implements UnlockMaterial, Destroyable {
private final char[] characters;
diff --git a/lib/src/main/java/zeroecho/sdk/guard/package-info.java b/lib/src/main/java/zeroecho/sdk/guard/package-info.java
index 954d73a..ab6483f 100644
--- a/lib/src/main/java/zeroecho/sdk/guard/package-info.java
+++ b/lib/src/main/java/zeroecho/sdk/guard/package-info.java
@@ -108,8 +108,8 @@
* generation and recipient entries; the symmetric builder manages algorithm
* parameters and payload framing.
* Reusable opener strategies: recipients encode entries;
- * openers attempt every applicable entry and create fresh cryptographic contexts
- * per attempt. Neither carries long-lived secret state.
+ * openers attempt every applicable entry and create fresh cryptographic
+ * contexts per attempt. Neither carries long-lived secret state.
* Defensive parsing: the builder applies limits to the
* number of recipients and the size of each entry blob; the symmetric stage
* applies its own limits to its header and payload.
diff --git a/lib/src/main/java/zeroecho/sdk/hybrid/derived/HybridDerived.java b/lib/src/main/java/zeroecho/sdk/hybrid/derived/HybridDerived.java
index 8ecd03a..ac55771 100644
--- a/lib/src/main/java/zeroecho/sdk/hybrid/derived/HybridDerived.java
+++ b/lib/src/main/java/zeroecho/sdk/hybrid/derived/HybridDerived.java
@@ -196,8 +196,8 @@ public final class HybridDerived {
* construction.
*
*
- * @param aes AES builder to configure (must not be null)
- * @param keyBits AES key size in bits (128/192/256)
+ * @param aes AES builder to configure (must not be null)
+ * @param keyBits AES key size in bits (128/192/256)
* @return the provided builder instance
* @throws NullPointerException if aes is null
* @throws IllegalArgumentException if keyBits is invalid
@@ -225,16 +225,16 @@ public final class HybridDerived {
}
/**
- * Derives a ChaCha key and applies it with optional AAD to the provided
- * ChaCha builder.
+ * Derives a ChaCha key and applies it with optional AAD to the provided ChaCha
+ * builder.
*
*
* The returned value is the same builder instance to preserve fluent pipeline
* construction.
*
*
- * @param chacha ChaCha builder to configure (must not be null)
- * @param keyBits key size in bits (typically 256)
+ * @param chacha ChaCha builder to configure (must not be null)
+ * @param keyBits key size in bits (typically 256)
* @return the provided builder instance
* @throws NullPointerException if chacha is null
* @throws IllegalArgumentException if keyBits is invalid
diff --git a/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContext.java b/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContext.java
index 38cfd8f..ad6042f 100644
--- a/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContext.java
+++ b/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContext.java
@@ -150,8 +150,8 @@ public final class HybridKexContext implements MessageAgreementContext {
this(profile, classic, pqc, Kdf::hkdfSha256);
}
- /* default */ HybridKexContext(HybridKexProfile profile, AgreementContext classic,
- MessageAgreementContext pqc, SecretDeriver secretDeriver) {
+ /* default */ HybridKexContext(HybridKexProfile profile, AgreementContext classic, MessageAgreementContext pqc,
+ SecretDeriver secretDeriver) {
this.profile = Objects.requireNonNull(profile, "profile");
this.classic = Objects.requireNonNull(classic, "classic");
this.pqc = Objects.requireNonNull(pqc, "pqc");
@@ -358,15 +358,14 @@ public final class HybridKexContext implements MessageAgreementContext {
/**
* Derives the final output from owned temporary hybrid input.
*
- * @param ikm combined component secrets
- * @param salt HKDF salt
- * @param info HKDF context information
+ * @param ikm combined component secrets
+ * @param salt HKDF salt
+ * @param info HKDF context information
* @param outputLength requested output length
* @return derived output transferred to the caller
* @throws GeneralSecurityException if derivation fails
*/
- byte[] derive(byte[] ikm, byte[] salt, byte[] info, int outputLength)
- throws GeneralSecurityException;
+ byte[] derive(byte[] ikm, byte[] salt, byte[] info, int outputLength) throws GeneralSecurityException;
}
/**
diff --git a/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContexts.java b/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContexts.java
index 2e0ad74..59b2853 100644
--- a/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContexts.java
+++ b/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexContexts.java
@@ -83,9 +83,11 @@ import zeroecho.sdk.ZeroEchoSession;
*
*
* Error handling
- * Context construction is in-memory and reports configuration or provider
- * failures through the security exception model of {@link ZeroEchoSession}.
- * I/O failures remain associated with later stream processing.
+ *
+ * Context construction is in-memory and reports configuration or provider
+ * failures through the security exception model of {@link ZeroEchoSession}. I/O
+ * failures remain associated with later stream processing.
+ *
*
* Thread safety
*
@@ -158,8 +160,7 @@ public final class HybridKexContexts {
AgreementContext classic = null;
MessageAgreementContext pqc = null;
try {
- classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicInitiatorPrivate,
- classicSpec);
+ classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicInitiatorPrivate, classicSpec);
classic.setPeerPublic(classicPeerPublic);
pqc = session.createContext(pqcAlgId, KeyUsage.AGREEMENT, pqcPeerPublic, pqcSpec);
return new HybridKexContext(profile, classic, pqc);
@@ -222,8 +223,7 @@ public final class HybridKexContexts {
AgreementContext classic = null;
MessageAgreementContext pqc = null;
try {
- classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicResponderPrivate,
- classicSpec);
+ classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicResponderPrivate, classicSpec);
classic.setPeerPublic(classicPeerPublic);
pqc = session.createContext(pqcAlgId, KeyUsage.AGREEMENT, pqcResponderPrivate, pqcSpec);
return new HybridKexContext(profile, classic, pqc);
@@ -262,9 +262,8 @@ public final class HybridKexContexts {
* @throws NullPointerException if any required argument is {@code null}
*/
public static HybridKexContext initiatorPairMessage(ZeroEchoSession session, HybridKexProfile profile,
- String classicAlgId,
- zeroecho.core.alg.common.agreement.KeyPairKey classicInitiatorKeyPair, ContextSpec classicSpec,
- String pqcAlgId, PublicKey pqcPeerPublic, ContextSpec pqcSpec) {
+ String classicAlgId, zeroecho.core.alg.common.agreement.KeyPairKey classicInitiatorKeyPair,
+ ContextSpec classicSpec, String pqcAlgId, PublicKey pqcPeerPublic, ContextSpec pqcSpec) {
Objects.requireNonNull(session, "session");
Objects.requireNonNull(profile, "profile");
@@ -276,8 +275,7 @@ public final class HybridKexContexts {
MessageAgreementContext classic = null;
MessageAgreementContext pqc = null;
try {
- classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicInitiatorKeyPair,
- classicSpec);
+ classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicInitiatorKeyPair, classicSpec);
pqc = session.createContext(pqcAlgId, KeyUsage.AGREEMENT, pqcPeerPublic, pqcSpec);
return new HybridKexContext(profile, classic, pqc);
} catch (RuntimeException | Error failure) { // NOPMD - close partial construction
@@ -312,9 +310,8 @@ public final class HybridKexContexts {
* @throws NullPointerException if any required argument is {@code null}
*/
public static HybridKexContext responderPairMessage(ZeroEchoSession session, HybridKexProfile profile,
- String classicAlgId,
- zeroecho.core.alg.common.agreement.KeyPairKey classicResponderKeyPair, ContextSpec classicSpec,
- String pqcAlgId, PrivateKey pqcResponderPrivate, ContextSpec pqcSpec) {
+ String classicAlgId, zeroecho.core.alg.common.agreement.KeyPairKey classicResponderKeyPair,
+ ContextSpec classicSpec, String pqcAlgId, PrivateKey pqcResponderPrivate, ContextSpec pqcSpec) {
Objects.requireNonNull(session, "session");
Objects.requireNonNull(profile, "profile");
@@ -326,8 +323,7 @@ public final class HybridKexContexts {
MessageAgreementContext classic = null;
MessageAgreementContext pqc = null;
try {
- classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicResponderKeyPair,
- classicSpec);
+ classic = session.createContext(classicAlgId, KeyUsage.AGREEMENT, classicResponderKeyPair, classicSpec);
pqc = session.createContext(pqcAlgId, KeyUsage.AGREEMENT, pqcResponderPrivate, pqcSpec);
return new HybridKexContext(profile, classic, pqc);
} catch (RuntimeException | Error failure) { // NOPMD - close partial construction
diff --git a/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexExporter.java b/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexExporter.java
index 825bae7..48cacd3 100644
--- a/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexExporter.java
+++ b/lib/src/main/java/zeroecho/sdk/hybrid/kex/HybridKexExporter.java
@@ -155,8 +155,10 @@ public final class HybridKexExporter implements Destroyable, AutoCloseable {
/**
* Overwrites the exporter root secret and salt.
*
- *
Destruction is idempotent. All subsequent export or diagnostic access
- * fails with {@link IllegalStateException}.
+ *
+ * Destruction is idempotent. All subsequent export or diagnostic access fails
+ * with {@link IllegalStateException}.
+ *
*/
@Override
public void destroy() {
diff --git a/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContext.java b/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContext.java
index f25a5d1..a006a0c 100644
--- a/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContext.java
+++ b/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContext.java
@@ -118,8 +118,7 @@ final class HybridSignatureContext implements SignatureContext {
* @throws IllegalArgumentException if {@code maxBufferedBytes <= 0}
*/
/* default */ HybridSignatureContext(ZeroEchoSession session, HybridSignatureProfile profile,
- PrivateKey classicPrivate,
- PrivateKey pqcPrivate, int maxBufferedBytes) {
+ PrivateKey classicPrivate, PrivateKey pqcPrivate, int maxBufferedBytes) {
this.session = Objects.requireNonNull(session, "session");
this.profile = Objects.requireNonNull(profile, "profile");
this.classicPrivate = Objects.requireNonNull(classicPrivate, "classicPrivate");
@@ -151,8 +150,7 @@ final class HybridSignatureContext implements SignatureContext {
* @throws IllegalArgumentException if {@code maxBufferedBytes <= 0}
*/
/* default */ HybridSignatureContext(ZeroEchoSession session, HybridSignatureProfile profile,
- PublicKey classicPublic,
- PublicKey pqcPublic, int maxBufferedBytes) {
+ PublicKey classicPublic, PublicKey pqcPublic, int maxBufferedBytes) {
this.session = Objects.requireNonNull(session, "session");
this.profile = Objects.requireNonNull(profile, "profile");
this.classicPublic = Objects.requireNonNull(classicPublic, "classicPublic");
diff --git a/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContexts.java b/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContexts.java
index 5930b17..73b71ab 100644
--- a/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContexts.java
+++ b/lib/src/main/java/zeroecho/sdk/hybrid/signature/HybridSignatureContexts.java
@@ -69,8 +69,7 @@ public final class HybridSignatureContexts {
* @since 1.0
*/
public static SignatureContext sign(ZeroEchoSession session, HybridSignatureProfile profile,
- PrivateKey classicPrivate,
- PrivateKey pqcPrivate, int maxBufferedBytes) {
+ PrivateKey classicPrivate, PrivateKey pqcPrivate, int maxBufferedBytes) {
Objects.requireNonNull(session, "session");
Objects.requireNonNull(profile, "profile");
Objects.requireNonNull(classicPrivate, "classicPrivate");
diff --git a/lib/src/main/java/zeroecho/sdk/util/Password.java b/lib/src/main/java/zeroecho/sdk/util/Password.java
index 8a397e7..469ff60 100644
--- a/lib/src/main/java/zeroecho/sdk/util/Password.java
+++ b/lib/src/main/java/zeroecho/sdk/util/Password.java
@@ -35,7 +35,6 @@ package zeroecho.sdk.util;
import zeroecho.core.util.RandomSupport;
-
/**
* Utility class for generating random passwords and secure random byte arrays.
*
diff --git a/lib/src/test/java/zeroecho/core/CapabilityValueSemanticsTest.java b/lib/src/test/java/zeroecho/core/CapabilityValueSemanticsTest.java
index e5fc63f..85648af 100644
--- a/lib/src/test/java/zeroecho/core/CapabilityValueSemanticsTest.java
+++ b/lib/src/test/java/zeroecho/core/CapabilityValueSemanticsTest.java
@@ -74,9 +74,8 @@ class CapabilityValueSemanticsTest {
void nullAndIncompatibleDefaultsAreRejectedAtConstruction() {
System.out.println("nullAndIncompatibleDefaultsAreRejectedAtConstruction");
assertThrows(NullPointerException.class, () -> capability(() -> null));
- assertThrows(IllegalArgumentException.class,
- () -> new Capability("DIGEST", AlgorithmFamily.DIGEST, KeyUsage.DIGEST, DigestContext.class,
- NullKey.class, TestSpec.class, new OtherSpec()));
+ assertThrows(IllegalArgumentException.class, () -> new Capability("DIGEST", AlgorithmFamily.DIGEST,
+ KeyUsage.DIGEST, DigestContext.class, NullKey.class, TestSpec.class, new OtherSpec()));
System.out.println("...invalidDefaultsRejected=true");
System.out.println("nullAndIncompatibleDefaultsAreRejectedAtConstruction...ok");
@@ -121,8 +120,7 @@ class CapabilityValueSemanticsTest {
(key, spec) -> {
runtimeSpecs.add(spec);
return mock(DigestContext.class);
- },
- () -> new TestSpec(Integer.toString(evaluations.incrementAndGet())));
+ }, () -> new TestSpec(Integer.toString(evaluations.incrementAndGet())));
}
}
}
diff --git a/lib/src/test/java/zeroecho/core/CatalogContractTest.java b/lib/src/test/java/zeroecho/core/CatalogContractTest.java
index 38ceb5b..f75342e 100644
--- a/lib/src/test/java/zeroecho/core/CatalogContractTest.java
+++ b/lib/src/test/java/zeroecho/core/CatalogContractTest.java
@@ -105,9 +105,10 @@ public class CatalogContractTest {
Logger jul = Logger.getLogger("zeroecho.audit");
jul.setLevel(Level.FINE); // see PROGRESS at FINE
- session = new ZeroEchoSession().withAuditListener(JulAuditListenerStd.builder().logger(jul)
- .infoLevel(Level.INFO).warnLevel(Level.WARNING).progressLevel(Level.FINE)
- .includeStackTraces(true).build()).withAuditMode(AuditMode.WRAP);
+ session = new ZeroEchoSession()
+ .withAuditListener(JulAuditListenerStd.builder().logger(jul).infoLevel(Level.INFO)
+ .warnLevel(Level.WARNING).progressLevel(Level.FINE).includeStackTraces(true).build())
+ .withAuditMode(AuditMode.WRAP);
dump("");
dump("zeroecho.core.audit");
@@ -178,8 +179,7 @@ public class CatalogContractTest {
.anyMatch(info -> info.operation() == KeyOperation.SYMMETRIC_GENERATE);
// SIGN/VERIFY (asymmetric)
- if (alg.roles().contains(KeyUsage.SIGN) && alg.roles().contains(KeyUsage.VERIFY)
- && hasAsym) {
+ if (alg.roles().contains(KeyUsage.SIGN) && alg.roles().contains(KeyUsage.VERIFY) && hasAsym) {
trySignVerify(id, msg);
System.out.println();
}
@@ -193,8 +193,7 @@ public class CatalogContractTest {
}
// KEM
- if (alg.roles().contains(KeyUsage.ENCAPSULATE) && alg.roles().contains(KeyUsage.DECAPSULATE)
- && hasAsym) {
+ if (alg.roles().contains(KeyUsage.ENCAPSULATE) && alg.roles().contains(KeyUsage.DECAPSULATE) && hasAsym) {
tryKem(id, msg);
System.out.println();
}
diff --git a/lib/src/test/java/zeroecho/core/CryptoAlgorithmsAuditWrapTest.java b/lib/src/test/java/zeroecho/core/CryptoAlgorithmsAuditWrapTest.java
index 04f515c..59811cf 100644
--- a/lib/src/test/java/zeroecho/core/CryptoAlgorithmsAuditWrapTest.java
+++ b/lib/src/test/java/zeroecho/core/CryptoAlgorithmsAuditWrapTest.java
@@ -74,10 +74,10 @@ import zeroecho.core.tag.TagEngine;
*
*
* These tests focus on the internal audit wrapping path used by
- * {@link AuditedContexts#wrap(CryptoContext, AuditListener, KeyUsage)}.
- * They verify that representative context types are wrapped as audited JDK
- * proxies and that the resulting wrapper preserves the expected basic
- * delegation behavior.
+ * {@link AuditedContexts#wrap(CryptoContext, AuditListener, KeyUsage)}. They
+ * verify that representative context types are wrapped as audited JDK proxies
+ * and that the resulting wrapper preserves the expected basic delegation
+ * behavior.
*
*/
class CryptoAlgorithmsAuditWrapTest {
diff --git a/lib/src/test/java/zeroecho/core/CryptoArchitectureTest.java b/lib/src/test/java/zeroecho/core/CryptoArchitectureTest.java
index fb01a12..a511862 100644
--- a/lib/src/test/java/zeroecho/core/CryptoArchitectureTest.java
+++ b/lib/src/test/java/zeroecho/core/CryptoArchitectureTest.java
@@ -27,7 +27,8 @@ import zeroecho.core.context.DigestContext;
import zeroecho.sdk.ZeroEchoSession;
/**
- * Verifies authoritative registry ownership and explicitly scoped runtime state.
+ * Verifies authoritative registry ownership and explicitly scoped runtime
+ * state.
*/
class CryptoArchitectureTest {
@@ -51,8 +52,8 @@ class CryptoArchitectureTest {
System.out.println("explicitPolicyOrder");
List events = new ArrayList<>();
AuditListener listener = policyOrderListener(events);
- ZeroEchoSession allowed = new ZeroEchoSession().withAuditListener(listener).withPolicy(
- (id, role, key, spec) -> events.add("policy"));
+ ZeroEchoSession allowed = new ZeroEchoSession().withAuditListener(listener)
+ .withPolicy((id, role, key, spec) -> events.add("policy"));
try (DigestContext context = allowed.createContext("DIGEST", KeyUsage.DIGEST, NullKey.INSTANCE)) {
assertSame(CryptoAlgorithms.require("DIGEST"), context.algorithm());
}
@@ -60,19 +61,18 @@ class CryptoArchitectureTest {
events.clear();
IllegalArgumentException denial = new IllegalArgumentException("controlled denial");
- ZeroEchoSession denied = new ZeroEchoSession().withAuditListener(listener).withPolicy(
- (id, role, key, spec) -> {
- events.add("policy");
- throw denial;
- });
+ ZeroEchoSession denied = new ZeroEchoSession().withAuditListener(listener).withPolicy((id, role, key, spec) -> {
+ events.add("policy");
+ throw denial;
+ });
assertSame(denial, assertThrows(IllegalArgumentException.class,
() -> denied.createContext("DIGEST", KeyUsage.DIGEST, NullKey.INSTANCE)));
assertEquals(List.of("policy"), events);
events.clear();
IllegalStateException failure = new IllegalStateException("controlled policy failure");
- ZeroEchoSession failing = new ZeroEchoSession().withAuditListener(listener).withPolicy(
- (id, role, key, spec) -> {
+ ZeroEchoSession failing = new ZeroEchoSession().withAuditListener(listener)
+ .withPolicy((id, role, key, spec) -> {
events.add("policy");
throw failure;
});
@@ -91,8 +91,7 @@ class CryptoArchitectureTest {
AtomicInteger secondEvents = new AtomicInteger();
AuditListener firstListener = contextListener(firstEvents);
AuditListener secondListener = contextListener(secondEvents);
- ZeroEchoSession wrapped = new ZeroEchoSession().withAuditListener(firstListener)
- .withAuditMode(AuditMode.WRAP);
+ ZeroEchoSession wrapped = new ZeroEchoSession().withAuditListener(firstListener).withAuditMode(AuditMode.WRAP);
ZeroEchoSession direct = new ZeroEchoSession().withAuditListener(secondListener);
try (DigestContext wrappedContext = wrapped.createContext("DIGEST", KeyUsage.DIGEST, NullKey.INSTANCE)) {
diff --git a/lib/src/test/java/zeroecho/core/SecretSpecLifecycleTest.java b/lib/src/test/java/zeroecho/core/SecretSpecLifecycleTest.java
index 40793ae..c67a7f8 100644
--- a/lib/src/test/java/zeroecho/core/SecretSpecLifecycleTest.java
+++ b/lib/src/test/java/zeroecho/core/SecretSpecLifecycleTest.java
@@ -58,15 +58,12 @@ class SecretSpecLifecycleTest {
new SpecCase("zeroecho.core.alg.kyber.KyberPrivateKeySpec", "pkcs8", 8, Factory.CONSTRUCTOR),
new SpecCase("zeroecho.core.alg.mldsa.MldsaPrivateKeySpec", "encoded", 8, Factory.CONSTRUCTOR),
new SpecCase("zeroecho.core.alg.ntru.NtruPrivateKeySpec", "pkcs8", 8, Factory.CONSTRUCTOR),
- new SpecCase("zeroecho.core.alg.ntruprime.NtrulPrimePrivateKeySpec", "pkcs8", 8,
- Factory.CONSTRUCTOR),
- new SpecCase("zeroecho.core.alg.ntruprime.SntruPrimePrivateKeySpec", "pkcs8", 8,
- Factory.CONSTRUCTOR),
+ new SpecCase("zeroecho.core.alg.ntruprime.NtrulPrimePrivateKeySpec", "pkcs8", 8, Factory.CONSTRUCTOR),
+ new SpecCase("zeroecho.core.alg.ntruprime.SntruPrimePrivateKeySpec", "pkcs8", 8, Factory.CONSTRUCTOR),
new SpecCase("zeroecho.core.alg.rsa.RsaPrivateKeySpec", "encoded", 8, Factory.CONSTRUCTOR),
new SpecCase("zeroecho.core.alg.saber.SaberPrivateKeySpec", "pkcs8", 8, Factory.CONSTRUCTOR),
new SpecCase("zeroecho.core.alg.slhdsa.SlhDsaPrivateKeySpec", "encoded", 8, Factory.CONSTRUCTOR),
- new SpecCase("zeroecho.core.alg.sphincsplus.SphincsPlusPrivateKeySpec", "encoded", 8,
- Factory.CONSTRUCTOR),
+ new SpecCase("zeroecho.core.alg.sphincsplus.SphincsPlusPrivateKeySpec", "encoded", 8, Factory.CONSTRUCTOR),
new SpecCase("zeroecho.core.alg.xdh.XdhPrivateKeySpec", "encoded", 8, Factory.CONSTRUCTOR));
@Test
@@ -131,14 +128,14 @@ class SecretSpecLifecycleTest {
() -> AesKeyImportSpec.unmarshal(PairSeq.of("k.b64", aesKey, "k.b64", "%")));
assertThrows(IllegalArgumentException.class,
() -> ChaChaKeyImportSpec.unmarshal(PairSeq.of("k.b64", chachaKey, "k.b64", "%")));
- assertThrows(IllegalArgumentException.class, () -> HmacKeyImportSpec.unmarshal(
- PairSeq.of("mac", "HmacSHA256", "k.b64", encodedPrivateKey, "k.b64", "%")));
- assertThrows(IllegalArgumentException.class, () -> MldsaPrivateKeySpec.unmarshal(
- PairSeq.of("pkcs8.b64", encodedPrivateKey, "pkcs8.b64", "%")));
- assertThrows(IllegalArgumentException.class, () -> SlhDsaPrivateKeySpec.unmarshal(
- PairSeq.of("pkcs8.b64", encodedPrivateKey, "pkcs8.b64", "%")));
- assertThrows(IllegalArgumentException.class, () -> SphincsPlusPrivateKeySpec.unmarshal(
- PairSeq.of("pkcs8.b64", encodedPrivateKey, "pkcs8.b64", "%")));
+ assertThrows(IllegalArgumentException.class, () -> HmacKeyImportSpec
+ .unmarshal(PairSeq.of("mac", "HmacSHA256", "k.b64", encodedPrivateKey, "k.b64", "%")));
+ assertThrows(IllegalArgumentException.class,
+ () -> MldsaPrivateKeySpec.unmarshal(PairSeq.of("pkcs8.b64", encodedPrivateKey, "pkcs8.b64", "%")));
+ assertThrows(IllegalArgumentException.class,
+ () -> SlhDsaPrivateKeySpec.unmarshal(PairSeq.of("pkcs8.b64", encodedPrivateKey, "pkcs8.b64", "%")));
+ assertThrows(IllegalArgumentException.class, () -> SphincsPlusPrivateKeySpec
+ .unmarshal(PairSeq.of("pkcs8.b64", encodedPrivateKey, "pkcs8.b64", "%")));
System.out.println("...cases=6");
System.out.println("unmarshalCleansUpWhenMalformedDataFollowsValidSecretMaterial...ok");
}
@@ -195,7 +192,8 @@ class SecretSpecLifecycleTest {
generator.initialize(2048);
KeyPair pair = generator.generateKeyPair();
RsaPrivateKeySpec rsaSpec = new RsaPrivateKeySpec(pair.getPrivate().getEncoded());
- PrivateKey imported = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().importPrivate("RSA", rsaSpec);
+ PrivateKey imported = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().importPrivate("RSA",
+ rsaSpec);
assertArrayEquals(pair.getPrivate().getEncoded(), imported.getEncoded());
assertFalse(rsaSpec.isDestroyed());
assertArrayEquals(pair.getPrivate().getEncoded(), rsaSpec.encoded());
@@ -221,9 +219,7 @@ class SecretSpecLifecycleTest {
}
private enum Factory {
- CONSTRUCTOR,
- STATIC_RAW,
- HMAC
+ CONSTRUCTOR, STATIC_RAW, HMAC
}
private record SpecCase(String className, String accessor, int length, Factory factory) {
diff --git a/lib/src/test/java/zeroecho/core/TargetArchitectureTest.java b/lib/src/test/java/zeroecho/core/TargetArchitectureTest.java
index afd61d5..d7e3b7f 100644
--- a/lib/src/test/java/zeroecho/core/TargetArchitectureTest.java
+++ b/lib/src/test/java/zeroecho/core/TargetArchitectureTest.java
@@ -60,12 +60,9 @@ class TargetArchitectureTest {
@Test
void obsoleteArchitectureTypesAreAbsent() {
String name = start("obsoleteArchitectureTypesAreAbsent");
- assertThrows(ClassNotFoundException.class,
- () -> Class.forName("zeroecho.core.spi.ContextConstructorKS"));
- assertThrows(ClassNotFoundException.class,
- () -> Class.forName("zeroecho.core.spi.SymmetricKeyBuilder"));
- assertThrows(ClassNotFoundException.class,
- () -> Class.forName("zeroecho.core.spi.AsymmetricKeyBuilder"));
+ assertThrows(ClassNotFoundException.class, () -> Class.forName("zeroecho.core.spi.ContextConstructorKS"));
+ assertThrows(ClassNotFoundException.class, () -> Class.forName("zeroecho.core.spi.SymmetricKeyBuilder"));
+ assertThrows(ClassNotFoundException.class, () -> Class.forName("zeroecho.core.spi.AsymmetricKeyBuilder"));
for (Method method : CryptoAlgorithms.class.getDeclaredMethods()) {
if (Modifier.isPublic(method.getModifiers()) && Modifier.isStatic(method.getModifiers())) {
@@ -76,8 +73,8 @@ class TargetArchitectureTest {
for (Field field : CryptoAlgorithms.class.getDeclaredFields()) {
assertTrue(Modifier.isFinal(field.getModifiers()), field.toString());
}
- Set removedConveniences = Set.of("generateSecret", "importSecret", "generateKeyPair",
- "importPublic", "importPrivate");
+ Set removedConveniences = Set.of("generateSecret", "importSecret", "generateKeyPair", "importPublic",
+ "importPrivate");
for (Method method : CryptoAlgorithm.class.getDeclaredMethods()) {
assertFalse(removedConveniences.contains(method.getName()), method.toString());
}
@@ -98,14 +95,13 @@ class TargetArchitectureTest {
String name = start("auditListenerFailureCannotChangeOperationOutcome");
AuditListener failing = new AuditListener() {
@Override
- public void onContextCreatedMeta(String contextId, String algorithmId, String provider,
- KeyUsage role, String keyFingerprint, Map metadata) {
+ public void onContextCreatedMeta(String contextId, String algorithmId, String provider, KeyUsage role,
+ String keyFingerprint, Map metadata) {
throw new AssertionError("controlled listener failure");
}
@Override
- public void onContextClosed(String contextId, long bodyBytes, long trailerBytes,
- long durationMillis) {
+ public void onContextClosed(String contextId, long bodyBytes, long trailerBytes, long durationMillis) {
throw new AssertionError("controlled listener failure");
}
};
@@ -127,14 +123,10 @@ class TargetArchitectureTest {
switch (info.operation()) {
case ASYMMETRIC_KEY_PAIR_GENERATE ->
assertDoesNotThrow(() -> algorithm.asymmetricKeyPairGenerator(specType));
- case ASYMMETRIC_PUBLIC_IMPORT ->
- assertDoesNotThrow(() -> algorithm.publicKeyImporter(specType));
- case ASYMMETRIC_PRIVATE_IMPORT ->
- assertDoesNotThrow(() -> algorithm.privateKeyImporter(specType));
- case SYMMETRIC_GENERATE ->
- assertDoesNotThrow(() -> algorithm.symmetricKeyGenerator(specType));
- case SYMMETRIC_IMPORT ->
- assertDoesNotThrow(() -> algorithm.symmetricKeyImporter(specType));
+ case ASYMMETRIC_PUBLIC_IMPORT -> assertDoesNotThrow(() -> algorithm.publicKeyImporter(specType));
+ case ASYMMETRIC_PRIVATE_IMPORT -> assertDoesNotThrow(() -> algorithm.privateKeyImporter(specType));
+ case SYMMETRIC_GENERATE -> assertDoesNotThrow(() -> algorithm.symmetricKeyGenerator(specType));
+ case SYMMETRIC_IMPORT -> assertDoesNotThrow(() -> algorithm.symmetricKeyImporter(specType));
}
}
diff --git a/lib/src/test/java/zeroecho/core/ZeroEchoSessionWrapIntegrationTest.java b/lib/src/test/java/zeroecho/core/ZeroEchoSessionWrapIntegrationTest.java
index 2141620..e06a133 100644
--- a/lib/src/test/java/zeroecho/core/ZeroEchoSessionWrapIntegrationTest.java
+++ b/lib/src/test/java/zeroecho/core/ZeroEchoSessionWrapIntegrationTest.java
@@ -67,16 +67,16 @@ class ZeroEchoSessionWrapIntegrationTest {
SecretKey aesKey = new SecretKeySpec(new byte[16], "AES");
CtxInterface aesContext = Ctx.INSTANCE.getContext("wrap-integration-" + CONTEXT_IDS.incrementAndGet());
byte[] ciphertext;
- try (EncryptionContext encryption = session.createContext(
- "AES", KeyUsage.ENCRYPT, aesKey, AesSpec.gcm128(null))) {
+ try (EncryptionContext encryption = session.createContext("AES", KeyUsage.ENCRYPT, aesKey,
+ AesSpec.gcm128(null))) {
assertProxy(encryption);
((ContextAware) encryption).setContext(aesContext);
try (InputStream input = encryption.attach(new ByteArrayInputStream(message))) {
ciphertext = input.readAllBytes();
}
}
- try (EncryptionContext decryption = session.createContext(
- "AES", KeyUsage.DECRYPT, aesKey, AesSpec.gcm128(null))) {
+ try (EncryptionContext decryption = session.createContext("AES", KeyUsage.DECRYPT, aesKey,
+ AesSpec.gcm128(null))) {
assertProxy(decryption);
((ContextAware) decryption).setContext(aesContext);
try (InputStream input = decryption.attach(new ByteArrayInputStream(ciphertext))) {
@@ -84,16 +84,14 @@ class ZeroEchoSessionWrapIntegrationTest {
}
}
- KeyPair signingKeys = session.keyBuilders().asymmetric()
- .generateKeyPair("Ed25519", Ed25519KeyGenSpec.defaultSpec());
+ KeyPair signingKeys = session.keyBuilders().asymmetric().generateKeyPair("Ed25519",
+ Ed25519KeyGenSpec.defaultSpec());
TaggedBody signature;
- try (SignatureContext signer = session.createContext(
- "Ed25519", KeyUsage.SIGN, signingKeys.getPrivate())) {
+ try (SignatureContext signer = session.createContext("Ed25519", KeyUsage.SIGN, signingKeys.getPrivate())) {
assertProxy(signer);
signature = produceTag(signer, message);
}
- try (SignatureContext verifier = session.createContext(
- "Ed25519", KeyUsage.VERIFY, signingKeys.getPublic())) {
+ try (SignatureContext verifier = session.createContext("Ed25519", KeyUsage.VERIFY, signingKeys.getPublic())) {
assertProxy(verifier);
verifier.setExpectedTag(signature.tag());
try (InputStream input = verifier.wrap(new ByteArrayInputStream(message))) {
@@ -111,9 +109,7 @@ class ZeroEchoSessionWrapIntegrationTest {
assertArrayEquals(message, produceTag(digest, message).body());
}
- assertEquals(List.of(
- "create:ENCRYPT", "create:DECRYPT",
- "create:SIGN", "tag", "create:VERIFY", "verify:true",
+ assertEquals(List.of("create:ENCRYPT", "create:DECRYPT", "create:SIGN", "tag", "create:VERIFY", "verify:true",
"create:MAC", "tag", "create:DIGEST", "tag"), listener.events);
System.out.println("...contexts=6...events=" + listener.events.size());
System.out.println("registeredStreamContexts...ok");
@@ -127,10 +123,10 @@ class ZeroEchoSessionWrapIntegrationTest {
KeyPair aliceKeys = session.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
KeyPair bobKeys = session.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- try (AgreementContext alice = session.createContext(
- "Xdh", KeyUsage.AGREEMENT, aliceKeys.getPrivate(), XdhSpec.X25519);
- AgreementContext bob = session.createContext(
- "Xdh", KeyUsage.AGREEMENT, bobKeys.getPrivate(), XdhSpec.X25519)) {
+ try (AgreementContext alice = session.createContext("Xdh", KeyUsage.AGREEMENT, aliceKeys.getPrivate(),
+ XdhSpec.X25519);
+ AgreementContext bob = session.createContext("Xdh", KeyUsage.AGREEMENT, bobKeys.getPrivate(),
+ XdhSpec.X25519)) {
assertProxy(alice);
assertProxy(bob);
alice.setPeerPublic(bobKeys.getPublic());
@@ -138,10 +134,10 @@ class ZeroEchoSessionWrapIntegrationTest {
assertArrayEquals(alice.deriveSecret(), bob.deriveSecret());
}
- try (MessageAgreementContext alice = session.createContext(
- "Xdh", KeyUsage.AGREEMENT, new KeyPairKey(aliceKeys), XdhSpec.X25519);
- MessageAgreementContext bob = session.createContext(
- "Xdh", KeyUsage.AGREEMENT, new KeyPairKey(bobKeys), XdhSpec.X25519)) {
+ try (MessageAgreementContext alice = session.createContext("Xdh", KeyUsage.AGREEMENT, new KeyPairKey(aliceKeys),
+ XdhSpec.X25519);
+ MessageAgreementContext bob = session.createContext("Xdh", KeyUsage.AGREEMENT, new KeyPairKey(bobKeys),
+ XdhSpec.X25519)) {
assertProxy(alice);
assertProxy(bob);
byte[] aliceMessage = alice.getPeerMessage();
@@ -151,10 +147,9 @@ class ZeroEchoSessionWrapIntegrationTest {
assertArrayEquals(alice.deriveSecret(), bob.deriveSecret());
}
- assertEquals(List.of(
- "create:AGREEMENT", "create:AGREEMENT", "peer", "peer", "derived", "derived",
- "create:AGREEMENT", "create:AGREEMENT", "message-get", "message-get",
- "message-set", "message-set", "derived", "derived"), listener.events);
+ assertEquals(List.of("create:AGREEMENT", "create:AGREEMENT", "peer", "peer", "derived", "derived",
+ "create:AGREEMENT", "create:AGREEMENT", "message-get", "message-get", "message-set", "message-set",
+ "derived", "derived"), listener.events);
System.out.println("...contexts=4...events=" + listener.events.size());
System.out.println("registeredAgreementContexts...ok");
}
@@ -164,32 +159,30 @@ class ZeroEchoSessionWrapIntegrationTest {
System.out.println("registeredKemContexts");
RecordingListener listener = new RecordingListener();
ZeroEchoSession session = wrappedSession(listener);
- KeyPair recipient = session.keyBuilders().asymmetric()
- .generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
+ KeyPair recipient = session.keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
KemContext.KemResult encapsulated;
- try (KemContext encapsulator = session.createContext(
- "ML-KEM", KeyUsage.ENCAPSULATE, recipient.getPublic(), VoidSpec.INSTANCE);
- KemContext decapsulator = session.createContext(
- "ML-KEM", KeyUsage.DECAPSULATE, recipient.getPrivate(), VoidSpec.INSTANCE)) {
+ try (KemContext encapsulator = session.createContext("ML-KEM", KeyUsage.ENCAPSULATE, recipient.getPublic(),
+ VoidSpec.INSTANCE);
+ KemContext decapsulator = session.createContext("ML-KEM", KeyUsage.DECAPSULATE, recipient.getPrivate(),
+ VoidSpec.INSTANCE)) {
assertProxy(encapsulator);
assertProxy(decapsulator);
encapsulated = encapsulator.encapsulate();
assertArrayEquals(encapsulated.sharedSecret(), decapsulator.decapsulate(encapsulated.ciphertext()));
}
- try (MessageAgreementContext initiator = session.createContext(
- "ML-KEM", KeyUsage.AGREEMENT, recipient.getPublic(), VoidSpec.INSTANCE);
- MessageAgreementContext responder = session.createContext(
- "ML-KEM", KeyUsage.AGREEMENT, recipient.getPrivate(), VoidSpec.INSTANCE)) {
+ try (MessageAgreementContext initiator = session.createContext("ML-KEM", KeyUsage.AGREEMENT,
+ recipient.getPublic(), VoidSpec.INSTANCE);
+ MessageAgreementContext responder = session.createContext("ML-KEM", KeyUsage.AGREEMENT,
+ recipient.getPrivate(), VoidSpec.INSTANCE)) {
assertProxy(initiator);
assertProxy(responder);
responder.setPeerMessage(initiator.getPeerMessage());
assertArrayEquals(initiator.deriveSecret(), responder.deriveSecret());
}
- assertEquals(List.of(
- "create:ENCAPSULATE", "create:DECAPSULATE", "encapsulated", "decapsulated",
+ assertEquals(List.of("create:ENCAPSULATE", "create:DECAPSULATE", "encapsulated", "decapsulated",
"create:AGREEMENT", "create:AGREEMENT", "message-get", "message-set", "derived", "derived"),
listener.events);
System.out.println("...contexts=4...events=" + listener.events.size());
@@ -204,8 +197,8 @@ class ZeroEchoSessionWrapIntegrationTest {
byte[][] tag = new byte[1][];
int tagLength = engine.tagLength();
byte[] emittedBody;
- try (InputStream input = new TailStrippingInputStream(
- engine.wrap(new ByteArrayInputStream(body)), tagLength, 128) {
+ try (InputStream input = new TailStrippingInputStream(engine.wrap(new ByteArrayInputStream(body)), tagLength,
+ 128) {
@Override
protected void processTail(byte[] tail) {
tag[0] = tail.clone();
@@ -220,7 +213,8 @@ class ZeroEchoSessionWrapIntegrationTest {
assertTrue(Proxy.isProxyClass(context.getClass()));
}
- private record TaggedBody(byte[] body, byte[] tag) {}
+ private record TaggedBody(byte[] body, byte[] tag) {
+ }
private static final class RecordingListener implements AuditListener {
private final List events = new ArrayList<>();
diff --git a/lib/src/test/java/zeroecho/core/alg/aes/AesDecryptionSecurityTest.java b/lib/src/test/java/zeroecho/core/alg/aes/AesDecryptionSecurityTest.java
index 07c5c35..3bfc99c 100644
--- a/lib/src/test/java/zeroecho/core/alg/aes/AesDecryptionSecurityTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/aes/AesDecryptionSecurityTest.java
@@ -41,8 +41,8 @@ class AesDecryptionSecurityTest {
byte[] plaintext = repeated((byte) 0x5a, 96);
Encrypted encrypted = encrypt(AesSpec.gcm128(null), plaintext);
- FailureResult modifiedBody = failedDecryption(
- encrypted.spec, KEY, encrypted.iv, changed(encrypted.ciphertext, 0));
+ FailureResult modifiedBody = failedDecryption(encrypted.spec, KEY, encrypted.iv,
+ changed(encrypted.ciphertext, 0));
FailureResult modifiedTag = failedDecryption(encrypted.spec, KEY, encrypted.iv,
changed(encrypted.ciphertext, encrypted.ciphertext.length - 1));
FailureResult truncatedBody = failedDecryption(encrypted.spec, KEY, encrypted.iv,
@@ -52,19 +52,17 @@ class AesDecryptionSecurityTest {
FailureResult trailing = failedDecryption(encrypted.spec, KEY, encrypted.iv,
Arrays.copyOf(encrypted.ciphertext, encrypted.ciphertext.length + 1));
FailureResult wrongKey = failedDecryption(encrypted.spec, WRONG_KEY, encrypted.iv, encrypted.ciphertext);
- FailureResult wrongIv = failedDecryption(
- encrypted.spec, KEY, changed(encrypted.iv, 0), encrypted.ciphertext);
+ FailureResult wrongIv = failedDecryption(encrypted.spec, KEY, changed(encrypted.iv, 0), encrypted.ciphertext);
FailureResult empty = failedDecryption(encrypted.spec, KEY, encrypted.iv, new byte[0]);
- for (FailureResult result : List.of(
- modifiedBody, modifiedTag, truncatedBody, truncatedTag, trailing, wrongKey, wrongIv, empty)) {
+ for (FailureResult result : List.of(modifiedBody, modifiedTag, truncatedBody, truncatedTag, trailing, wrongKey,
+ wrongIv, empty)) {
assertEquals(0, result.outputBytes());
assertAuthenticationFailure(result.failure());
}
assertThrows(IOException.class, () -> decrypt(encrypted.spec, KEY,
Arrays.copyOf(encrypted.iv, encrypted.iv.length - 1), encrypted.ciphertext));
- assertThrows(IOException.class,
- () -> decrypt(encrypted.spec, KEY, null, encrypted.ciphertext));
+ assertThrows(IOException.class, () -> decrypt(encrypted.spec, KEY, null, encrypted.ciphertext));
System.out.println("...cases=10");
System.out.println("gcmTamperMatrix...ok");
}
@@ -102,18 +100,15 @@ class AesDecryptionSecurityTest {
byte[] plaintext = repeated((byte) 0x44, 32);
Encrypted encrypted = encrypt(spec, plaintext);
- assertFalse(Arrays.equals(plaintext,
- decrypt(spec, KEY, changed(encrypted.iv, 0), encrypted.ciphertext)));
- assertFalse(Arrays.equals(plaintext,
- decrypt(spec, WRONG_KEY, encrypted.iv, encrypted.ciphertext)));
- assertFalse(Arrays.equals(plaintext,
- decrypt(spec, KEY, encrypted.iv, changed(encrypted.ciphertext, 0))));
+ assertFalse(Arrays.equals(plaintext, decrypt(spec, KEY, changed(encrypted.iv, 0), encrypted.ciphertext)));
+ assertFalse(Arrays.equals(plaintext, decrypt(spec, WRONG_KEY, encrypted.iv, encrypted.ciphertext)));
+ assertFalse(Arrays.equals(plaintext, decrypt(spec, KEY, encrypted.iv, changed(encrypted.ciphertext, 0))));
assertThrows(IOException.class, () -> decrypt(spec, KEY, encrypted.iv,
Arrays.copyOf(encrypted.ciphertext, encrypted.ciphertext.length - 1)));
assertThrows(IOException.class, () -> decrypt(spec, KEY, encrypted.iv,
Arrays.copyOf(encrypted.ciphertext, encrypted.ciphertext.length + 1)));
- assertThrows(IOException.class, () -> decrypt(spec, KEY,
- Arrays.copyOf(encrypted.iv, encrypted.iv.length - 1), encrypted.ciphertext));
+ assertThrows(IOException.class,
+ () -> decrypt(spec, KEY, Arrays.copyOf(encrypted.iv, encrypted.iv.length - 1), encrypted.ciphertext));
assertThrows(IOException.class, () -> decrypt(spec, KEY, null, encrypted.ciphertext));
System.out.println("...cases=7");
System.out.println("cbcNoPaddingMatrix...ok");
@@ -132,8 +127,8 @@ class AesDecryptionSecurityTest {
// authentication.
assertThrows(IOException.class, () -> decrypt(spec, KEY, encrypted.iv,
changed(encrypted.ciphertext, encrypted.ciphertext.length - 17)));
- assertThrows(IOException.class, () -> decrypt(spec, KEY,
- Arrays.copyOf(encrypted.iv, encrypted.iv.length - 1), encrypted.ciphertext));
+ assertThrows(IOException.class,
+ () -> decrypt(spec, KEY, Arrays.copyOf(encrypted.iv, encrypted.iv.length - 1), encrypted.ciphertext));
assertThrows(IOException.class, () -> decrypt(spec, KEY, null, encrypted.ciphertext));
System.out.println("...cases=4");
System.out.println("cbcPkcsPaddingMatrix...ok");
@@ -141,7 +136,8 @@ class AesDecryptionSecurityTest {
private static Encrypted encrypt(AesSpec spec, byte[] plaintext) throws Exception {
CtxInterface context = newContext("aes-security-enc-");
- EncryptionContext encryption = new zeroecho.sdk.ZeroEchoSession().createContext("AES", KeyUsage.ENCRYPT, KEY, spec);
+ EncryptionContext encryption = new zeroecho.sdk.ZeroEchoSession().createContext("AES", KeyUsage.ENCRYPT, KEY,
+ spec);
((ContextAware) encryption).setContext(context);
byte[] ciphertext;
try (InputStream stream = encryption.attach(new ByteArrayInputStream(plaintext))) {
@@ -157,7 +153,8 @@ class AesDecryptionSecurityTest {
if (iv != null) {
context.put(ConfluxKeys.iv("AES"), iv);
}
- EncryptionContext decryption = new zeroecho.sdk.ZeroEchoSession().createContext("AES", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext decryption = new zeroecho.sdk.ZeroEchoSession().createContext("AES", KeyUsage.DECRYPT, key,
+ spec);
((ContextAware) decryption).setContext(context);
try (InputStream stream = decryption.attach(new ByteArrayInputStream(ciphertext))) {
return stream.readAllBytes();
@@ -170,7 +167,8 @@ class AesDecryptionSecurityTest {
throws Exception {
CtxInterface context = newContext("aes-security-fail-");
context.put(ConfluxKeys.iv("AES"), iv);
- EncryptionContext decryption = new zeroecho.sdk.ZeroEchoSession().createContext("AES", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext decryption = new zeroecho.sdk.ZeroEchoSession().createContext("AES", KeyUsage.DECRYPT, key,
+ spec);
((ContextAware) decryption).setContext(context);
ByteArrayOutputStream output = new ByteArrayOutputStream();
try (InputStream stream = decryption.attach(new ByteArrayInputStream(ciphertext))) {
@@ -226,7 +224,9 @@ class AesDecryptionSecurityTest {
return result;
}
- private record Encrypted(AesSpec spec, byte[] iv, byte[] ciphertext) {}
+ private record Encrypted(AesSpec spec, byte[] iv, byte[] ciphertext) {
+ }
- private record FailureResult(int outputBytes, IOException failure) {}
+ private record FailureResult(int outputBytes, IOException failure) {
+ }
}
diff --git a/lib/src/test/java/zeroecho/core/alg/aes/AesRandomSupportTest.java b/lib/src/test/java/zeroecho/core/alg/aes/AesRandomSupportTest.java
index 7af8495..3b0eff3 100644
--- a/lib/src/test/java/zeroecho/core/alg/aes/AesRandomSupportTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/aes/AesRandomSupportTest.java
@@ -198,7 +198,8 @@ class AesRandomSupportTest {
@Test
void publicBuilderExposesOnlyDecryptionIvConfiguration() throws Exception {
System.out.print("AesRandomSupport/publicBuilderExposesOnlyDecryptionIvConfiguration...");
- List methodNames = Arrays.stream(AesDataContentBuilder.class.getMethods()).map(Method::getName).toList();
+ List methodNames = Arrays.stream(AesDataContentBuilder.class.getMethods()).map(Method::getName)
+ .toList();
assertFalse(methodNames.contains("withIv"));
assertTrue(methodNames.contains("withDecryptionIv"));
diff --git a/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaLargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaLargeDataTest.java
index 1181c8c..78edd11 100644
--- a/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaLargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaLargeDataTest.java
@@ -116,17 +116,20 @@ public class ChaChaLargeDataTest {
byte[] msg = randomBytes(SIZE);
CryptoAlgorithm chacha = CryptoAlgorithms.require("CHACHA20");
- SecretKey key = chacha.symmetricKeyGenerator(ChaChaKeyGenSpec.class).generateSecret(ChaChaKeyGenSpec.chacha256());
+ SecretKey key = chacha.symmetricKeyGenerator(ChaChaKeyGenSpec.class)
+ .generateSecret(ChaChaKeyGenSpec.chacha256());
CtxInterface session = Ctx.INSTANCE.getContext("chacha-ctx-" + System.nanoTime());
ChaChaSpec spec = ChaChaSpec.builder().initialCounter(1).header(null).build();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.ENCRYPT, key, spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.ENCRYPT, key,
+ spec);
((ContextAware) enc).setContext(session);
byte[] ct = readAll(enc.attach(new ByteArrayInputStream(msg)));
enc.close();
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key,
+ spec);
((ContextAware) dec).setContext(session);
byte[] pt = readAll(dec.attach(new ByteArrayInputStream(ct)));
dec.close();
@@ -143,17 +146,20 @@ public class ChaChaLargeDataTest {
byte[] msg = randomBytes(SIZE);
CryptoAlgorithm chacha = CryptoAlgorithms.require("CHACHA20");
- SecretKey key = chacha.symmetricKeyGenerator(ChaChaKeyGenSpec.class).generateSecret(ChaChaKeyGenSpec.chacha256());
+ SecretKey key = chacha.symmetricKeyGenerator(ChaChaKeyGenSpec.class)
+ .generateSecret(ChaChaKeyGenSpec.chacha256());
CtxInterface session = Ctx.INSTANCE.getContext("chacha-hdr-" + System.nanoTime());
ChaChaSpec spec = ChaChaSpec.builder().initialCounter(1).header(new ChaChaHeaderCodec()).build();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.ENCRYPT, key, spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.ENCRYPT, key,
+ spec);
((ContextAware) enc).setContext(session);
byte[] ct = readAll(enc.attach(new ByteArrayInputStream(msg)));
enc.close();
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key,
+ spec);
((ContextAware) dec).setContext(session);
byte[] pt = readAll(dec.attach(new ByteArrayInputStream(ct)));
dec.close();
@@ -174,14 +180,16 @@ public class ChaChaLargeDataTest {
byte[] msg = randomBytes(SIZE);
CryptoAlgorithm chacha = CryptoAlgorithms.require("CHACHA20");
- SecretKey key = chacha.symmetricKeyGenerator(ChaChaKeyGenSpec.class).generateSecret(ChaChaKeyGenSpec.chacha256());
+ SecretKey key = chacha.symmetricKeyGenerator(ChaChaKeyGenSpec.class)
+ .generateSecret(ChaChaKeyGenSpec.chacha256());
// Encrypt with explicit counter=7 (in ctx), headerless (ctx-only).
CtxInterface encCtx = Ctx.INSTANCE.getContext("chacha-ctr-enc-" + System.nanoTime());
encCtx.put(ConfluxKeys.tagBits("CHACHA20"), 7);
ChaChaSpec spec = ChaChaSpec.builder().initialCounter(1).header(null).build();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.ENCRYPT, key, spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.ENCRYPT, key,
+ spec);
((ContextAware) enc).setContext(encCtx);
byte[] ct = readAll(enc.attach(new ByteArrayInputStream(msg)));
enc.close();
@@ -194,7 +202,8 @@ public class ChaChaLargeDataTest {
decCtxOk.put(ConfluxKeys.iv("CHACHA20"), nonce);
decCtxOk.put(ConfluxKeys.tagBits("CHACHA20"), 7);
- EncryptionContext decOk = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext decOk = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key,
+ spec);
((ContextAware) decOk).setContext(decCtxOk);
byte[] ptOk = readAll(decOk.attach(new ByteArrayInputStream(ct)));
decOk.close();
@@ -205,7 +214,8 @@ public class ChaChaLargeDataTest {
decCtxBad.put(ConfluxKeys.iv("CHACHA20"), nonce);
decCtxBad.put(ConfluxKeys.tagBits("CHACHA20"), 8);
- EncryptionContext decBad = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext decBad = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20", KeyUsage.DECRYPT, key,
+ spec);
((ContextAware) decBad).setContext(decCtxBad);
byte[] ptBad = readAll(decBad.attach(new ByteArrayInputStream(ct)));
decBad.close();
@@ -235,12 +245,14 @@ public class ChaChaLargeDataTest {
ChaCha20Poly1305Spec spec = ChaCha20Poly1305Spec.builder().header(null).build();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.ENCRYPT, key, spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.ENCRYPT,
+ key, spec);
((ContextAware) enc).setContext(session);
byte[] ct = readAll(enc.attach(new ByteArrayInputStream(msg)));
enc.close();
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.DECRYPT,
+ key, spec);
((ContextAware) dec).setContext(session);
byte[] pt = readAll(dec.attach(new ByteArrayInputStream(ct)));
dec.close();
@@ -266,12 +278,14 @@ public class ChaChaLargeDataTest {
ChaCha20Poly1305Spec spec = ChaCha20Poly1305Spec.builder().header(new ChaCha20Poly1305HeaderCodec()).build();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.ENCRYPT, key, spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.ENCRYPT,
+ key, spec);
((ContextAware) enc).setContext(session);
byte[] ct = readAll(enc.attach(new ByteArrayInputStream(msg)));
enc.close();
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.DECRYPT,
+ key, spec);
((ContextAware) dec).setContext(session);
byte[] pt = readAll(dec.attach(new ByteArrayInputStream(ct)));
dec.close();
@@ -302,7 +316,8 @@ public class ChaChaLargeDataTest {
ChaCha20Poly1305Spec spec = ChaCha20Poly1305Spec.builder().header(null).build();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.ENCRYPT, key, spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.ENCRYPT,
+ key, spec);
((ContextAware) enc).setContext(encCtx);
byte[] ct = readAll(enc.attach(new ByteArrayInputStream(msg)));
enc.close();
@@ -314,7 +329,8 @@ public class ChaChaLargeDataTest {
byte[] nonce = encCtx.get(ConfluxKeys.iv("CHACHA20-POLY1305"));
decCtx.put(ConfluxKeys.iv("CHACHA20-POLY1305"), nonce);
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.DECRYPT, key, spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("CHACHA20-POLY1305", KeyUsage.DECRYPT,
+ key, spec);
((ContextAware) dec).setContext(decCtx);
assertThrows(IOException.class, () -> {
diff --git a/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaNonceLifecycleTest.java b/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaNonceLifecycleTest.java
index afb7e85..0902e59 100644
--- a/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaNonceLifecycleTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/chacha/ChaChaNonceLifecycleTest.java
@@ -177,8 +177,8 @@ class ChaChaNonceLifecycleTest {
private static ChaCha20Poly1305CipherContext encryptingContext(ChaCha20Poly1305Spec spec, SecureRandom random,
CtxInterface operation) {
- ChaCha20Poly1305CipherContext context = new ChaCha20Poly1305CipherContext(
- new ChaCha20Poly1305Algorithm(), KEY, true, spec, random);
+ ChaCha20Poly1305CipherContext context = new ChaCha20Poly1305CipherContext(new ChaCha20Poly1305Algorithm(), KEY,
+ true, spec, random);
((ContextAware) context).setContext(operation);
return context;
}
@@ -190,8 +190,8 @@ class ChaChaNonceLifecycleTest {
}
private static byte[] decryptHeader(byte[] ciphertext) throws Exception {
- ChaCha20Poly1305CipherContext context = new ChaCha20Poly1305CipherContext(
- new ChaCha20Poly1305Algorithm(), KEY, false, HEADER_SPEC, null);
+ ChaCha20Poly1305CipherContext context = new ChaCha20Poly1305CipherContext(new ChaCha20Poly1305Algorithm(), KEY,
+ false, HEADER_SPEC, null);
((ContextAware) context).setContext(Ctx.INSTANCE.getContext("chacha-header-decrypt-" + System.nanoTime()));
try (InputStream stream = context.attach(new ByteArrayInputStream(ciphertext))) {
return stream.readAllBytes();
diff --git a/lib/src/test/java/zeroecho/core/alg/common/agreement/AgreementAlgorithmsRoundTripTest.java b/lib/src/test/java/zeroecho/core/alg/common/agreement/AgreementAlgorithmsRoundTripTest.java
index d8a516c..03b6b23 100644
--- a/lib/src/test/java/zeroecho/core/alg/common/agreement/AgreementAlgorithmsRoundTripTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/common/agreement/AgreementAlgorithmsRoundTripTest.java
@@ -206,8 +206,10 @@ public class AgreementAlgorithmsRoundTripTest {
MessageAgreementContext bCtx = null;
try {
- aCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, aliceKey, spec);
- bCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, bobKey, spec);
+ aCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, aliceKey,
+ spec);
+ bCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, bobKey,
+ spec);
byte[] aMsg = aCtx.getPeerMessage();
byte[] bMsg = bCtx.getPeerMessage();
@@ -274,12 +276,12 @@ public class AgreementAlgorithmsRoundTripTest {
try {
// Alice (initiator): has Bob's public key
- aliceCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, bob.getPublic(),
- VoidSpec.INSTANCE);
+ aliceCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT,
+ bob.getPublic(), VoidSpec.INSTANCE);
// Bob (responder): has his private key
- bobCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, bob.getPrivate(),
- VoidSpec.INSTANCE);
+ bobCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT,
+ bob.getPrivate(), VoidSpec.INSTANCE);
// Initiator produces encapsulation message (ciphertext) to send
byte[] enc = aliceCtx.getPeerMessage();
@@ -362,8 +364,10 @@ public class AgreementAlgorithmsRoundTripTest {
AgreementContext bCtx = null;
try {
- aCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, alice.getPrivate(), spec);
- bCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT, bob.getPrivate(), spec);
+ aCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT,
+ alice.getPrivate(), spec);
+ bCtx = new zeroecho.sdk.ZeroEchoSession().createContext(alg.id(), KeyUsage.AGREEMENT,
+ bob.getPrivate(), spec);
aCtx.setPeerPublic(bob.getPublic());
bCtx.setPeerPublic(alice.getPublic());
diff --git a/lib/src/test/java/zeroecho/core/alg/ecdsa/EcdsaLargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/ecdsa/EcdsaLargeDataTest.java
index b6cf953..076cb0d 100644
--- a/lib/src/test/java/zeroecho/core/alg/ecdsa/EcdsaLargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/ecdsa/EcdsaLargeDataTest.java
@@ -135,7 +135,8 @@ public class EcdsaLargeDataTest {
KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ECDSA", spec);
// SIGN (streaming): emits [body][signature]; capture trailer
- SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("ECDSA", KeyUsage.SIGN, kp.getPrivate(), spec);
+ SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("ECDSA", KeyUsage.SIGN,
+ kp.getPrivate(), spec);
final byte[][] sigHolder = new byte[1][];
final int sigLen = signer.tagLength(); // should equal spec.signFixedLength()
@@ -160,7 +161,8 @@ public class EcdsaLargeDataTest {
System.out.println("...signature size: " + ourSig.length + " (expected " + spec.signFixedLength() + ")");
// VERIFY with our streaming verifier
- SignatureContext verifier = new zeroecho.sdk.ZeroEchoSession().createContext("ECDSA", KeyUsage.VERIFY, kp.getPublic(), spec);
+ SignatureContext verifier = new zeroecho.sdk.ZeroEchoSession().createContext("ECDSA", KeyUsage.VERIFY,
+ kp.getPublic(), spec);
verifier.setExpectedTag(ourSig);
byte[] sink2;
try (InputStream verIn = verifier.wrap(new ByteArrayInputStream(msg))) {
@@ -181,7 +183,8 @@ public class EcdsaLargeDataTest {
// Extra symmetry check (optional): our verifier must accept a JCA signature
// (different bytes)
byte[] jcaSig = jcaEcdsaSign(spec.jcaFactory(), kp.getPrivate(), msg);
- SignatureContext verifier2 = new zeroecho.sdk.ZeroEchoSession().createContext("ECDSA", KeyUsage.VERIFY, kp.getPublic(), spec);
+ SignatureContext verifier2 = new zeroecho.sdk.ZeroEchoSession().createContext("ECDSA", KeyUsage.VERIFY,
+ kp.getPublic(), spec);
verifier2.setExpectedTag(jcaSig);
try (InputStream verIn2 = verifier2.wrap(new ByteArrayInputStream(msg))) {
byte[] passthrough = readAll(verIn2);
diff --git a/lib/src/test/java/zeroecho/core/alg/ed25519/Ed25519LargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/ed25519/Ed25519LargeDataTest.java
index 729fc94..8e6b77b 100644
--- a/lib/src/test/java/zeroecho/core/alg/ed25519/Ed25519LargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/ed25519/Ed25519LargeDataTest.java
@@ -132,11 +132,13 @@ public class Ed25519LargeDataTest {
return;
}
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed25519", Ed25519KeyGenSpec.defaultSpec());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed25519",
+ Ed25519KeyGenSpec.defaultSpec());
// SIGN: context emits [body][signature] — capture trailer via
// TailStrippingInputStream
- SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("Ed25519", KeyUsage.SIGN, kp.getPrivate(), null);
+ SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("Ed25519", KeyUsage.SIGN,
+ kp.getPrivate(), null);
final byte[][] sigHolder = new byte[1][];
final int sigLen = signer.tagLength();
@@ -166,7 +168,8 @@ public class Ed25519LargeDataTest {
assertArrayEquals(refSig, ourSig, "signature mismatch vs JCA reference");
// VERIFY: supply expected tag and drain (throws on mismatch)
- SignatureContext verifier = new zeroecho.sdk.ZeroEchoSession().createContext("Ed25519", KeyUsage.VERIFY, kp.getPublic(), null);
+ SignatureContext verifier = new zeroecho.sdk.ZeroEchoSession().createContext("Ed25519", KeyUsage.VERIFY,
+ kp.getPublic(), null);
verifier.setExpectedTag(ourSig);
byte[] sink2;
diff --git a/lib/src/test/java/zeroecho/core/alg/ed448/Ed448LargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/ed448/Ed448LargeDataTest.java
index 28d515f..cc2516c 100644
--- a/lib/src/test/java/zeroecho/core/alg/ed448/Ed448LargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/ed448/Ed448LargeDataTest.java
@@ -132,11 +132,13 @@ public class Ed448LargeDataTest {
return;
}
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed448", Ed448KeyGenSpec.defaultSpec());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed448",
+ Ed448KeyGenSpec.defaultSpec());
// SIGN: context emits [body][signature] — capture trailer via
// TailStrippingInputStream
- SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("Ed448", KeyUsage.SIGN, kp.getPrivate(), null);
+ SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("Ed448", KeyUsage.SIGN,
+ kp.getPrivate(), null);
final byte[][] sigHolder = new byte[1][];
final int sigLen = signer.tagLength();
@@ -166,7 +168,8 @@ public class Ed448LargeDataTest {
assertArrayEquals(refSig, ourSig, "signature mismatch vs JCA reference");
// VERIFY: supply expected tag and drain (throws on mismatch)
- SignatureContext verifier = new zeroecho.sdk.ZeroEchoSession().createContext("Ed448", KeyUsage.VERIFY, kp.getPublic(), null);
+ SignatureContext verifier = new zeroecho.sdk.ZeroEchoSession().createContext("Ed448", KeyUsage.VERIFY,
+ kp.getPublic(), null);
verifier.setExpectedTag(ourSig);
byte[] sink2;
diff --git a/lib/src/test/java/zeroecho/core/alg/elgamal/ElgamalLargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/elgamal/ElgamalLargeDataTest.java
index a56a9d4..740a1df 100644
--- a/lib/src/test/java/zeroecho/core/alg/elgamal/ElgamalLargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/elgamal/ElgamalLargeDataTest.java
@@ -92,16 +92,19 @@ public class ElgamalLargeDataTest {
byte[] msg = randomBytes(SIZE);
System.out.printf("...input: %d bytes%n", msg.length);
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
ElgamalEncSpec spec = ElgamalEncSpec.pkcs1();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, kp.getPublic(), spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ kp.getPublic(), spec);
InputStream ctIn = enc.attach(new ByteArrayInputStream(msg));
byte[] ct = ctIn.readAllBytes();
enc.close();
System.out.printf("...encrypted: %d bytes%n", ct.length);
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.DECRYPT, kp.getPrivate(), spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.DECRYPT,
+ kp.getPrivate(), spec);
InputStream ptIn = dec.attach(new ByteArrayInputStream(ct));
byte[] pt = ptIn.readAllBytes();
dec.close();
@@ -120,16 +123,19 @@ public class ElgamalLargeDataTest {
byte[] msg = randomBytes(SIZE);
System.out.printf("...input: %d bytes%n", msg.length);
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
ElgamalEncSpec spec = ElgamalEncSpec.noPadding();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, kp.getPublic(), spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ kp.getPublic(), spec);
InputStream ctIn = enc.attach(new ByteArrayInputStream(msg));
byte[] ct = ctIn.readAllBytes();
enc.close();
System.out.printf("...encrypted: %d bytes%n", ct.length);
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.DECRYPT, kp.getPrivate(), spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.DECRYPT,
+ kp.getPrivate(), spec);
InputStream ptIn = dec.attach(new ByteArrayInputStream(ct));
byte[] pt = ptIn.readAllBytes();
dec.close();
@@ -148,10 +154,12 @@ public class ElgamalLargeDataTest {
byte[] msg = randomBytes(SIZE);
System.out.printf("...input: %d bytes%n", msg.length);
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
ElgamalEncSpec spec = ElgamalEncSpec.noPadding();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, kp.getPublic(), spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ kp.getPublic(), spec);
InputStream ctIn = enc.attach(new ByteArrayInputStream(msg));
assertThrowsExactly(IllegalStateException.class, () -> ctIn.readAllBytes(),
"No-padding cipher streams cannot processes incomplete blocks: 3 instead of 255");
diff --git a/lib/src/test/java/zeroecho/core/alg/hmac/HmacLargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/hmac/HmacLargeDataTest.java
index d9619b4..3dd0ed1 100644
--- a/lib/src/test/java/zeroecho/core/alg/hmac/HmacLargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/hmac/HmacLargeDataTest.java
@@ -127,7 +127,8 @@ public class HmacLargeDataTest {
CryptoAlgorithm algo = CryptoAlgorithms.require(ALG_ID);
// Generate a key (macName must match)
- SecretKey key = algo.symmetricKeyGenerator(HmacKeyGenSpec.class).generateSecret(new HmacKeyGenSpec(JCA_MAC, 256));
+ SecretKey key = algo.symmetricKeyGenerator(HmacKeyGenSpec.class)
+ .generateSecret(new HmacKeyGenSpec(JCA_MAC, 256));
// --- MAC (produce): engine emits [body][tag]; capture trailer ---
HmacSpec spec = HmacSpec.sha256();
diff --git a/lib/src/test/java/zeroecho/core/alg/mldsa/MldsaLargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/mldsa/MldsaLargeDataTest.java
index b50b048..6c7c3b1 100644
--- a/lib/src/test/java/zeroecho/core/alg/mldsa/MldsaLargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/mldsa/MldsaLargeDataTest.java
@@ -119,11 +119,13 @@ public final class MldsaLargeDataTest {
KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-DSA", spec);
- SignatureContext mldsaVerifier = new zeroecho.sdk.ZeroEchoSession().createContext("ML-DSA", KeyUsage.VERIFY, kp.getPublic());
+ SignatureContext mldsaVerifier = new zeroecho.sdk.ZeroEchoSession().createContext("ML-DSA", KeyUsage.VERIFY,
+ kp.getPublic());
int expectedSigLen = mldsaVerifier.tagLength();
System.out.println(INDENT + " expectedSigLen=" + expectedSigLen);
- SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("ML-DSA", KeyUsage.SIGN, kp.getPrivate());
+ SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("ML-DSA", KeyUsage.SIGN,
+ kp.getPrivate());
final byte[][] sigHolder = new byte[1][];
byte[] passthrough;
@@ -178,7 +180,8 @@ public final class MldsaLargeDataTest {
byte[] badSig = Arrays.copyOf(signature, signature.length);
badSig[0] = (byte) (badSig[0] ^ 0x01);
- SignatureContext badVerifier = new zeroecho.sdk.ZeroEchoSession().createContext("ML-DSA", KeyUsage.VERIFY, kp.getPublic());
+ SignatureContext badVerifier = new zeroecho.sdk.ZeroEchoSession().createContext("ML-DSA", KeyUsage.VERIFY,
+ kp.getPublic());
try {
badVerifier.setExpectedTag(badSig);
diff --git a/lib/src/test/java/zeroecho/core/alg/rsa/BlockGeometryTest.java b/lib/src/test/java/zeroecho/core/alg/rsa/BlockGeometryTest.java
index f14344a..7fee995 100644
--- a/lib/src/test/java/zeroecho/core/alg/rsa/BlockGeometryTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/rsa/BlockGeometryTest.java
@@ -47,8 +47,7 @@ class BlockGeometryTest {
assertEquals(2, first.inChunkSize());
assertEquals(3, first.outChunkSize());
assertEquals(0, first.finalizationOutputChunks());
- assertEquals("BlockGeometry[inChunkSize=2, outChunkSize=3, finalizationOutputChunks=0]",
- first.toString());
+ assertEquals("BlockGeometry[inChunkSize=2, outChunkSize=3, finalizationOutputChunks=0]", first.toString());
System.out.println("...legacyFields=true");
System.out.println("valueSemantics...ok");
}
@@ -56,7 +55,8 @@ class BlockGeometryTest {
@Test
void actualRsaPath() throws Exception {
System.out.println("actualRsaPath");
- KeyPair keyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair keyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
RsaEncSpec spec = RsaEncSpec.oaep(RsaEncSpec.Hash.SHA256);
BlockGeometry encryptGeometry = BlockGeometry.forRsa(spec, keyPair.getPublic(), true);
BlockGeometry decryptGeometry = BlockGeometry.forRsa(spec, keyPair.getPrivate(), false);
@@ -66,7 +66,8 @@ class BlockGeometryTest {
assertEquals(256, decryptGeometry.inChunkSize());
assertEquals(256, decryptGeometry.outChunkSize());
- EncryptionContext context = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, keyPair.getPublic(), spec);
+ EncryptionContext context = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ keyPair.getPublic(), spec);
try (InputStream stream = context.attach(new ByteArrayInputStream(new byte[] { 1, 2, 3 }))) {
assertEquals(256, stream.readAllBytes().length);
} finally {
diff --git a/lib/src/test/java/zeroecho/core/alg/rsa/RsaLargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/rsa/RsaLargeDataTest.java
index db7cbe0..d44dfce 100644
--- a/lib/src/test/java/zeroecho/core/alg/rsa/RsaLargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/rsa/RsaLargeDataTest.java
@@ -88,16 +88,19 @@ public class RsaLargeDataTest {
byte[] msg = randomBytes(SIZE);
System.out.printf("...input: %d bytes%n", msg.length);
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
RsaEncSpec spec = RsaEncSpec.oaep(RsaEncSpec.Hash.SHA256);
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, kp.getPublic(), spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ kp.getPublic(), spec);
InputStream ctIn = enc.attach(new ByteArrayInputStream(msg));
byte[] ct = ctIn.readAllBytes();
enc.close();
System.out.printf("...encrypted: %d bytes%n", ct.length);
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.DECRYPT, kp.getPrivate(), spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.DECRYPT,
+ kp.getPrivate(), spec);
InputStream ptIn = dec.attach(new ByteArrayInputStream(ct));
byte[] pt = ptIn.readAllBytes();
dec.close();
@@ -116,16 +119,19 @@ public class RsaLargeDataTest {
byte[] msg = randomBytes(SIZE);
System.out.printf("...input: %d bytes%n", msg.length);
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
RsaEncSpec spec = RsaEncSpec.pkcs1v15();
- EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, kp.getPublic(), spec);
+ EncryptionContext enc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ kp.getPublic(), spec);
InputStream ctIn = enc.attach(new ByteArrayInputStream(msg));
byte[] ct = ctIn.readAllBytes();
enc.close();
System.out.printf("...encrypted: %d bytes%n", ct.length);
- EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.DECRYPT, kp.getPrivate(), spec);
+ EncryptionContext dec = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.DECRYPT,
+ kp.getPrivate(), spec);
InputStream ptIn = dec.attach(new ByteArrayInputStream(ct));
byte[] pt = ptIn.readAllBytes();
dec.close();
diff --git a/lib/src/test/java/zeroecho/core/alg/slhdsa/SlhDsaLargeDataTest.java b/lib/src/test/java/zeroecho/core/alg/slhdsa/SlhDsaLargeDataTest.java
index 64763f0..016b6a1 100644
--- a/lib/src/test/java/zeroecho/core/alg/slhdsa/SlhDsaLargeDataTest.java
+++ b/lib/src/test/java/zeroecho/core/alg/slhdsa/SlhDsaLargeDataTest.java
@@ -126,14 +126,16 @@ public final class SlhDsaLargeDataTest {
// Create verifier FIRST to obtain tag length via
// SlhDsaSignatureContext.sigLenFromPublicKey.
- SignatureContext verifierCtx = new zeroecho.sdk.ZeroEchoSession().createContext("SLH-DSA", KeyUsage.VERIFY, kp.getPublic());
+ SignatureContext verifierCtx = new zeroecho.sdk.ZeroEchoSession().createContext("SLH-DSA", KeyUsage.VERIFY,
+ kp.getPublic());
int expectedSigLen = verifierCtx.tagLength();
System.out.println(INDENT + " expectedSigLen=" + expectedSigLen);
// Now sign and strip trailer using the expected length from verifier (not from
// signer).
- SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("SLH-DSA", KeyUsage.SIGN, kp.getPrivate());
+ SignatureContext signer = new zeroecho.sdk.ZeroEchoSession().createContext("SLH-DSA", KeyUsage.SIGN,
+ kp.getPrivate());
final byte[][] sigHolder = new byte[1][];
byte[] passthrough;
@@ -188,7 +190,8 @@ public final class SlhDsaLargeDataTest {
byte[] badSig = Arrays.copyOf(signature, signature.length);
badSig[0] = (byte) (badSig[0] ^ 0x01);
- SignatureContext badVerifier = new zeroecho.sdk.ZeroEchoSession().createContext("SLH-DSA", KeyUsage.VERIFY, kp.getPublic());
+ SignatureContext badVerifier = new zeroecho.sdk.ZeroEchoSession().createContext("SLH-DSA", KeyUsage.VERIFY,
+ kp.getPublic());
try {
badVerifier.setExpectedTag(badSig);
diff --git a/lib/src/test/java/zeroecho/core/audit/AuditedContextsRegressionTest.java b/lib/src/test/java/zeroecho/core/audit/AuditedContextsRegressionTest.java
index 91fd682..2291d49 100644
--- a/lib/src/test/java/zeroecho/core/audit/AuditedContextsRegressionTest.java
+++ b/lib/src/test/java/zeroecho/core/audit/AuditedContextsRegressionTest.java
@@ -48,9 +48,8 @@ class AuditedContextsRegressionTest {
DigestContext target = mock(DigestContext.class);
when(target.tagLength()).thenReturn(2);
when(target.wrap(any(InputStream.class))).thenAnswer(invocation -> invocation.getArgument(0));
- DigestContext unrelated = (DigestContext) Proxy.newProxyInstance(
- DigestContext.class.getClassLoader(), new Class>[] { DigestContext.class },
- (proxy, method, arguments) -> {
+ DigestContext unrelated = (DigestContext) Proxy.newProxyInstance(DigestContext.class.getClassLoader(),
+ new Class>[] { DigestContext.class }, (proxy, method, arguments) -> {
try {
return method.invoke(target, arguments);
} catch (InvocationTargetException exception) {
@@ -62,7 +61,8 @@ class AuditedContextsRegressionTest {
assertNotSame(unrelated, wrapped);
assertTrue(Proxy.isProxyClass(wrapped.getClass()));
- assertArrayEquals(new byte[] { 1, 2 }, wrapped.wrap(new ByteArrayInputStream(new byte[] { 1, 2 })).readAllBytes());
+ assertArrayEquals(new byte[] { 1, 2 },
+ wrapped.wrap(new ByteArrayInputStream(new byte[] { 1, 2 })).readAllBytes());
assertSame(wrapped, AuditedContexts.wrap(wrapped, AuditListener.noop(), KeyUsage.DIGEST));
System.out.println("...nestedProxy=true");
System.out.println("unrelatedProxyGetsWrapped...ok");
@@ -179,8 +179,8 @@ class AuditedContextsRegressionTest {
AgreementContext agreement = mock(AgreementContext.class);
doThrow(peerFailure).when(agreement).setPeerPublic(any(PublicKey.class));
when(agreement.deriveSecret()).thenThrow(deriveFailure);
- AgreementContext wrappedAgreement = (AgreementContext) AuditedContexts.wrap(
- agreement, listener, KeyUsage.AGREEMENT);
+ AgreementContext wrappedAgreement = (AgreementContext) AuditedContexts.wrap(agreement, listener,
+ KeyUsage.AGREEMENT);
assertSame(peerFailure, assertThrows(IllegalArgumentException.class,
() -> wrappedAgreement.setPeerPublic(mock(PublicKey.class))));
@@ -193,14 +193,13 @@ class AuditedContextsRegressionTest {
doThrow(setMessageFailure).when(messageAgreement).setPeerMessage(any(byte[].class));
when(messageAgreement.getPeerMessage()).thenThrow(getMessageFailure);
when(messageAgreement.deriveSecret()).thenThrow(messageDeriveFailure);
- MessageAgreementContext wrappedMessage = (MessageAgreementContext) AuditedContexts.wrap(
- messageAgreement, listener, KeyUsage.AGREEMENT);
+ MessageAgreementContext wrappedMessage = (MessageAgreementContext) AuditedContexts.wrap(messageAgreement,
+ listener, KeyUsage.AGREEMENT);
- assertSame(setMessageFailure, assertThrows(IllegalArgumentException.class,
- () -> wrappedMessage.setPeerMessage(new byte[] { 1 })));
+ assertSame(setMessageFailure,
+ assertThrows(IllegalArgumentException.class, () -> wrappedMessage.setPeerMessage(new byte[] { 1 })));
assertSame(getMessageFailure, assertThrows(IllegalStateException.class, wrappedMessage::getPeerMessage));
- assertSame(messageDeriveFailure,
- assertThrows(IllegalStateException.class, wrappedMessage::deriveSecret));
+ assertSame(messageDeriveFailure, assertThrows(IllegalStateException.class, wrappedMessage::deriveSecret));
assertEquals(List.of(peerFailure, deriveFailure, setMessageFailure, getMessageFailure, messageDeriveFailure),
listener.failures);
diff --git a/lib/src/test/java/zeroecho/core/audit/JulAuditListenerStdSecurityTest.java b/lib/src/test/java/zeroecho/core/audit/JulAuditListenerStdSecurityTest.java
index 0b0f7ab..f459781 100644
--- a/lib/src/test/java/zeroecho/core/audit/JulAuditListenerStdSecurityTest.java
+++ b/lib/src/test/java/zeroecho/core/audit/JulAuditListenerStdSecurityTest.java
@@ -65,8 +65,8 @@ class JulAuditListenerStdSecurityTest {
}
private static JulAuditListenerStd listener(RecordingHandler handler) {
- Logger logger = Logger.getLogger(
- JulAuditListenerStdSecurityTest.class.getName() + "." + LOGGER_IDS.incrementAndGet());
+ Logger logger = Logger
+ .getLogger(JulAuditListenerStdSecurityTest.class.getName() + "." + LOGGER_IDS.incrementAndGet());
logger.setUseParentHandlers(false);
logger.setLevel(Level.ALL);
handler.setLevel(Level.ALL);
diff --git a/lib/src/test/java/zeroecho/core/io/CipherTransformInputStreamBuilderTest.java b/lib/src/test/java/zeroecho/core/io/CipherTransformInputStreamBuilderTest.java
index 0e5fe66..804aa59 100644
--- a/lib/src/test/java/zeroecho/core/io/CipherTransformInputStreamBuilderTest.java
+++ b/lib/src/test/java/zeroecho/core/io/CipherTransformInputStreamBuilderTest.java
@@ -25,10 +25,8 @@ class CipherTransformInputStreamBuilderTest {
assertThrows(IllegalArgumentException.class, () -> new TestStream(2, 1, 0, 0));
assertThrows(IllegalArgumentException.class, () -> new TestStream(2, 1, 1, -1));
assertThrows(IllegalArgumentException.class, () -> new TestStream(Integer.MAX_VALUE, 1, 2, 0));
- assertThrows(IllegalArgumentException.class,
- () -> new TestStream(2, 1, Integer.MAX_VALUE, 1));
- assertThrows(IllegalArgumentException.class,
- () -> new TestStream(2, Integer.MAX_VALUE, 1, 1));
+ assertThrows(IllegalArgumentException.class, () -> new TestStream(2, 1, Integer.MAX_VALUE, 1));
+ assertThrows(IllegalArgumentException.class, () -> new TestStream(2, Integer.MAX_VALUE, 1, 1));
new TestStream(2, 1, 1, 0);
new TestStream(2, 1, 1, 1);
@@ -57,16 +55,14 @@ class CipherTransformInputStreamBuilderTest {
System.out.print("CipherBuilder/algorithm-guard...");
CountingInputStream gcmInput = new CountingInputStream();
Cipher gcm = Cipher.getInstance("AES/GCM/NoPadding");
- assertThrows(IllegalArgumentException.class,
- () -> CipherTransformInputStreamBuilder.builder().withUpstream(gcmInput).withCipher(gcm)
- .withIndependentBlocks().build());
+ assertThrows(IllegalArgumentException.class, () -> CipherTransformInputStreamBuilder.builder()
+ .withUpstream(gcmInput).withCipher(gcm).withIndependentBlocks().build());
assertEquals(0, gcmInput.reads);
CountingInputStream cbcInput = new CountingInputStream();
Cipher cbc = Cipher.getInstance("AES/CBC/PKCS5Padding");
- assertThrows(IllegalArgumentException.class,
- () -> CipherTransformInputStreamBuilder.builder().withUpstream(cbcInput).withCipher(cbc)
- .withLeftZeroPadding(true).withIndependentBlocks().build());
+ assertThrows(IllegalArgumentException.class, () -> CipherTransformInputStreamBuilder.builder()
+ .withUpstream(cbcInput).withCipher(cbc).withLeftZeroPadding(true).withIndependentBlocks().build());
assertEquals(0, cbcInput.reads);
System.out.println("ok");
}
diff --git a/lib/src/test/java/zeroecho/core/marshal/PairSeqTest.java b/lib/src/test/java/zeroecho/core/marshal/PairSeqTest.java
index ccd5ef4..8d19b7c 100644
--- a/lib/src/test/java/zeroecho/core/marshal/PairSeqTest.java
+++ b/lib/src/test/java/zeroecho/core/marshal/PairSeqTest.java
@@ -44,8 +44,8 @@ class PairSeqTest {
assertEquals("pair 0 value must not be null",
assertThrows(IllegalArgumentException.class, () -> PairSeq.of("key", null)).getMessage());
assertEquals("pair 1 key must not be null",
- assertThrows(IllegalArgumentException.class,
- () -> PairSeq.of("first", "value", null, "other")).getMessage());
+ assertThrows(IllegalArgumentException.class, () -> PairSeq.of("first", "value", null, "other"))
+ .getMessage());
String[] source = { "key", "value" };
PairSeq sequence = PairSeq.of(source);
@@ -66,8 +66,7 @@ class PairSeqTest {
IOException partial = new IOException("partial");
FailingAppendable partialOutput = new FailingAppendable(2, partial);
- IOException partialActual = assertThrows(IOException.class,
- () -> PairSeq.of("a", "b").writeTo(partialOutput));
+ IOException partialActual = assertThrows(IOException.class, () -> PairSeq.of("a", "b").writeTo(partialOutput));
assertSame(partial, partialActual);
assertEquals("a=", partialOutput.output.toString());
diff --git a/lib/src/test/java/zeroecho/core/storage/KeyringAlgorithmCoverageTest.java b/lib/src/test/java/zeroecho/core/storage/KeyringAlgorithmCoverageTest.java
index 57e8c3f..4eb9dea 100644
--- a/lib/src/test/java/zeroecho/core/storage/KeyringAlgorithmCoverageTest.java
+++ b/lib/src/test/java/zeroecho/core/storage/KeyringAlgorithmCoverageTest.java
@@ -50,8 +50,7 @@ import zeroecho.sdk.util.BouncyCastleActivator;
* then proves that the reconstructed key remains operational.
*/
class KeyringAlgorithmCoverageTest {
- private static final byte[] MESSAGE = "keyring-algorithm-matrix".getBytes(
- java.nio.charset.StandardCharsets.UTF_8);
+ private static final byte[] MESSAGE = "keyring-algorithm-matrix".getBytes(java.nio.charset.StandardCharsets.UTF_8);
@TempDir
Path temporaryDirectory;
@@ -62,8 +61,7 @@ class KeyringAlgorithmCoverageTest {
@Test
void persistentImporterUniverseHasAcceptedCardinality() {
- List mappings =
- KeyringImportRegistry.mappings();
+ List mappings = KeyringImportRegistry.mappings();
assertEquals(19, count(mappings, KeyringStore.Kind.PUBLIC_KEY));
assertEquals(19, count(mappings, KeyringStore.Kind.PRIVATE_KEY));
assertEquals(6, count(mappings, KeyringStore.Kind.SECRET_KEY));
@@ -72,49 +70,39 @@ class KeyringAlgorithmCoverageTest {
@Test
void publicApiRequiresUnlockMaterialAndExposesNoPlaintextStorePath() {
List publicMethods = Arrays.stream(KeyringStore.class.getDeclaredMethods())
- .filter(method -> Modifier.isPublic(method.getModifiers()))
- .toList();
- publicMethods.stream()
- .filter(method -> "create".equals(method.getName())
- || "open".equals(method.getName()))
+ .filter(method -> Modifier.isPublic(method.getModifiers())).toList();
+ publicMethods.stream().filter(method -> "create".equals(method.getName()) || "open".equals(method.getName()))
.forEach(method -> {
- assertTrue(Arrays.asList(method.getParameterTypes())
- .contains(KeyringPassword.class));
- assertTrue(Arrays.stream(method.getParameterTypes())
- .noneMatch(String.class::equals));
+ assertTrue(Arrays.asList(method.getParameterTypes()).contains(KeyringPassword.class));
+ assertTrue(Arrays.stream(method.getParameterTypes()).noneMatch(String.class::equals));
});
assertTrue(publicMethods.stream().noneMatch(method -> switch (method.getName()) {
case "exportText", "importText", "save", "load" -> true;
default -> false;
}));
- assertTrue(Arrays.stream(KeyringStore.class.getFields())
- .noneMatch(field -> field.getType() == byte[].class));
+ assertTrue(Arrays.stream(KeyringStore.class.getFields()).noneMatch(field -> field.getType() == byte[].class));
}
@TestFactory
Stream asymmetricEncryptedStoreRoundTrips() {
List algorithms = KeyringImportRegistry.mappings().stream()
.filter(mapping -> mapping.kind() == KeyringStore.Kind.PUBLIC_KEY)
- .map(KeyringImportRegistry.PersistentMapping::algorithmId)
- .toList();
- return algorithms.stream().map(algorithmId -> DynamicTest.dynamicTest(
- algorithmId + " PUBLIC/X.509 + PRIVATE/PKCS#8",
- () -> roundTripAsymmetric(algorithmId)));
+ .map(KeyringImportRegistry.PersistentMapping::algorithmId).toList();
+ return algorithms.stream().map(algorithmId -> DynamicTest
+ .dynamicTest(algorithmId + " PUBLIC/X.509 + PRIVATE/PKCS#8", () -> roundTripAsymmetric(algorithmId)));
}
@TestFactory
Stream secretEncryptedStoreRoundTrips() {
return KeyringImportRegistry.mappings().stream()
.filter(mapping -> mapping.kind() == KeyringStore.Kind.SECRET_KEY)
- .map(mapping -> DynamicTest.dynamicTest(secretDisplayName(mapping),
- () -> roundTripSecret(mapping)));
+ .map(mapping -> DynamicTest.dynamicTest(secretDisplayName(mapping), () -> roundTripSecret(mapping)));
}
private void roundTripAsymmetric(String algorithmId) throws Exception {
KeyPair original = generatePair(algorithmId);
Path path = temporaryDirectory.resolve("asymmetric-" + safeName(algorithmId) + ".zek");
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.create(path, password)) {
store.putPublic("matrix", algorithmId, original.getPublic());
store.putPrivate("matrix", algorithmId, original.getPrivate());
}
@@ -123,8 +111,7 @@ class KeyringAlgorithmCoverageTest {
PrivateKey reconstructedPrivate = null;
byte[] originalPublic = null;
byte[] reconstructedPublicBytes = null;
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
KeyringStore.PublicWithId publicWithId = store.getPublicWithId("matrix");
KeyringStore.PrivateWithId privateWithId = store.getPrivateWithId("matrix");
assertEquals(algorithmId, publicWithId.algorithm());
@@ -134,8 +121,7 @@ class KeyringAlgorithmCoverageTest {
originalPublic = original.getPublic().getEncoded();
reconstructedPublicBytes = reconstructedPublic.getEncoded();
assertArrayEquals(originalPublic, reconstructedPublicBytes);
- proveAsymmetricOperation(algorithmId, reconstructedPublic,
- reconstructedPrivate);
+ proveAsymmetricOperation(algorithmId, reconstructedPublic, reconstructedPrivate);
} finally {
wipe(originalPublic);
wipe(reconstructedPublicBytes);
@@ -146,23 +132,19 @@ class KeyringAlgorithmCoverageTest {
}
}
- private void roundTripSecret(KeyringImportRegistry.PersistentMapping mapping)
- throws Exception {
+ private void roundTripSecret(KeyringImportRegistry.PersistentMapping mapping) throws Exception {
byte[] material = new byte[32];
Arrays.fill(material, secretFill(mapping));
String jcaName = secretJcaName(mapping);
SecretKey original = new SecretKeySpec(material, jcaName);
- Path path = temporaryDirectory.resolve("secret-" + safeName(secretDisplayName(mapping))
- + ".zek");
+ Path path = temporaryDirectory.resolve("secret-" + safeName(secretDisplayName(mapping)) + ".zek");
SecretKey reconstructed = null;
byte[] reconstructedBytes = null;
try {
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.create(path, password)) {
store.putSecret("matrix", mapping.algorithmId(), original);
}
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
KeyringStore.SecretWithId withId = store.getSecretWithId("matrix");
assertEquals(mapping.algorithmId(), withId.algorithm());
reconstructed = withId.key();
@@ -179,11 +161,10 @@ class KeyringAlgorithmCoverageTest {
}
}
- private static void proveAsymmetricOperation(String algorithmId,
- PublicKey publicKey, PrivateKey privateKey) throws Exception {
+ private static void proveAsymmetricOperation(String algorithmId, PublicKey publicKey, PrivateKey privateKey)
+ throws Exception {
CryptoAlgorithm algorithm = CryptoAlgorithms.require(algorithmId);
- if (algorithm.roles().contains(KeyUsage.SIGN)
- && algorithm.roles().contains(KeyUsage.VERIFY)) {
+ if (algorithm.roles().contains(KeyUsage.SIGN) && algorithm.roles().contains(KeyUsage.VERIFY)) {
proveSignature(algorithmId, publicKey, privateKey);
} else if (algorithm.roles().contains(KeyUsage.ENCAPSULATE)
&& algorithm.roles().contains(KeyUsage.DECAPSULATE)) {
@@ -191,21 +172,18 @@ class KeyringAlgorithmCoverageTest {
} else if (algorithm.roles().contains(KeyUsage.AGREEMENT)) {
proveAgreement(algorithmId, publicKey, privateKey);
} else {
- assertTrue(algorithm.roles().contains(KeyUsage.ENCRYPT)
- && algorithm.roles().contains(KeyUsage.DECRYPT));
+ assertTrue(algorithm.roles().contains(KeyUsage.ENCRYPT) && algorithm.roles().contains(KeyUsage.DECRYPT));
proveEncryption(algorithmId, publicKey, privateKey);
}
}
- private static void proveSignature(String algorithmId, PublicKey publicKey,
- PrivateKey privateKey) throws Exception {
+ private static void proveSignature(String algorithmId, PublicKey publicKey, PrivateKey privateKey)
+ throws Exception {
ZeroEchoSession session = new ZeroEchoSession();
AtomicReference signatureHolder = new AtomicReference<>();
byte[] signature = null;
- try (SignatureContext signer = session.createContext(
- algorithmId, KeyUsage.SIGN, privateKey);
- InputStream signed = new TailStrippingInputStream(
- signer.wrap(new ByteArrayInputStream(MESSAGE)),
+ try (SignatureContext signer = session.createContext(algorithmId, KeyUsage.SIGN, privateKey);
+ InputStream signed = new TailStrippingInputStream(signer.wrap(new ByteArrayInputStream(MESSAGE)),
signer.tagLength(), 512) {
@Override
protected void processTail(byte[] tail) {
@@ -217,8 +195,7 @@ class KeyringAlgorithmCoverageTest {
}
try {
assertTrue(signature != null && signature.length > 0);
- try (SignatureContext verifier = session.createContext(
- algorithmId, KeyUsage.VERIFY, publicKey);
+ try (SignatureContext verifier = session.createContext(algorithmId, KeyUsage.VERIFY, publicKey);
InputStream verified = verificationStream(verifier, signature)) {
assertArrayEquals(MESSAGE, verified.readAllBytes());
}
@@ -227,23 +204,19 @@ class KeyringAlgorithmCoverageTest {
}
}
- private static InputStream verificationStream(SignatureContext verifier,
- byte[] signature) throws IOException {
+ private static InputStream verificationStream(SignatureContext verifier, byte[] signature) throws IOException {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(signature);
return verifier.wrap(new ByteArrayInputStream(MESSAGE));
}
- private static void proveKem(String algorithmId, PublicKey publicKey,
- PrivateKey privateKey) throws Exception {
+ private static void proveKem(String algorithmId, PublicKey publicKey, PrivateKey privateKey) throws Exception {
ZeroEchoSession session = new ZeroEchoSession();
byte[] encapsulated = null;
byte[] senderSecret = null;
byte[] recipientSecret = null;
- try (KemContext sender = session.createContext(
- algorithmId, KeyUsage.ENCAPSULATE, publicKey);
- KemContext recipient = session.createContext(
- algorithmId, KeyUsage.DECAPSULATE, privateKey)) {
+ try (KemContext sender = session.createContext(algorithmId, KeyUsage.ENCAPSULATE, publicKey);
+ KemContext recipient = session.createContext(algorithmId, KeyUsage.DECAPSULATE, privateKey)) {
KemContext.KemResult result = sender.encapsulate();
encapsulated = result.ciphertext();
senderSecret = result.sharedSecret();
@@ -256,16 +229,14 @@ class KeyringAlgorithmCoverageTest {
}
}
- private static void proveAgreement(String algorithmId, PublicKey publicKey,
- PrivateKey privateKey) throws Exception {
+ private static void proveAgreement(String algorithmId, PublicKey publicKey, PrivateKey privateKey)
+ throws Exception {
KeyPair peer = generatePair(algorithmId);
ZeroEchoSession session = new ZeroEchoSession();
byte[] firstSecret = null;
byte[] secondSecret = null;
- try (AgreementContext first = session.createContext(
- algorithmId, KeyUsage.AGREEMENT, privateKey);
- AgreementContext second = session.createContext(
- algorithmId, KeyUsage.AGREEMENT, peer.getPrivate())) {
+ try (AgreementContext first = session.createContext(algorithmId, KeyUsage.AGREEMENT, privateKey);
+ AgreementContext second = session.createContext(algorithmId, KeyUsage.AGREEMENT, peer.getPrivate())) {
first.setPeerPublic(peer.getPublic());
second.setPeerPublic(publicKey);
firstSecret = first.deriveSecret();
@@ -279,32 +250,26 @@ class KeyringAlgorithmCoverageTest {
}
}
- private static void proveEncryption(String algorithmId, Key encryptionKey,
- Key decryptionKey) throws Exception {
+ private static void proveEncryption(String algorithmId, Key encryptionKey, Key decryptionKey) throws Exception {
ZeroEchoSession session = new ZeroEchoSession();
- conflux.CtxInterface operationContext =
- conflux.Ctx.INSTANCE.getContext("keyring-matrix-" + algorithmId);
+ conflux.CtxInterface operationContext = conflux.Ctx.INSTANCE.getContext("keyring-matrix-" + algorithmId);
byte[] ciphertext = null;
byte[] plaintext = null;
try {
- try (EncryptionContext encryption = session.createContext(
- algorithmId, KeyUsage.ENCRYPT, encryptionKey)) {
+ try (EncryptionContext encryption = session.createContext(algorithmId, KeyUsage.ENCRYPT, encryptionKey)) {
if (encryption instanceof zeroecho.core.spi.ContextAware contextAware) {
contextAware.setContext(operationContext);
}
- try (InputStream encrypted = encryption.attach(
- new ByteArrayInputStream(MESSAGE))) {
+ try (InputStream encrypted = encryption.attach(new ByteArrayInputStream(MESSAGE))) {
ciphertext = encrypted.readAllBytes();
}
}
- try (EncryptionContext decryption = session.createContext(
- algorithmId, KeyUsage.DECRYPT, decryptionKey)) {
+ try (EncryptionContext decryption = session.createContext(algorithmId, KeyUsage.DECRYPT, decryptionKey)) {
if (decryption instanceof zeroecho.core.spi.ContextAware contextAware) {
contextAware.setContext(operationContext);
}
- try (InputStream decrypted = decryption.attach(
- new ByteArrayInputStream(ciphertext))) {
- plaintext = decrypted.readAllBytes();
+ try (InputStream decrypted = decryption.attach(new ByteArrayInputStream(ciphertext))) {
+ plaintext = decrypted.readAllBytes();
}
}
assertArrayEquals(MESSAGE, plaintext);
@@ -314,8 +279,7 @@ class KeyringAlgorithmCoverageTest {
}
}
- private static void proveSecretOperation(
- KeyringImportRegistry.PersistentMapping mapping, SecretKey key)
+ private static void proveSecretOperation(KeyringImportRegistry.PersistentMapping mapping, SecretKey key)
throws Exception {
if ("HMAC".equals(mapping.algorithmId())) {
proveMac(key);
@@ -345,30 +309,22 @@ class KeyringAlgorithmCoverageTest {
private static KeyPair generatePair(String algorithmId) throws Exception {
CryptoAlgorithm algorithm = CryptoAlgorithms.require(algorithmId);
KeyOperationInfo generation = algorithm.keyOperations().stream()
- .filter(info -> info.operation()
- == KeyOperation.ASYMMETRIC_KEY_PAIR_GENERATE)
- .filter(info -> info.defaultSpec() != null)
- .findFirst()
- .orElseThrow(() -> new AssertionError(
- "No default key-pair generation mapping for " + algorithmId));
- AsymmetricKeyPairGenerator generator =
- algorithm.asymmetricKeyPairGenerator(generation.specType());
+ .filter(info -> info.operation() == KeyOperation.ASYMMETRIC_KEY_PAIR_GENERATE)
+ .filter(info -> info.defaultSpec() != null).findFirst()
+ .orElseThrow(() -> new AssertionError("No default key-pair generation mapping for " + algorithmId));
+ AsymmetricKeyPairGenerator generator = algorithm.asymmetricKeyPairGenerator(generation.specType());
return generator.generateKeyPair((AlgorithmKeySpec) generation.defaultSpec());
}
- private static long count(List mappings,
- KeyringStore.Kind kind) {
+ private static long count(List mappings, KeyringStore.Kind kind) {
return mappings.stream().filter(mapping -> mapping.kind() == kind).count();
}
- private static String secretDisplayName(
- KeyringImportRegistry.PersistentMapping mapping) {
- return mapping.algorithmId() + "/" + mapping.hmacVariant().name()
- + " SECRET/RAW";
+ private static String secretDisplayName(KeyringImportRegistry.PersistentMapping mapping) {
+ return mapping.algorithmId() + "/" + mapping.hmacVariant().name() + " SECRET/RAW";
}
- private static String secretJcaName(
- KeyringImportRegistry.PersistentMapping mapping) {
+ private static String secretJcaName(KeyringImportRegistry.PersistentMapping mapping) {
return switch (mapping.algorithmId()) {
case "AES" -> "AES";
case "CHACHA20", "CHACHA20-POLY1305" -> "ChaCha20";
@@ -377,8 +333,7 @@ class KeyringAlgorithmCoverageTest {
};
}
- private static byte secretFill(
- KeyringImportRegistry.PersistentMapping mapping) {
+ private static byte secretFill(KeyringImportRegistry.PersistentMapping mapping) {
return (byte) (mapping.hmacVariant().code() + mapping.algorithmId().length() + 1);
}
diff --git a/lib/src/test/java/zeroecho/core/storage/KeyringAtomicPersistenceTest.java b/lib/src/test/java/zeroecho/core/storage/KeyringAtomicPersistenceTest.java
index affbdde..e01fdd6 100644
--- a/lib/src/test/java/zeroecho/core/storage/KeyringAtomicPersistenceTest.java
+++ b/lib/src/test/java/zeroecho/core/storage/KeyringAtomicPersistenceTest.java
@@ -32,8 +32,8 @@ class KeyringAtomicPersistenceTest {
private static final char[] PASSWORD = { 'a', 't', 'o', 'm', 'i', 'c' };
private static final byte[] ENTRY_A = material((byte) 0x31);
private static final byte[] ENTRY_B = material((byte) 0x72);
- private static final Set FILE_PERMISSIONS = Set.of(
- PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE);
+ private static final Set FILE_PERMISSIONS = Set.of(PosixFilePermission.OWNER_READ,
+ PosixFilePermission.OWNER_WRITE);
@TempDir
Path temporaryDirectory;
@@ -41,20 +41,16 @@ class KeyringAtomicPersistenceTest {
@Test
void mainImagePreCommitFailuresPreserveAuthoritativeState() throws Exception {
start("mainImagePreCommitFailuresPreserveAuthoritativeState");
- for (FailureStage stage : List.of(FailureStage.CREATE_TEMP,
- FailureStage.WRITE_TEMP, FailureStage.FORCE_TEMP,
+ for (FailureStage stage : List.of(FailureStage.CREATE_TEMP, FailureStage.WRITE_TEMP, FailureStage.FORCE_TEMP,
FailureStage.ATOMIC_MOVE)) {
Path path = initialized("main-" + stage + ".zek");
byte[] before = Files.readAllBytes(path);
- FailingFileOperations operations =
- new FailingFileOperations(Target.MAIN_IMAGE, stage, false);
+ FailingFileOperations operations = new FailingFileOperations(Target.MAIN_IMAGE, stage, false);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password,
- KeyringProtection.standard(), deterministicRandom(50),
- operations)) {
+ KeyringStore store = KeyringStore.open(path, password, KeyringProtection.standard(),
+ deterministicRandom(50), operations)) {
long highWater = longField(store, "nonceHighWater");
- KeyringException failure = assertThrows(KeyringException.class,
- () -> put(store, "B", ENTRY_B));
+ KeyringException failure = assertThrows(KeyringException.class, () -> put(store, "B", ENTRY_B));
assertSafe(failure, KeyringException.Code.KEYRING_IO_FAILED);
assertTrue(store.contains("A"));
assertFalse(store.contains("B"));
@@ -76,16 +72,15 @@ class KeyringAtomicPersistenceTest {
void mainImageDirectoryForceFailurePoisonsUntilReopen() throws Exception {
start("mainImageDirectoryForceFailurePoisonsUntilReopen");
Path path = initialized("main-directory.zek");
- FailingFileOperations operations = new FailingFileOperations(
- Target.MAIN_IMAGE, FailureStage.FORCE_DIRECTORY, false);
+ FailingFileOperations operations = new FailingFileOperations(Target.MAIN_IMAGE, FailureStage.FORCE_DIRECTORY,
+ false);
KeyringStore store;
try (KeyringPassword password = password()) {
- store = KeyringStore.open(path, password, KeyringProtection.standard(),
- deterministicRandom(70), operations);
+ store = KeyringStore.open(path, password, KeyringProtection.standard(), deterministicRandom(70),
+ operations);
}
try {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> put(store, "B", ENTRY_B));
+ KeyringException failure = assertThrows(KeyringException.class, () -> put(store, "B", ENTRY_B));
assertSafe(failure, KeyringException.Code.KEYRING_DURABILITY_UNCONFIRMED);
assertTrue(store.isDestroyed());
assertThrows(IllegalStateException.class, () -> store.contains("A"));
@@ -101,21 +96,17 @@ class KeyringAtomicPersistenceTest {
@Test
void sidecarPreCommitFailuresIssueNoUncommittedNonce() throws Exception {
start("sidecarPreCommitFailuresIssueNoUncommittedNonce");
- for (FailureStage stage : List.of(FailureStage.CREATE_TEMP,
- FailureStage.WRITE_TEMP, FailureStage.FORCE_TEMP,
+ for (FailureStage stage : List.of(FailureStage.CREATE_TEMP, FailureStage.WRITE_TEMP, FailureStage.FORCE_TEMP,
FailureStage.ATOMIC_MOVE)) {
Path path = initialized("sidecar-" + stage + ".zek");
byte[] mainBefore = Files.readAllBytes(path);
byte[] sidecarBefore = Files.readAllBytes(sidecar(path));
- FailingFileOperations operations =
- new FailingFileOperations(Target.NONCE_RESERVATION, stage, false);
+ FailingFileOperations operations = new FailingFileOperations(Target.NONCE_RESERVATION, stage, false);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password,
- KeyringProtection.standard(), deterministicRandom(90),
- operations)) {
+ KeyringStore store = KeyringStore.open(path, password, KeyringProtection.standard(),
+ deterministicRandom(90), operations)) {
long highWater = longField(store, "nonceHighWater");
- KeyringException failure = assertThrows(KeyringException.class,
- () -> put(store, "B", ENTRY_B));
+ KeyringException failure = assertThrows(KeyringException.class, () -> put(store, "B", ENTRY_B));
assertSafe(failure, KeyringException.Code.KEYRING_IO_FAILED);
assertEquals(highWater, longField(store, "nonceHighWater"));
assertFalse(store.contains("B"));
@@ -138,17 +129,16 @@ class KeyringAtomicPersistenceTest {
start("sidecarDirectoryForceFailureIssuesNothingUntilReopen");
Path path = initialized("sidecar-directory.zek");
long initialHighWater;
- FailingFileOperations operations = new FailingFileOperations(
- Target.NONCE_RESERVATION, FailureStage.FORCE_DIRECTORY, false);
+ FailingFileOperations operations = new FailingFileOperations(Target.NONCE_RESERVATION,
+ FailureStage.FORCE_DIRECTORY, false);
KeyringStore store;
try (KeyringPassword password = password()) {
- store = KeyringStore.open(path, password, KeyringProtection.standard(),
- deterministicRandom(110), operations);
+ store = KeyringStore.open(path, password, KeyringProtection.standard(), deterministicRandom(110),
+ operations);
}
try {
initialHighWater = longField(store, "nonceHighWater");
- KeyringException failure = assertThrows(KeyringException.class,
- () -> put(store, "B", ENTRY_B));
+ KeyringException failure = assertThrows(KeyringException.class, () -> put(store, "B", ENTRY_B));
assertSafe(failure, KeyringException.Code.KEYRING_DURABILITY_UNCONFIRMED);
assertFalse(store.isDestroyed());
assertThrows(IllegalStateException.class, () -> store.contains("A"));
@@ -157,8 +147,8 @@ class KeyringAtomicPersistenceTest {
store.close();
}
try (KeyringPassword password = password();
- KeyringStore reopened = KeyringStore.open(path, password,
- KeyringProtection.standard(), deterministicRandom(130))) {
+ KeyringStore reopened = KeyringStore.open(path, password, KeyringProtection.standard(),
+ deterministicRandom(130))) {
assertTrue(reopened.contains("A"));
assertFalse(reopened.contains("B"));
assertEquals(initialHighWater + 1, longField(reopened, "nonceHighWater"));
@@ -179,18 +169,14 @@ class KeyringAtomicPersistenceTest {
private void assertCleanupFailure(Target target, String file) throws Exception {
Path path = initialized(file);
- FailingFileOperations operations = new FailingFileOperations(
- target, FailureStage.WRITE_TEMP, true);
+ FailingFileOperations operations = new FailingFileOperations(target, FailureStage.WRITE_TEMP, true);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password,
- KeyringProtection.standard(), deterministicRandom(150),
- operations)) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> put(store, "B", ENTRY_B));
+ KeyringStore store = KeyringStore.open(path, password, KeyringProtection.standard(),
+ deterministicRandom(150), operations)) {
+ KeyringException failure = assertThrows(KeyringException.class, () -> put(store, "B", ENTRY_B));
assertSafe(failure, KeyringException.Code.KEYRING_IO_FAILED);
assertEquals(1, failure.getSuppressed().length);
- assertSafe((KeyringException) failure.getSuppressed()[0],
- KeyringException.Code.KEYRING_IO_FAILED);
+ assertSafe((KeyringException) failure.getSuppressed()[0], KeyringException.Code.KEYRING_IO_FAILED);
assertTrue(store.contains("A"));
assertFalse(store.contains("B"));
Path residual = operations.firstTemporary();
@@ -207,21 +193,19 @@ class KeyringAtomicPersistenceTest {
private Path initialized(String file) throws Exception {
Path path = temporaryDirectory.resolve(file);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom(1))) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom(1))) {
put(store, "A", ENTRY_A);
}
return path;
}
- private static void put(KeyringStore store, String alias, byte[] material)
- throws Exception {
+ private static void put(KeyringStore store, String alias, byte[] material) throws Exception {
store.putSecret(alias, "AES", new SecretKeySpec(material, "AES"));
}
private static void assertReopened(Path path, boolean hasB) throws Exception {
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
assertTrue(store.contains("A"));
assertEquals(hasB, store.contains("B"));
assertSecretEquals(ENTRY_A, store.getSecret("A"));
@@ -242,21 +226,18 @@ class KeyringAtomicPersistenceTest {
private static void assertAlreadyOpen(Path path) throws Exception {
try (KeyringPassword password = password()) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
+ KeyringException failure = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
assertSafe(failure, KeyringException.Code.KEYRING_ALREADY_OPEN);
}
}
- private static void assertSafe(KeyringException failure,
- KeyringException.Code expected) {
+ private static void assertSafe(KeyringException failure, KeyringException.Code expected) {
assertEquals(expected, failure.code());
assertEquals(expected.name(), failure.getMessage());
assertNull(failure.getCause());
}
- private static void assertSentinelAbsent(Path directory, byte[] sentinel)
- throws IOException {
+ private static void assertSentinelAbsent(Path directory, byte[] sentinel) throws IOException {
try (java.util.stream.Stream paths = Files.list(directory)) {
for (Path current : paths.toList()) {
if (Files.isRegularFile(current)) {
@@ -272,8 +253,7 @@ class KeyringAtomicPersistenceTest {
}
private static int indexOf(byte[] haystack, byte[] needle) {
- outer:
- for (int index = 0; index <= haystack.length - needle.length; index++) {
+ outer: for (int index = 0; index <= haystack.length - needle.length; index++) {
for (int offset = 0; offset < needle.length; offset++) {
if (haystack[index + offset] != needle[offset]) {
continue outer;
@@ -329,12 +309,7 @@ class KeyringAtomicPersistenceTest {
}
private enum FailureStage {
- CREATE_TEMP,
- WRITE_TEMP,
- FORCE_TEMP,
- ATOMIC_MOVE,
- FORCE_DIRECTORY,
- DELETE_TEMP
+ CREATE_TEMP, WRITE_TEMP, FORCE_TEMP, ATOMIC_MOVE, FORCE_DIRECTORY, DELETE_TEMP
}
private static final class FailingFileOperations implements KeyringFileOperations {
@@ -345,20 +320,17 @@ class KeyringAtomicPersistenceTest {
private boolean primaryFailed;
private boolean cleanupFailed;
- private FailingFileOperations(Target target, FailureStage primaryStage,
- boolean failCleanup) {
+ private FailingFileOperations(Target target, FailureStage primaryStage, boolean failCleanup) {
this.target = target;
this.primaryStage = primaryStage;
this.failCleanup = failCleanup;
}
@Override
- public Path createTemporary(Target actualTarget, Path parent, String prefix,
- String suffix, FileAttribute> permissions)
- throws IOException {
+ public Path createTemporary(Target actualTarget, Path parent, String prefix, String suffix,
+ FileAttribute> permissions) throws IOException {
failBefore(actualTarget, FailureStage.CREATE_TEMP);
- Path temporary = NIO.createTemporary(actualTarget, parent, prefix, suffix,
- permissions);
+ Path temporary = NIO.createTemporary(actualTarget, parent, prefix, suffix, permissions);
if (actualTarget == target) {
temporaryPaths.add(temporary);
}
@@ -366,22 +338,19 @@ class KeyringAtomicPersistenceTest {
}
@Override
- public void writeTemporary(Target actualTarget, Path temporary, byte[] image)
- throws IOException {
+ public void writeTemporary(Target actualTarget, Path temporary, byte[] image) throws IOException {
NIO.writeTemporary(actualTarget, temporary, image);
failAfter(actualTarget, FailureStage.WRITE_TEMP);
}
@Override
- public void forceTemporary(Target actualTarget, Path temporary)
- throws IOException {
+ public void forceTemporary(Target actualTarget, Path temporary) throws IOException {
NIO.forceTemporary(actualTarget, temporary);
failAfter(actualTarget, FailureStage.FORCE_TEMP);
}
@Override
- public void atomicReplace(Target actualTarget, Path temporary, Path destination)
- throws IOException {
+ public void atomicReplace(Target actualTarget, Path temporary, Path destination) throws IOException {
failBefore(actualTarget, FailureStage.ATOMIC_MOVE);
NIO.atomicReplace(actualTarget, temporary, destination);
}
@@ -393,8 +362,7 @@ class KeyringAtomicPersistenceTest {
}
@Override
- public void deleteTemporary(Target actualTarget, Path temporary)
- throws IOException {
+ public void deleteTemporary(Target actualTarget, Path temporary) throws IOException {
if (actualTarget == target && failCleanup && !cleanupFailed) {
cleanupFailed = true;
throw new IOException("DELETE_TEMP_SENTINEL");
@@ -402,16 +370,14 @@ class KeyringAtomicPersistenceTest {
NIO.deleteTemporary(actualTarget, temporary);
}
- private void failBefore(Target actualTarget, FailureStage stage)
- throws IOException {
+ private void failBefore(Target actualTarget, FailureStage stage) throws IOException {
if (actualTarget == target && primaryStage == stage && !primaryFailed) {
primaryFailed = true;
throw new IOException(stage.name() + "_SENTINEL");
}
}
- private void failAfter(Target actualTarget, FailureStage stage)
- throws IOException {
+ private void failAfter(Target actualTarget, FailureStage stage) throws IOException {
failBefore(actualTarget, stage);
}
diff --git a/lib/src/test/java/zeroecho/core/storage/KeyringCryptographicFormatTest.java b/lib/src/test/java/zeroecho/core/storage/KeyringCryptographicFormatTest.java
index c2c786c..10b1877 100644
--- a/lib/src/test/java/zeroecho/core/storage/KeyringCryptographicFormatTest.java
+++ b/lib/src/test/java/zeroecho/core/storage/KeyringCryptographicFormatTest.java
@@ -56,62 +56,57 @@ class KeyringCryptographicFormatTest {
Path source = createEmpty("master-source.zek", 1);
byte[] image = Files.readAllBytes(source);
try {
- assertUniformUnlockFailure(source,
- new char[] { 'w', 'r', 'o', 'n', 'g' });
+ assertUniformUnlockFailure(source, new char[] { 'w', 'r', 'o', 'n', 'g' });
- assertUniformUnlockFailure(copyWithMutation(source, image, "wrapped-cipher",
- value -> value[WRAPPED_OFFSET] ^= 1), PASSWORD);
- assertUniformUnlockFailure(copyWithMutation(source, image, "wrapped-tag",
- value -> value[WRAPPED_OFFSET + 47] ^= 1), PASSWORD);
- assertUniformUnlockFailure(copyWithMutation(source, image, "salt",
- value -> value[SALT_OFFSET] ^= 1), PASSWORD);
+ assertUniformUnlockFailure(
+ copyWithMutation(source, image, "wrapped-cipher", value -> value[WRAPPED_OFFSET] ^= 1), PASSWORD);
+ assertUniformUnlockFailure(
+ copyWithMutation(source, image, "wrapped-tag", value -> value[WRAPPED_OFFSET + 47] ^= 1), PASSWORD);
+ assertUniformUnlockFailure(copyWithMutation(source, image, "salt", value -> value[SALT_OFFSET] ^= 1),
+ PASSWORD);
assertUniformUnlockFailure(copyWithMutation(source, image, "iterations-auth",
value -> putInt(value, ITERATIONS_OFFSET, 600_001)), PASSWORD);
- assertUniformUnlockFailure(copyWithMutation(source, image, "wrap-nonce-auth",
- value -> value[WRAP_NONCE_OFFSET + 1] ^= 1), PASSWORD);
+ assertUniformUnlockFailure(
+ copyWithMutation(source, image, "wrap-nonce-auth", value -> value[WRAP_NONCE_OFFSET + 1] ^= 1),
+ PASSWORD);
- assertRejected(copyWithMutation(source, image, "iterations-low",
- value -> putInt(value, ITERATIONS_OFFSET, 599_999)),
+ assertRejected(
+ copyWithMutation(source, image, "iterations-low",
+ value -> putInt(value, ITERATIONS_OFFSET, 599_999)),
KeyringException.Code.KEYRING_LIMIT_EXCEEDED);
- assertRejected(copyWithMutation(source, image, "iterations-operational",
- value -> putInt(value, ITERATIONS_OFFSET, 1_000_001)),
+ assertRejected(
+ copyWithMutation(source, image, "iterations-operational",
+ value -> putInt(value, ITERATIONS_OFFSET, 1_000_001)),
KeyringException.Code.KEYRING_LIMIT_EXCEEDED);
- assertRejected(copyWithMutation(source, image, "iterations-absolute",
- value -> putInt(value, ITERATIONS_OFFSET, 10_000_001)),
+ assertRejected(
+ copyWithMutation(source, image, "iterations-absolute",
+ value -> putInt(value, ITERATIONS_OFFSET, 10_000_001)),
KeyringException.Code.KEYRING_LIMIT_EXCEEDED);
- assertRejected(copyWithMutation(source, image, "unknown-kdf",
- value -> value[KDF_OFFSET] = 99),
+ assertRejected(copyWithMutation(source, image, "unknown-kdf", value -> value[KDF_OFFSET] = 99),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "unknown-aead",
- value -> value[AEAD_OFFSET] = 99),
+ assertRejected(copyWithMutation(source, image, "unknown-aead", value -> value[AEAD_OFFSET] = 99),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "kek-length",
- value -> putInt(value, KEK_LENGTH_OFFSET, 31)),
+ assertRejected(copyWithMutation(source, image, "kek-length", value -> putInt(value, KEK_LENGTH_OFFSET, 31)),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "wrap-domain",
- value -> value[WRAP_NONCE_OFFSET] = 2),
+ assertRejected(copyWithMutation(source, image, "wrap-domain", value -> value[WRAP_NONCE_OFFSET] = 2),
KeyringException.Code.KEYRING_FORMAT_INVALID);
for (int wrappedLength : new int[] { -1, 47, 49 }) {
- assertRejected(copyWithMutation(source, image,
- "wrapped-length-" + wrappedLength,
- value -> putInt(value, WRAPPED_LENGTH_OFFSET, wrappedLength)),
- wrappedLength == 47
- ? KeyringException.Code.KEYRING_FORMAT_INVALID
+ assertRejected(
+ copyWithMutation(source, image, "wrapped-length-" + wrappedLength,
+ value -> putInt(value, WRAPPED_LENGTH_OFFSET, wrappedLength)),
+ wrappedLength == 47 ? KeyringException.Code.KEYRING_FORMAT_INVALID
: KeyringException.Code.KEYRING_LIMIT_EXCEEDED);
}
- int[] boundaries = { 1, VERSION_OFFSET, STORE_ID_OFFSET, KDF_OFFSET,
- ITERATIONS_OFFSET, SALT_OFFSET, KEK_LENGTH_OFFSET, AEAD_OFFSET,
- WRAP_NONCE_OFFSET, WRAPPED_LENGTH_OFFSET, WRAPPED_OFFSET,
+ int[] boundaries = { 1, VERSION_OFFSET, STORE_ID_OFFSET, KDF_OFFSET, ITERATIONS_OFFSET, SALT_OFFSET,
+ KEK_LENGTH_OFFSET, AEAD_OFFSET, WRAP_NONCE_OFFSET, WRAPPED_LENGTH_OFFSET, WRAPPED_OFFSET,
WRAPPED_OFFSET + 47, ENTRY_COUNT_OFFSET };
for (int boundary : boundaries) {
- Path truncated = copyImage(source, Arrays.copyOf(image, boundary),
- "truncated-" + boundary);
+ Path truncated = copyImage(source, Arrays.copyOf(image, boundary), "truncated-" + boundary);
assertSafeRejected(truncated);
}
byte[] trailing = Arrays.copyOf(image, image.length + 1);
- assertRejected(copyImage(source, trailing, "trailing"),
- KeyringException.Code.KEYRING_FORMAT_INVALID);
+ assertRejected(copyImage(source, trailing, "trailing"), KeyringException.Code.KEYRING_FORMAT_INVALID);
} finally {
wipe(image);
}
@@ -125,44 +120,47 @@ class KeyringCryptographicFormatTest {
byte[] image = Files.readAllBytes(source);
ImageLayout layout = layout(image);
try {
- assertRejected(copyWithMutation(source, image, "entry-cipher",
- value -> value[layout.entries.get(0).ciphertextOffset] ^= 1),
+ assertRejected(
+ copyWithMutation(source, image, "entry-cipher",
+ value -> value[layout.entries.get(0).ciphertextOffset] ^= 1),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "entry-tag",
- value -> value[layout.entries.get(0).endOffset - 1] ^= 1),
+ assertRejected(
+ copyWithMutation(source, image, "entry-tag",
+ value -> value[layout.entries.get(0).endOffset - 1] ^= 1),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "entry-nonce",
- value -> value[layout.entries.get(0).nonceOffset] ^= 1),
+ assertRejected(
+ copyWithMutation(source, image, "entry-nonce",
+ value -> value[layout.entries.get(0).nonceOffset] ^= 1),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "entry-id",
- value -> value[layout.entries.get(0).entryIdOffset] ^= 1),
+ assertRejected(
+ copyWithMutation(source, image, "entry-id",
+ value -> value[layout.entries.get(0).entryIdOffset] ^= 1),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "manifest-nonce",
- value -> value[layout.manifestNonceOffset] ^= 1),
+ assertRejected(
+ copyWithMutation(source, image, "manifest-nonce", value -> value[layout.manifestNonceOffset] ^= 1),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "manifest-cipher",
- value -> value[layout.manifestCipherOffset] ^= 1),
+ assertRejected(
+ copyWithMutation(source, image, "manifest-cipher",
+ value -> value[layout.manifestCipherOffset] ^= 1),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "manifest-tag",
- value -> value[image.length - 1] ^= 1),
+ assertRejected(copyWithMutation(source, image, "manifest-tag", value -> value[image.length - 1] ^= 1),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyImage(source, reorderEntries(image, layout),
- "entry-reorder"), KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyImage(source, duplicateFirstEntry(image, layout),
- "entry-duplicate"), KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyImage(source, deleteFirstEntry(image, layout),
- "entry-delete"), KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyImage(source, insertUnauthenticatedEntry(image, layout),
- "entry-insert"), KeyringException.Code.KEYRING_FORMAT_INVALID);
+ assertRejected(copyImage(source, reorderEntries(image, layout), "entry-reorder"),
+ KeyringException.Code.KEYRING_FORMAT_INVALID);
+ assertRejected(copyImage(source, duplicateFirstEntry(image, layout), "entry-duplicate"),
+ KeyringException.Code.KEYRING_FORMAT_INVALID);
+ assertRejected(copyImage(source, deleteFirstEntry(image, layout), "entry-delete"),
+ KeyringException.Code.KEYRING_FORMAT_INVALID);
+ assertRejected(copyImage(source, insertUnauthenticatedEntry(image, layout), "entry-insert"),
+ KeyringException.Code.KEYRING_FORMAT_INVALID);
Path other = createTwoEntries("outer-other.zek", 107);
byte[] otherImage = Files.readAllBytes(other);
try {
ImageLayout otherLayout = layout(otherImage);
byte[] copied = replaceEntry(otherImage, otherLayout.entries.get(0),
- slice(image, layout.entries.get(0).entryIdOffset,
- layout.entries.get(0).endOffset));
+ slice(image, layout.entries.get(0).entryIdOffset, layout.entries.get(0).endOffset));
assertRejected(copyImage(other, copied, "entry-cross-store"),
KeyringException.Code.KEYRING_FORMAT_INVALID);
wipe(copied);
@@ -192,19 +190,15 @@ class KeyringCryptographicFormatTest {
value -> value[descriptor(value, 0).nonceOffset] ^= 1);
assertManifestMutationRejected(fixture.path, image, masterKey, "cipher-length",
value -> putInt(value, descriptor(value, 0).ciphertextLengthOffset,
- getInt(value,
- descriptor(value, 0).ciphertextLengthOffset) + 1));
+ getInt(value, descriptor(value, 0).ciphertextLengthOffset) + 1));
assertManifestMutationRejected(fixture.path, image, masterKey, "cipher-digest",
value -> value[descriptor(value, 0).digestOffset] ^= 1);
- assertManifestMutationRejected(fixture.path, image, masterKey, "duplicate-id",
- value -> copyField(value, descriptor(value, 0).entryIdOffset,
- descriptor(value, 1).entryIdOffset, KeyringStore.UUID_BYTES));
- assertManifestMutationRejected(fixture.path, image, masterKey, "duplicate-nonce",
- value -> copyField(value, descriptor(value, 0).nonceOffset,
- descriptor(value, 1).nonceOffset, KeyringStore.NONCE_BYTES));
+ assertManifestMutationRejected(fixture.path, image, masterKey, "duplicate-id", value -> copyField(value,
+ descriptor(value, 0).entryIdOffset, descriptor(value, 1).entryIdOffset, KeyringStore.UUID_BYTES));
+ assertManifestMutationRejected(fixture.path, image, masterKey, "duplicate-nonce", value -> copyField(value,
+ descriptor(value, 0).nonceOffset, descriptor(value, 1).nonceOffset, KeyringStore.NONCE_BYTES));
assertManifestMutationRejected(fixture.path, image, masterKey, "duplicate-alias",
- value -> copyField(value, descriptor(value, 0).aliasOffset,
- descriptor(value, 1).aliasOffset,
+ value -> copyField(value, descriptor(value, 0).aliasOffset, descriptor(value, 1).aliasOffset,
descriptor(value, 0).aliasLength));
assertManifestMutationRejected(fixture.path, image, masterKey, "unknown-algorithm",
value -> overwriteAscii(value, descriptor(value, 0).algorithmOffset, "BAD"),
@@ -222,33 +216,29 @@ class KeyringCryptographicFormatTest {
value -> putInt(value, 16, 1));
assertManifestMutationRejected(fixture.path, image, masterKey, "manifest-reorder",
KeyringCryptographicFormatTest::swapManifestDescriptors);
- assertManifestReplacementRejected(fixture.path, image, masterKey,
- "manifest-truncated", value -> Arrays.copyOf(value, value.length - 1));
- assertManifestReplacementRejected(fixture.path, image, masterKey,
- "manifest-trailing", value -> Arrays.copyOf(value, value.length + 1));
+ assertManifestReplacementRejected(fixture.path, image, masterKey, "manifest-truncated",
+ value -> Arrays.copyOf(value, value.length - 1));
+ assertManifestReplacementRejected(fixture.path, image, masterKey, "manifest-trailing",
+ value -> Arrays.copyOf(value, value.length + 1));
- assertEntryMutationRejected(fixture.path, image, masterKey, "entry-cipher-auth",
- value -> value[0] ^= 1, false);
+ assertEntryMutationRejected(fixture.path, image, masterKey, "entry-cipher-auth", value -> value[0] ^= 1,
+ false);
assertEntryMutationRejected(fixture.path, image, masterKey, "entry-tag-auth",
value -> value[value.length - 1] ^= 1, false);
- assertEntryMutationRejected(fixture.path, image, masterKey, "entry-version",
- value -> putInt(value, 0, 2), true);
+ assertEntryMutationRejected(fixture.path, image, masterKey, "entry-version", value -> putInt(value, 0, 2),
+ true);
assertEntryMutationRejected(fixture.path, image, masterKey, "alias-substitution",
value -> overwriteAscii(value, Integer.BYTES * 2, "xxx"), true);
- assertEntryMutationRejected(fixture.path, image, masterKey,
- "algorithm-substitution",
+ assertEntryMutationRejected(fixture.path, image, masterKey, "algorithm-substitution",
value -> overwriteAscii(value, Integer.BYTES * 3 + 3, "BAD"), true);
assertEntryMutationRejected(fixture.path, image, masterKey, "kind-substitution",
value -> value[Integer.BYTES * 4 + 2] = 1, true);
- assertEntryMutationRejected(fixture.path, image, masterKey,
- "encoding-substitution",
+ assertEntryMutationRejected(fixture.path, image, masterKey, "encoding-substitution",
value -> value[Integer.BYTES * 4 + 3] = 1, true);
assertEntryMutationRejected(fixture.path, image, masterKey, "hmac-substitution",
value -> value[Integer.BYTES * 4 + 4] = 1, true);
- assertCoherentIdentityMutationRejected(fixture.path, image, masterKey,
- "coherent-entry-id", true);
- assertCoherentIdentityMutationRejected(fixture.path, image, masterKey,
- "coherent-entry-nonce", false);
+ assertCoherentIdentityMutationRejected(fixture.path, image, masterKey, "coherent-entry-id", true);
+ assertCoherentIdentityMutationRejected(fixture.path, image, masterKey, "coherent-entry-nonce", false);
} finally {
wipe(image);
wipe(masterKey);
@@ -259,35 +249,24 @@ class KeyringCryptographicFormatTest {
@Test
void decodedEntryAndManifestSchemasRejectTypeConfusionAndBounds() throws Exception {
start("decodedEntryAndManifestSchemasRejectTypeConfusionAndBounds");
- byte[] validEntry = entryPlaintext(1, "a", "AES", 3, 3, 0,
- new byte[32], false);
+ byte[] validEntry = entryPlaintext(1, "a", "AES", 3, 3, 0, new byte[32], false);
try {
invokeDecodeEntry(validEntry);
- assertDecodeEntryRejected(entryPlaintext(2, "a", "AES", 3, 3, 0,
- new byte[32], false));
- assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 99, 3, 0,
- new byte[32], false));
- assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 3, 99, 0,
- new byte[32], false));
- assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 3, 3, 99,
- new byte[32], false));
- assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 3, 3, 0,
- new byte[32], true));
+ assertDecodeEntryRejected(entryPlaintext(2, "a", "AES", 3, 3, 0, new byte[32], false));
+ assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 99, 3, 0, new byte[32], false));
+ assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 3, 99, 0, new byte[32], false));
+ assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 3, 3, 99, new byte[32], false));
+ assertDecodeEntryRejected(entryPlaintext(1, "a", "AES", 3, 3, 0, new byte[32], true));
assertDecodeEntryRejected(lengthOnlyEntry(-1, "AES"));
- assertDecodeEntryRejected(lengthOnlyEntry(KeyringStore.MAX_ALIAS_BYTES + 1,
- "AES"));
+ assertDecodeEntryRejected(lengthOnlyEntry(KeyringStore.MAX_ALIAS_BYTES + 1, "AES"));
assertDecodeEntryRejected(metadataLengthEntry(-1));
- assertDecodeEntryRejected(metadataLengthEntry(
- KeyringStore.MAX_METADATA_BYTES + 1));
+ assertDecodeEntryRejected(metadataLengthEntry(KeyringStore.MAX_METADATA_BYTES + 1));
assertDecodeEntryRejected(encodedLengthEntry(-1));
- assertDecodeEntryRejected(encodedLengthEntry(
- KeyringStore.MAX_ENTRY_CIPHERTEXT_BYTES));
+ assertDecodeEntryRejected(encodedLengthEntry(KeyringStore.MAX_ENTRY_CIPHERTEXT_BYTES));
- byte[] maximumAlias = entryPlaintext(1,
- "a".repeat(KeyringStore.MAX_ALIAS_BYTES), "AES", 3, 3, 0,
+ byte[] maximumAlias = entryPlaintext(1, "a".repeat(KeyringStore.MAX_ALIAS_BYTES), "AES", 3, 3, 0,
new byte[1], false);
- byte[] maximumMetadata = entryPlaintext(1, "a",
- "A".repeat(KeyringStore.MAX_METADATA_BYTES), 3, 3, 0,
+ byte[] maximumMetadata = entryPlaintext(1, "a", "A".repeat(KeyringStore.MAX_METADATA_BYTES), 3, 3, 0,
new byte[1], false);
try {
invokeDecodeEntry(maximumAlias);
@@ -320,26 +299,26 @@ class KeyringCryptographicFormatTest {
Path source = createEmpty("bounds-source.zek", 31);
byte[] image = Files.readAllBytes(source);
try {
- assertRejected(copyWithMutation(source, image, "negative-count",
- value -> putInt(value, ENTRY_COUNT_OFFSET, -1)),
+ assertRejected(
+ copyWithMutation(source, image, "negative-count", value -> putInt(value, ENTRY_COUNT_OFFSET, -1)),
KeyringException.Code.KEYRING_LIMIT_EXCEEDED);
- assertRejected(copyWithMutation(source, image, "oversized-count",
- value -> putInt(value, ENTRY_COUNT_OFFSET,
- KeyringStore.MAX_ENTRY_COUNT + 1)),
+ assertRejected(
+ copyWithMutation(source, image, "oversized-count",
+ value -> putInt(value, ENTRY_COUNT_OFFSET, KeyringStore.MAX_ENTRY_COUNT + 1)),
KeyringException.Code.KEYRING_LIMIT_EXCEEDED);
- assertRejected(copyWithMutation(source, image, "old-main-version",
- value -> putInt(value, VERSION_OFFSET, 1)),
+ assertRejected(
+ copyWithMutation(source, image, "old-main-version", value -> putInt(value, VERSION_OFFSET, 1)),
KeyringException.Code.KEYRING_FORMAT_INVALID);
- assertRejected(copyWithMutation(source, image, "draft-main-version",
- value -> putInt(value, VERSION_OFFSET, 3)),
+ assertRejected(
+ copyWithMutation(source, image, "draft-main-version", value -> putInt(value, VERSION_OFFSET, 3)),
KeyringException.Code.KEYRING_FORMAT_INVALID);
} finally {
wipe(image);
}
Path oversized = temporaryDirectory.resolve("oversized.zek");
- try (java.nio.channels.FileChannel channel = java.nio.channels.FileChannel.open(
- oversized, StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
+ try (java.nio.channels.FileChannel channel = java.nio.channels.FileChannel.open(oversized,
+ StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
channel.position(KeyringStore.MAX_FILE_BYTES);
channel.write(ByteBuffer.wrap(new byte[] { 0 }));
}
@@ -351,8 +330,7 @@ class KeyringCryptographicFormatTest {
}
Path plaintext = temporaryDirectory.resolve("plaintext-v1.zek");
- Files.writeString(plaintext, "# KeyringStore v1\njava.io.File\nHmacSHA1\n",
- StandardCharsets.UTF_8);
+ Files.writeString(plaintext, "# KeyringStore v1\njava.io.File\nHmacSHA1\n", StandardCharsets.UTF_8);
ownerOnly(plaintext);
assertRejected(plaintext, KeyringException.Code.KEYRING_FORMAT_INVALID);
@@ -363,10 +341,9 @@ class KeyringCryptographicFormatTest {
root.addHandler(handler);
try {
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(protectedStore, password,
- KeyringProtection.standard(), deterministicRandom(61))) {
- store.putSecret("sentinel", "AES",
- new SecretKeySpec(Arrays.copyOf(sentinel, 32), "AES"));
+ KeyringStore store = KeyringStore.create(protectedStore, password, KeyringProtection.standard(),
+ deterministicRandom(61))) {
+ store.putSecret("sentinel", "AES", new SecretKeySpec(Arrays.copyOf(sentinel, 32), "AES"));
}
assertAbsent(Files.readAllBytes(protectedStore), sentinel);
assertAbsent(Files.readAllBytes(sidecar(protectedStore)), sentinel);
@@ -397,8 +374,8 @@ class KeyringCryptographicFormatTest {
private Path createEmpty(String name, int seed) throws Exception {
Path path = temporaryDirectory.resolve(name);
try (KeyringPassword password = password();
- KeyringStore ignored = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom(seed))) {
+ KeyringStore ignored = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom(seed))) {
// Current empty image and reservation sidecar are durable.
}
return path;
@@ -418,8 +395,8 @@ class KeyringCryptographicFormatTest {
Arrays.fill(first, (byte) 0x31);
Arrays.fill(second, (byte) 0x42);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom(seed))) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom(seed))) {
store.putSecret("one", "AES", new SecretKeySpec(first, "AES"));
store.putSecret("two", "AES", new SecretKeySpec(second, "AES"));
masterKey = bytesField(store, "masterKey").clone();
@@ -430,29 +407,28 @@ class KeyringCryptographicFormatTest {
return new StoreFixture(path, masterKey);
}
- private void assertManifestMutationRejected(Path source, byte[] image, byte[] masterKey,
- String name, Mutation mutation) throws Exception {
+ private void assertManifestMutationRejected(Path source, byte[] image, byte[] masterKey, String name,
+ Mutation mutation) throws Exception {
assertManifestMutationRejected(source, image, masterKey, name, mutation,
KeyringException.Code.KEYRING_FORMAT_INVALID);
}
- private void assertManifestMutationRejected(Path source, byte[] image, byte[] masterKey,
- String name, Mutation mutation, KeyringException.Code code) throws Exception {
+ private void assertManifestMutationRejected(Path source, byte[] image, byte[] masterKey, String name,
+ Mutation mutation, KeyringException.Code code) throws Exception {
assertManifestReplacementRejected(source, image, masterKey, name, value -> {
mutation.apply(value);
return value;
}, code);
}
- private void assertManifestReplacementRejected(Path source, byte[] image,
- byte[] masterKey, String name, Replacement mutation) throws Exception {
+ private void assertManifestReplacementRejected(Path source, byte[] image, byte[] masterKey, String name,
+ Replacement mutation) throws Exception {
assertManifestReplacementRejected(source, image, masterKey, name, mutation,
KeyringException.Code.KEYRING_FORMAT_INVALID);
}
- private void assertManifestReplacementRejected(Path source, byte[] image,
- byte[] masterKey, String name, Replacement mutation,
- KeyringException.Code code) throws Exception {
+ private void assertManifestReplacementRejected(Path source, byte[] image, byte[] masterKey, String name,
+ Replacement mutation, KeyringException.Code code) throws Exception {
byte[] plaintext = decryptManifest(image, masterKey);
byte[] replacement = null;
byte[] rewritten = null;
@@ -469,8 +445,8 @@ class KeyringCryptographicFormatTest {
}
}
- private void assertEntryMutationRejected(Path source, byte[] image, byte[] masterKey,
- String name, Mutation mutation, boolean plaintextMutation) throws Exception {
+ private void assertEntryMutationRejected(Path source, byte[] image, byte[] masterKey, String name,
+ Mutation mutation, boolean plaintextMutation) throws Exception {
ImageLayout imageLayout = layout(image);
WireEntry entry = imageLayout.entries.get(0);
byte[] ciphertext = slice(image, entry.ciphertextOffset, entry.endOffset);
@@ -478,8 +454,7 @@ class KeyringCryptographicFormatTest {
byte[] rewritten = null;
try {
if (plaintextMutation) {
- byte[] nonce = slice(image, entry.nonceOffset,
- entry.nonceOffset + KeyringStore.NONCE_BYTES);
+ byte[] nonce = slice(image, entry.nonceOffset, entry.nonceOffset + KeyringStore.NONCE_BYTES);
byte[] aad = entryAad(image, entry, 0);
byte[] plaintext = null;
try {
@@ -497,13 +472,10 @@ class KeyringCryptographicFormatTest {
}
rewritten = installFirstCiphertext(image, masterKey, changed);
Path path = copyImage(source, rewritten, name);
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> store.getSecret("one"));
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
+ KeyringException failure = assertThrows(KeyringException.class, () -> store.getSecret("one"));
assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID, failure.code());
- assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID.name(),
- failure.getMessage());
+ assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID.name(), failure.getMessage());
}
} finally {
wipe(ciphertext);
@@ -512,8 +484,8 @@ class KeyringCryptographicFormatTest {
}
}
- private void assertCoherentIdentityMutationRejected(Path source, byte[] image,
- byte[] masterKey, String name, boolean entryId) throws Exception {
+ private void assertCoherentIdentityMutationRejected(Path source, byte[] image, byte[] masterKey, String name,
+ boolean entryId) throws Exception {
byte[] rewritten = image.clone();
byte[] manifest = decryptManifest(image, masterKey);
try {
@@ -531,10 +503,8 @@ class KeyringCryptographicFormatTest {
wipe(rewritten);
rewritten = withManifest;
Path path = copyImage(source, rewritten, name);
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> store.getSecret("one"));
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
+ KeyringException failure = assertThrows(KeyringException.class, () -> store.getSecret("one"));
assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID, failure.code());
}
} finally {
@@ -543,8 +513,7 @@ class KeyringCryptographicFormatTest {
}
}
- private static byte[] installFirstCiphertext(byte[] image, byte[] masterKey,
- byte[] ciphertext) throws Exception {
+ private static byte[] installFirstCiphertext(byte[] image, byte[] masterKey, byte[] ciphertext) throws Exception {
byte[] result = image.clone();
ImageLayout imageLayout = layout(result);
WireEntry entry = imageLayout.entries.get(0);
@@ -581,8 +550,7 @@ class KeyringCryptographicFormatTest {
}
}
- private static byte[] replaceManifest(byte[] image, byte[] masterKey,
- byte[] plaintext) throws Exception {
+ private static byte[] replaceManifest(byte[] image, byte[] masterKey, byte[] plaintext) throws Exception {
ImageLayout imageLayout = layout(image);
byte[] nonce = slice(image, imageLayout.manifestNonceOffset,
imageLayout.manifestNonceOffset + KeyringStore.NONCE_BYTES);
@@ -591,11 +559,9 @@ class KeyringCryptographicFormatTest {
try {
ciphertext = crypt(Cipher.ENCRYPT_MODE, masterKey, nonce, aad, plaintext);
int lengthOffset = imageLayout.manifestCipherOffset - Integer.BYTES;
- byte[] result = Arrays.copyOf(image, imageLayout.manifestCipherOffset
- + ciphertext.length);
+ byte[] result = Arrays.copyOf(image, imageLayout.manifestCipherOffset + ciphertext.length);
putInt(result, lengthOffset, ciphertext.length);
- System.arraycopy(ciphertext, 0, result, imageLayout.manifestCipherOffset,
- ciphertext.length);
+ System.arraycopy(ciphertext, 0, result, imageLayout.manifestCipherOffset, ciphertext.length);
return result;
} finally {
wipe(nonce);
@@ -605,8 +571,7 @@ class KeyringCryptographicFormatTest {
}
private static byte[] manifestAad(byte[] image) {
- ByteBuffer buffer = ByteBuffer.allocate(8 + Integer.BYTES
- + KeyringStore.UUID_BYTES + Integer.BYTES * 2);
+ ByteBuffer buffer = ByteBuffer.allocate(8 + Integer.BYTES + KeyringStore.UUID_BYTES + Integer.BYTES * 2);
buffer.put(KeyringStore.MAGIC);
buffer.putInt(KeyringStore.FORMAT_VERSION);
buffer.put(image, STORE_ID_OFFSET, KeyringStore.UUID_BYTES);
@@ -616,8 +581,7 @@ class KeyringCryptographicFormatTest {
}
private static byte[] entryAad(byte[] image, WireEntry entry, int position) {
- ByteBuffer buffer = ByteBuffer.allocate(8 + Integer.BYTES
- + KeyringStore.UUID_BYTES * 2 + Integer.BYTES * 2);
+ ByteBuffer buffer = ByteBuffer.allocate(8 + Integer.BYTES + KeyringStore.UUID_BYTES * 2 + Integer.BYTES * 2);
buffer.put(KeyringStore.MAGIC);
buffer.putInt(KeyringStore.FORMAT_VERSION);
buffer.put(image, STORE_ID_OFFSET, KeyringStore.UUID_BYTES);
@@ -627,11 +591,9 @@ class KeyringCryptographicFormatTest {
return buffer.array();
}
- private static byte[] crypt(int mode, byte[] key, byte[] nonce, byte[] aad,
- byte[] input) throws Exception {
+ private static byte[] crypt(int mode, byte[] key, byte[] nonce, byte[] aad, byte[] input) throws Exception {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
- cipher.init(mode, new SecretKeySpec(key, "AES"),
- new GCMParameterSpec(KeyringStore.GCM_TAG_BITS, nonce));
+ cipher.init(mode, new SecretKeySpec(key, "AES"), new GCMParameterSpec(KeyringStore.GCM_TAG_BITS, nonce));
cipher.updateAAD(aad);
return cipher.doFinal(input);
}
@@ -664,9 +626,8 @@ class KeyringCryptographicFormatTest {
int digest = buffer.position();
buffer.position(digest + KeyringStore.SHA256_BYTES);
if (index == target) {
- return new ManifestDescriptor(start, buffer.position(), entryId, position,
- alias, aliasLength, algorithm, kind, encoding,
- hmac, nonce, ciphertextLength, digest);
+ return new ManifestDescriptor(start, buffer.position(), entryId, position, alias, aliasLength,
+ algorithm, kind, encoding, hmac, nonce, ciphertextLength, digest);
}
}
throw new IllegalArgumentException("descriptor index");
@@ -712,11 +673,9 @@ class KeyringCryptographicFormatTest {
private void assertUniformUnlockFailure(Path source, char[] candidate) throws Exception {
try (KeyringPassword password = new KeyringPassword(candidate)) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> KeyringStore.open(source, password));
+ KeyringException failure = assertThrows(KeyringException.class, () -> KeyringStore.open(source, password));
assertEquals(KeyringException.Code.KEYRING_UNLOCK_FAILED, failure.code());
- assertEquals(KeyringException.Code.KEYRING_UNLOCK_FAILED.name(),
- failure.getMessage());
+ assertEquals(KeyringException.Code.KEYRING_UNLOCK_FAILED.name(), failure.getMessage());
assertNull(failure.getCause());
assertEquals(0, failure.getSuppressed().length);
}
@@ -724,8 +683,7 @@ class KeyringCryptographicFormatTest {
private void assertRejected(Path path, KeyringException.Code code) throws Exception {
try (KeyringPassword password = password()) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
+ KeyringException failure = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
assertEquals(code, failure.code());
assertEquals(code.name(), failure.getMessage());
assertNull(failure.getCause());
@@ -734,18 +692,16 @@ class KeyringCryptographicFormatTest {
private void assertSafeRejected(Path path) throws Exception {
try (KeyringPassword password = password()) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
- assertTrue(Set.of(KeyringException.Code.KEYRING_FORMAT_INVALID,
- KeyringException.Code.KEYRING_LIMIT_EXCEEDED,
- KeyringException.Code.KEYRING_UNLOCK_FAILED).contains(failure.code()));
+ KeyringException failure = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
+ assertTrue(
+ Set.of(KeyringException.Code.KEYRING_FORMAT_INVALID, KeyringException.Code.KEYRING_LIMIT_EXCEEDED,
+ KeyringException.Code.KEYRING_UNLOCK_FAILED).contains(failure.code()));
assertEquals(failure.code().name(), failure.getMessage());
assertNull(failure.getCause());
}
}
- private Path copyWithMutation(Path source, byte[] image, String name,
- Mutation mutation) throws Exception {
+ private Path copyWithMutation(Path source, byte[] image, String name, Mutation mutation) throws Exception {
byte[] copy = image.clone();
try {
mutation.apply(copy);
@@ -765,8 +721,7 @@ class KeyringCryptographicFormatTest {
}
private static List openAliases(Path path) throws Exception {
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
return store.aliases();
}
}
@@ -784,8 +739,7 @@ class KeyringCryptographicFormatTest {
int length = buffer.getInt();
int ciphertext = buffer.position();
buffer.position(ciphertext + length);
- entries.add(new WireEntry(entryId, nonce, ciphertext,
- buffer.position()));
+ entries.add(new WireEntry(entryId, nonce, ciphertext, buffer.position()));
}
int manifestNonce = buffer.position();
buffer.position(manifestNonce + KeyringStore.NONCE_BYTES);
@@ -812,8 +766,7 @@ class KeyringCryptographicFormatTest {
private static byte[] duplicateFirstEntry(byte[] image, ImageLayout layout) {
WireEntry first = layout.entries.get(0);
WireEntry second = layout.entries.get(1);
- return replaceEntry(image, second,
- slice(image, first.entryIdOffset, first.endOffset));
+ return replaceEntry(image, second, slice(image, first.entryIdOffset, first.endOffset));
}
private static byte[] deleteFirstEntry(byte[] image, ImageLayout layout) {
@@ -833,8 +786,7 @@ class KeyringCryptographicFormatTest {
System.arraycopy(image, 0, result, 0, layout.manifestNonceOffset);
putInt(result, ENTRY_COUNT_OFFSET, 3);
System.arraycopy(encoded, 0, result, layout.manifestNonceOffset, encoded.length);
- System.arraycopy(image, layout.manifestNonceOffset, result,
- layout.manifestNonceOffset + encoded.length,
+ System.arraycopy(image, layout.manifestNonceOffset, result, layout.manifestNonceOffset + encoded.length,
image.length - layout.manifestNonceOffset);
wipe(encoded);
return result;
@@ -845,14 +797,14 @@ class KeyringCryptographicFormatTest {
byte[] result = new byte[image.length - currentLength + replacement.length];
System.arraycopy(image, 0, result, 0, target.entryIdOffset);
System.arraycopy(replacement, 0, result, target.entryIdOffset, replacement.length);
- System.arraycopy(image, target.endOffset, result,
- target.entryIdOffset + replacement.length, image.length - target.endOffset);
+ System.arraycopy(image, target.endOffset, result, target.entryIdOffset + replacement.length,
+ image.length - target.endOffset);
wipe(replacement);
return result;
}
- private static byte[] entryPlaintext(int version, String alias, String algorithm,
- int kind, int encoding, int hmac, byte[] key, boolean trailing) throws Exception {
+ private static byte[] entryPlaintext(int version, String alias, String algorithm, int kind, int encoding, int hmac,
+ byte[] key, boolean trailing) throws Exception {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (DataOutputStream out = new DataOutputStream(bytes)) {
out.writeInt(version);
@@ -870,8 +822,7 @@ class KeyringCryptographicFormatTest {
return bytes.toByteArray();
}
- private static byte[] lengthOnlyEntry(int aliasLength, String algorithm)
- throws Exception {
+ private static byte[] lengthOnlyEntry(int aliasLength, String algorithm) throws Exception {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
try (DataOutputStream out = new DataOutputStream(bytes)) {
out.writeInt(1);
@@ -905,10 +856,8 @@ class KeyringCryptographicFormatTest {
return bytes.toByteArray();
}
- private static byte[] emptyManifest(int version, long highWater, int count,
- boolean trailing) {
- ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES * 3 + Long.BYTES
- + (trailing ? 1 : 0));
+ private static byte[] emptyManifest(int version, long highWater, int count, boolean trailing) {
+ ByteBuffer buffer = ByteBuffer.allocate(Integer.BYTES * 3 + Long.BYTES + (trailing ? 1 : 0));
buffer.putInt(version).putInt(0x010203).putLong(highWater).putInt(count);
if (trailing) {
buffer.put((byte) 0);
@@ -917,8 +866,7 @@ class KeyringCryptographicFormatTest {
}
private static void invokeDecodeEntry(byte[] input) throws Exception {
- Method method = KeyringStore.class.getDeclaredMethod("decodeEntryPlaintext",
- byte[].class);
+ Method method = KeyringStore.class.getDeclaredMethod("decodeEntryPlaintext", byte[].class);
method.setAccessible(true);
method.invoke(null, (Object) input);
}
@@ -933,16 +881,13 @@ class KeyringCryptographicFormatTest {
}
}
- private static void invokeDecodeManifest(byte[] input, int expectedCount)
- throws Exception {
- Method method = KeyringStore.class.getDeclaredMethod("decodeManifest",
- byte[].class, int.class);
+ private static void invokeDecodeManifest(byte[] input, int expectedCount) throws Exception {
+ Method method = KeyringStore.class.getDeclaredMethod("decodeManifest", byte[].class, int.class);
method.setAccessible(true);
method.invoke(null, input, expectedCount);
}
- private static void assertDecodeManifestRejected(byte[] input, int expectedCount)
- throws Exception {
+ private static void assertDecodeManifestRejected(byte[] input, int expectedCount) throws Exception {
try {
InvocationTargetException failure = assertThrows(InvocationTargetException.class,
() -> invokeDecodeManifest(input, expectedCount));
@@ -971,8 +916,7 @@ class KeyringCryptographicFormatTest {
}
private static int indexOf(byte[] haystack, byte[] needle) {
- outer:
- for (int index = 0; index <= haystack.length - needle.length; index++) {
+ outer: for (int index = 0; index <= haystack.length - needle.length; index++) {
for (int offset = 0; offset < needle.length; offset++) {
if (haystack[index + offset] != needle[offset]) {
continue outer;
@@ -992,8 +936,7 @@ class KeyringCryptographicFormatTest {
}
private static void ownerOnly(Path path) throws Exception {
- Files.setPosixFilePermissions(path, Set.of(
- java.nio.file.attribute.PosixFilePermission.OWNER_READ,
+ Files.setPosixFilePermissions(path, Set.of(java.nio.file.attribute.PosixFilePermission.OWNER_READ,
java.nio.file.attribute.PosixFilePermission.OWNER_WRITE));
}
@@ -1039,18 +982,15 @@ class KeyringCryptographicFormatTest {
byte[] apply(byte[] value);
}
- private record WireEntry(int entryIdOffset, int nonceOffset,
- int ciphertextOffset, int endOffset) {
+ private record WireEntry(int entryIdOffset, int nonceOffset, int ciphertextOffset, int endOffset) {
}
- private record ImageLayout(List entries, int manifestNonceOffset,
- int manifestCipherOffset) {
+ private record ImageLayout(List entries, int manifestNonceOffset, int manifestCipherOffset) {
}
- private record ManifestDescriptor(int startOffset, int endOffset,
- int entryIdOffset, int positionOffset, int aliasOffset, int aliasLength,
- int algorithmOffset, int kindOffset, int encodingOffset, int hmacOffset, int nonceOffset,
- int ciphertextLengthOffset, int digestOffset) {
+ private record ManifestDescriptor(int startOffset, int endOffset, int entryIdOffset, int positionOffset,
+ int aliasOffset, int aliasLength, int algorithmOffset, int kindOffset, int encodingOffset, int hmacOffset,
+ int nonceOffset, int ciphertextLengthOffset, int digestOffset) {
}
private record StoreFixture(Path path, byte[] masterKey) {
diff --git a/lib/src/test/java/zeroecho/core/storage/KeyringFilesystemSecurityTest.java b/lib/src/test/java/zeroecho/core/storage/KeyringFilesystemSecurityTest.java
index 9720d62..e3b1805 100644
--- a/lib/src/test/java/zeroecho/core/storage/KeyringFilesystemSecurityTest.java
+++ b/lib/src/test/java/zeroecho/core/storage/KeyringFilesystemSecurityTest.java
@@ -54,12 +54,9 @@ class KeyringFilesystemSecurityTest {
private static final char[] PASSWORD = { 'f', 'i', 'l', 'e', 's', 'y', 's' };
private static final byte[] CHILD_PASSWORD = { 'f', 'i', 'l', 'e', 's', 'y', 's' };
private static final long TIMEOUT_SECONDS = 15L;
- private static final Set DIRECTORY_PERMISSIONS = Set.of(
- PosixFilePermission.OWNER_READ,
- PosixFilePermission.OWNER_WRITE,
- PosixFilePermission.OWNER_EXECUTE);
- private static final Set FILE_PERMISSIONS = Set.of(
- PosixFilePermission.OWNER_READ,
+ private static final Set DIRECTORY_PERMISSIONS = Set.of(PosixFilePermission.OWNER_READ,
+ PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_EXECUTE);
+ private static final Set FILE_PERMISSIONS = Set.of(PosixFilePermission.OWNER_READ,
PosixFilePermission.OWNER_WRITE);
@TempDir
@@ -80,20 +77,15 @@ class KeyringFilesystemSecurityTest {
}
assertOpenSucceeds(path);
- for (PosixFilePermission unsafe : List.of(
- PosixFilePermission.GROUP_READ,
- PosixFilePermission.GROUP_WRITE,
- PosixFilePermission.OTHERS_READ,
- PosixFilePermission.OTHERS_WRITE)) {
+ for (PosixFilePermission unsafe : List.of(PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_WRITE,
+ PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_WRITE)) {
Path unsafeParent = temporaryDirectory.resolve("parent-" + unsafe.name());
Path unsafeStore = unsafeParent.resolve("keys.zek");
createPopulated(unsafeStore, unsafe.ordinal() + 10);
- Set permissions = new java.util.HashSet<>(
- DIRECTORY_PERMISSIONS);
+ Set permissions = new java.util.HashSet<>(DIRECTORY_PERMISSIONS);
permissions.add(unsafe);
Files.setPosixFilePermissions(unsafeParent, permissions);
- assertRedactedFailure(unsafeStore,
- KeyringException.Code.KEYRING_FILESYSTEM_UNSUPPORTED);
+ assertRedactedFailure(unsafeStore, KeyringException.Code.KEYRING_FILESYSTEM_UNSUPPORTED);
Files.setPosixFilePermissions(unsafeParent, DIRECTORY_PERMISSIONS);
}
@@ -119,8 +111,8 @@ class KeyringFilesystemSecurityTest {
Path path = temporaryDirectory.resolve("owner-mismatch.zek");
createPopulated(path, 31);
- Method validator = KeyringStore.class.getDeclaredMethod("validateExistingFile",
- Path.class, UserPrincipal.class);
+ Method validator = KeyringStore.class.getDeclaredMethod("validateExistingFile", Path.class,
+ UserPrincipal.class);
validator.setAccessible(true);
UserPrincipal other = () -> "controlled-other-owner";
InvocationTargetException failure = assertThrows(InvocationTargetException.class,
@@ -151,15 +143,14 @@ class KeyringFilesystemSecurityTest {
Path path = temporaryDirectory.resolve("shared.zek");
byte[] material = material((byte) 0x41);
try (KeyringPassword password = password();
- KeyringStore first = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom(41));
+ KeyringStore first = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom(41));
KeyringPassword secondPassword = password()) {
first.putSecret("shared", "AES", new SecretKeySpec(material, "AES"));
KeyringException contention = assertThrows(KeyringException.class,
() -> KeyringStore.open(path, secondPassword));
assertEquals(KeyringException.Code.KEYRING_ALREADY_OPEN, contention.code());
- assertEquals(KeyringException.Code.KEYRING_ALREADY_OPEN.name(),
- contention.getMessage());
+ assertEquals(KeyringException.Code.KEYRING_ALREADY_OPEN.name(), contention.getMessage());
assertNull(contention.getCause());
assertArrayEquals(material, first.getSecret("shared").getEncoded());
} finally {
@@ -216,8 +207,8 @@ class KeyringFilesystemSecurityTest {
byte[] first = material((byte) 0x12);
byte[] second = material((byte) 0x34);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom(71))) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom(71))) {
store.putSecret("one", "AES", new SecretKeySpec(first, "AES"));
store.putSecret("two", "AES", new SecretKeySpec(second, "AES"));
runConcurrentReaders(store, first, second);
@@ -273,8 +264,7 @@ class KeyringFilesystemSecurityTest {
BlockingRandom random = new BlockingRandom(81);
KeyringStore store;
try (KeyringPassword password = password()) {
- store = KeyringStore.create(path, password,
- KeyringProtection.standard(), random);
+ store = KeyringStore.create(path, password, KeyringProtection.standard(), random);
}
byte[] material = material((byte) 0x5c);
AtomicReference putFailure = new AtomicReference<>();
@@ -282,8 +272,7 @@ class KeyringFilesystemSecurityTest {
random.arm();
Thread mutation = new Thread(() -> {
try {
- store.putSecret("admitted", "AES",
- new SecretKeySpec(material, "AES"));
+ store.putSecret("admitted", "AES", new SecretKeySpec(material, "AES"));
} catch (Throwable throwable) {
putFailure.set(throwable);
}
@@ -305,11 +294,8 @@ class KeyringFilesystemSecurityTest {
assertNull(putFailure.get());
assertNull(closeFailure.get());
assertTrue(store.isDestroyed());
- assertThrows(KeyringException.class,
- () -> store.putSecret("late", "AES",
- new SecretKeySpec(material, "AES")));
- try (KeyringPassword password = password();
- KeyringStore reopened = KeyringStore.open(path, password)) {
+ assertThrows(KeyringException.class, () -> store.putSecret("late", "AES", new SecretKeySpec(material, "AES")));
+ try (KeyringPassword password = password(); KeyringStore reopened = KeyringStore.open(path, password)) {
assertArrayEquals(material, reopened.getSecret("admitted").getEncoded());
} finally {
wipe(material);
@@ -367,8 +353,7 @@ class KeyringFilesystemSecurityTest {
createPopulated(path, 111);
Path link = temporaryDirectory.resolve("linked-parent");
Files.createSymbolicLink(link, real.getFileName());
- assertRedactedFailure(link.resolve("keys.zek"),
- KeyringException.Code.KEYRING_FILESYSTEM_UNSUPPORTED);
+ assertRedactedFailure(link.resolve("keys.zek"), KeyringException.Code.KEYRING_FILESYSTEM_UNSUPPORTED);
}
private void assertArtifactHardLinkRejected(Artifact artifact) throws Exception {
@@ -394,8 +379,7 @@ class KeyringFilesystemSecurityTest {
Path malicious = temporaryDirectory.resolve(".temp-race.zek.precreated.tmp");
Files.createSymbolicLink(malicious, target.getFileName());
byte[] material = material((byte) 0x63);
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
store.putSecret("safe", "AES", new SecretKeySpec(material, "AES"));
assertArrayEquals(before, Files.readAllBytes(target));
} finally {
@@ -404,8 +388,7 @@ class KeyringFilesystemSecurityTest {
}
}
- private void runConcurrentReaders(KeyringStore store, byte[] first, byte[] second)
- throws Exception {
+ private void runConcurrentReaders(KeyringStore store, byte[] first, byte[] second) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(8);
CountDownLatch start = new CountDownLatch(1);
List> results = new ArrayList<>();
@@ -415,8 +398,7 @@ class KeyringFilesystemSecurityTest {
results.add(executor.submit(() -> {
start.await();
if (selected == 7) {
- assertThrows(IllegalArgumentException.class,
- () -> store.getSecret("missing"));
+ assertThrows(IllegalArgumentException.class, () -> store.getSecret("missing"));
return true;
}
String alias = selected % 2 == 0 ? "one" : "two";
@@ -472,8 +454,8 @@ class KeyringFilesystemSecurityTest {
private void createPopulated(Path path, int seed) throws Exception {
byte[] material = material((byte) seed);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom(seed))) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom(seed))) {
store.putSecret("child", "AES", new SecretKeySpec(material, "AES"));
} finally {
wipe(material);
@@ -481,8 +463,7 @@ class KeyringFilesystemSecurityTest {
}
private static void assertOpenSucceeds(Path path) throws Exception {
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
assertFalse(store.isDestroyed());
store.aliases();
}
@@ -490,19 +471,16 @@ class KeyringFilesystemSecurityTest {
private static void assertAlreadyOpen(Path path) throws Exception {
try (KeyringPassword password = password()) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
+ KeyringException failure = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
assertEquals(KeyringException.Code.KEYRING_ALREADY_OPEN, failure.code());
assertEquals(failure.code().name(), failure.getMessage());
assertNull(failure.getCause());
}
}
- private static void assertRedactedFailure(Path path, KeyringException.Code code)
- throws Exception {
+ private static void assertRedactedFailure(Path path, KeyringException.Code code) throws Exception {
try (KeyringPassword password = password()) {
- KeyringException failure = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
+ KeyringException failure = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
assertEquals(code, failure.code());
assertEquals(code.name(), failure.getMessage());
assertNull(failure.getCause());
@@ -511,8 +489,8 @@ class KeyringFilesystemSecurityTest {
}
}
- private static Thread closeThread(KeyringStore store, CountDownLatch started,
- AtomicReference failure, String name) {
+ private static Thread closeThread(KeyringStore store, CountDownLatch started, AtomicReference failure,
+ String name) {
return new Thread(() -> {
started.countDown();
try {
@@ -523,8 +501,7 @@ class KeyringFilesystemSecurityTest {
}, name);
}
- private static void awaitQueued(ReentrantReadWriteLock lock, int minimum)
- throws Exception {
+ private static void awaitQueued(ReentrantReadWriteLock lock, int minimum) throws Exception {
long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(TIMEOUT_SECONDS);
while (lock.getQueueLength() < minimum && System.nanoTime() < deadline) {
Thread.onSpinWait();
@@ -674,19 +651,17 @@ class KeyringFilesystemSecurityTest {
private ChildOwner(Process process) {
this.process = process;
- output = new BufferedReader(new InputStreamReader(process.getInputStream(),
- StandardCharsets.UTF_8));
+ output = new BufferedReader(new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8));
input = process.getOutputStream();
}
private static ChildOwner start(Path path) throws Exception {
- String executable = System.getProperty("os.name", "")
- .toLowerCase(java.util.Locale.ROOT).contains("win")
- ? "java.exe" : "java";
+ String executable = System.getProperty("os.name", "").toLowerCase(java.util.Locale.ROOT).contains("win")
+ ? "java.exe"
+ : "java";
Path java = Path.of(System.getProperty("java.home"), "bin", executable);
Process process = new ProcessBuilder(java.toString(), "-cp", childClasspath(),
- KeyringStoreLockProcess.class.getName(), path.toString())
- .redirectErrorStream(true).start();
+ KeyringStoreLockProcess.class.getName(), path.toString()).redirectErrorStream(true).start();
return new ChildOwner(process);
}
@@ -777,8 +752,7 @@ class KeyringFilesystemSecurityTest {
}
private static String codeSource(Class> type) throws Exception {
- return Path.of(type.getProtectionDomain().getCodeSource().getLocation().toURI())
- .toString();
+ return Path.of(type.getProtectionDomain().getCodeSource().getLocation().toURI()).toString();
}
}
@@ -802,8 +776,8 @@ final class KeyringStoreLockProcess {
}
try (KeyringPassword password = new KeyringPassword(passwordChars);
KeyringStore store = KeyringStore.open(Path.of(args[0]), password);
- BufferedReader control = new BufferedReader(new InputStreamReader(
- System.in, StandardCharsets.US_ASCII))) {
+ BufferedReader control = new BufferedReader(
+ new InputStreamReader(System.in, StandardCharsets.US_ASCII))) {
Arrays.fill(passwordChars, '\0');
Arrays.fill(passwordBytes, (byte) 0);
System.out.println("KEYRING_OPEN");
diff --git a/lib/src/test/java/zeroecho/core/storage/KeyringImportRegistryTest.java b/lib/src/test/java/zeroecho/core/storage/KeyringImportRegistryTest.java
index 4a477e2..c068e44 100644
--- a/lib/src/test/java/zeroecho/core/storage/KeyringImportRegistryTest.java
+++ b/lib/src/test/java/zeroecho/core/storage/KeyringImportRegistryTest.java
@@ -36,34 +36,31 @@ class KeyringImportRegistryTest {
@Test
void persistentImporterMatrixIsClosedUniqueAndExecutable() throws Exception {
start("persistentImporterMatrixIsClosedUniqueAndExecutable");
- List mappings =
- KeyringImportRegistry.mappings();
+ List mappings = KeyringImportRegistry.mappings();
assertEquals(19, count(mappings, KeyringStore.Kind.PUBLIC_KEY));
assertEquals(19, count(mappings, KeyringStore.Kind.PRIVATE_KEY));
assertEquals(6, count(mappings, KeyringStore.Kind.SECRET_KEY));
assertEquals(mappings.size(), mappings.stream().distinct().count());
for (KeyringImportRegistry.PersistentMapping mapping : mappings) {
- KeyringImportRegistry.validateMapping(mapping.algorithmId(), mapping.kind(),
- mapping.encoding(), mapping.hmacVariant());
+ KeyringImportRegistry.validateMapping(mapping.algorithmId(), mapping.kind(), mapping.encoding(),
+ mapping.hmacVariant());
}
roundTripAsymmetricMappings(mappings);
roundTripSecretMappings(mappings);
assertEquals(KeyringException.Code.KEYRING_IMPORT_MAPPING_INVALID,
assertThrows(KeyringException.class,
- () -> KeyringImportRegistry.validateMapping("RSA",
- KeyringStore.Kind.SECRET_KEY, KeyringStore.Encoding.RAW,
- KeyringImportRegistry.HmacVariant.NONE)).code());
+ () -> KeyringImportRegistry.validateMapping("RSA", KeyringStore.Kind.SECRET_KEY,
+ KeyringStore.Encoding.RAW, KeyringImportRegistry.HmacVariant.NONE))
+ .code());
System.out.println("...mapping-count=" + mappings.size());
ok();
}
@Test
- void alternateProviderStandardEncodingUsesCanonicalImporter(
- @TempDir Path temporaryDirectory) throws Exception {
+ void alternateProviderStandardEncodingUsesCanonicalImporter(@TempDir Path temporaryDirectory) throws Exception {
start("alternateProviderStandardEncodingUsesCanonicalImporter");
- java.security.KeyPairGenerator generator =
- java.security.KeyPairGenerator.getInstance("RSA", "BC");
+ java.security.KeyPairGenerator generator = java.security.KeyPairGenerator.getInstance("RSA", "BC");
generator.initialize(2048);
KeyPair pair = generator.generateKeyPair();
byte[] encoded = pair.getPublic().getEncoded();
@@ -72,20 +69,17 @@ class KeyringImportRegistryTest {
byte[] importedEncoding = null;
byte[] reopenedEncoding = null;
try {
- imported = KeyringImportRegistry.importKey("RSA",
- KeyringStore.Kind.PUBLIC_KEY, KeyringStore.Encoding.X509,
+ imported = KeyringImportRegistry.importKey("RSA", KeyringStore.Kind.PUBLIC_KEY, KeyringStore.Encoding.X509,
KeyringImportRegistry.HmacVariant.NONE, encoded);
importedEncoding = imported.getEncoded();
assertArrayEquals(encoded, importedEncoding);
assertEquals("RSA", imported.getAlgorithm());
assertNotEquals(pair.getPublic().getClass(), imported.getClass());
Path path = temporaryDirectory.resolve("alternate-provider.zek");
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.create(path, password)) {
store.putPublic("alternate", "RSA", pair.getPublic());
}
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.open(path, password)) {
reopened = store.getPublic("alternate");
reopenedEncoding = reopened.getEncoded();
assertArrayEquals(encoded, reopenedEncoding);
@@ -100,28 +94,23 @@ class KeyringImportRegistryTest {
ok();
}
- private static long count(List mappings,
- KeyringStore.Kind kind) {
+ private static long count(List mappings, KeyringStore.Kind kind) {
return mappings.stream().filter(mapping -> mapping.kind() == kind).count();
}
- private static void roundTripAsymmetricMappings(
- List mappings) throws Exception {
- List algorithms = mappings.stream()
- .filter(mapping -> mapping.kind() == KeyringStore.Kind.PUBLIC_KEY)
- .map(KeyringImportRegistry.PersistentMapping::algorithmId)
- .toList();
+ private static void roundTripAsymmetricMappings(List mappings)
+ throws Exception {
+ List algorithms = mappings.stream().filter(mapping -> mapping.kind() == KeyringStore.Kind.PUBLIC_KEY)
+ .map(KeyringImportRegistry.PersistentMapping::algorithmId).toList();
for (String algorithmId : algorithms) {
KeyPair pair = generatePair(algorithmId);
- roundTrip(mapping(mappings, algorithmId, KeyringStore.Kind.PUBLIC_KEY),
- pair.getPublic());
- roundTrip(mapping(mappings, algorithmId, KeyringStore.Kind.PRIVATE_KEY),
- pair.getPrivate());
+ roundTrip(mapping(mappings, algorithmId, KeyringStore.Kind.PUBLIC_KEY), pair.getPublic());
+ roundTrip(mapping(mappings, algorithmId, KeyringStore.Kind.PRIVATE_KEY), pair.getPrivate());
}
}
- private static void roundTripSecretMappings(
- List mappings) throws Exception {
+ private static void roundTripSecretMappings(List mappings)
+ throws Exception {
for (KeyringImportRegistry.PersistentMapping mapping : mappings) {
if (mapping.kind() != KeyringStore.Kind.SECRET_KEY) {
continue;
@@ -147,33 +136,26 @@ class KeyringImportRegistryTest {
CryptoAlgorithm algorithm = CryptoAlgorithms.require(algorithmId);
KeyOperationInfo generation = algorithm.keyOperations().stream()
.filter(info -> info.operation() == KeyOperation.ASYMMETRIC_KEY_PAIR_GENERATE)
- .filter(info -> info.defaultSpec() != null)
- .findFirst()
- .orElseThrow(() -> new AssertionError(
- "No default key-pair generation mapping for " + algorithmId));
- AsymmetricKeyPairGenerator generator =
- algorithm.asymmetricKeyPairGenerator(generation.specType());
+ .filter(info -> info.defaultSpec() != null).findFirst()
+ .orElseThrow(() -> new AssertionError("No default key-pair generation mapping for " + algorithmId));
+ AsymmetricKeyPairGenerator generator = algorithm.asymmetricKeyPairGenerator(generation.specType());
return generator.generateKeyPair((AlgorithmKeySpec) generation.defaultSpec());
}
private static KeyringImportRegistry.PersistentMapping mapping(
- List mappings, String algorithmId,
- KeyringStore.Kind kind) {
+ List mappings, String algorithmId, KeyringStore.Kind kind) {
return mappings.stream()
- .filter(candidate -> candidate.algorithmId().equals(algorithmId)
- && candidate.kind() == kind)
- .findFirst()
- .orElseThrow();
+ .filter(candidate -> candidate.algorithmId().equals(algorithmId) && candidate.kind() == kind)
+ .findFirst().orElseThrow();
}
- private static void roundTrip(KeyringImportRegistry.PersistentMapping mapping,
- Key source) throws Exception {
+ private static void roundTrip(KeyringImportRegistry.PersistentMapping mapping, Key source) throws Exception {
byte[] encoded = source.getEncoded();
Key imported = null;
byte[] reconstructed = null;
try {
- imported = KeyringImportRegistry.importKey(mapping.algorithmId(), mapping.kind(),
- mapping.encoding(), mapping.hmacVariant(), encoded);
+ imported = KeyringImportRegistry.importKey(mapping.algorithmId(), mapping.kind(), mapping.encoding(),
+ mapping.hmacVariant(), encoded);
reconstructed = imported.getEncoded();
assertArrayEquals(encoded, reconstructed);
} finally {
diff --git a/lib/src/test/java/zeroecho/core/storage/KeyringNonceReservationTest.java b/lib/src/test/java/zeroecho/core/storage/KeyringNonceReservationTest.java
index 9da5ed4..0756860 100644
--- a/lib/src/test/java/zeroecho/core/storage/KeyringNonceReservationTest.java
+++ b/lib/src/test/java/zeroecho/core/storage/KeyringNonceReservationTest.java
@@ -27,8 +27,7 @@ import org.junit.jupiter.api.io.TempDir;
class KeyringNonceReservationTest {
private static final int MAGIC_BYTES = 8;
private static final int VERSION_OFFSET = MAGIC_BYTES;
- private static final int HIGH_WATER_OFFSET =
- MAGIC_BYTES + Integer.BYTES + KeyringStore.UUID_BYTES + Integer.BYTES;
+ private static final int HIGH_WATER_OFFSET = MAGIC_BYTES + Integer.BYTES + KeyringStore.UUID_BYTES + Integer.BYTES;
private static final int TAG_BYTES = 32;
private static final int CURRENT_SIDECAR_VERSION = 2;
private static final char[] PASSWORD = { 'n', 'o', 'n', 'c', 'e' };
@@ -47,8 +46,7 @@ class KeyringNonceReservationTest {
for (int index = 0; index < storeId.length; index++) {
storeId[index] = (byte) (0xa0 + index);
}
- byte[] expected = HexFormat.of().parseHex(
- "54e0e054749745a3ef5e2cc5a5c16bafed6f39df9daa4ff412bac74d56bd27b9");
+ byte[] expected = HexFormat.of().parseHex("54e0e054749745a3ef5e2cc5a5c16bafed6f39df9daa4ff412bac74d56bd27b9");
byte[] first = null;
byte[] second = null;
byte[] changedMaster = null;
@@ -88,13 +86,12 @@ class KeyringNonceReservationTest {
byte[] retainedMacKey;
byte[] macKeyCopy;
try (KeyringPassword password = password()) {
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom());
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom());
retainedMacKey = field(store, "nonceReservationMacKey");
macKeyCopy = retainedMacKey.clone();
assertEquals(CURRENT_SIDECAR_VERSION,
- ByteBuffer.wrap(Files.readAllBytes(sidecar(path)),
- VERSION_OFFSET, Integer.BYTES).getInt());
+ ByteBuffer.wrap(Files.readAllBytes(sidecar(path)), VERSION_OFFSET, Integer.BYTES).getInt());
store.close();
store.close();
assertTrue(allZero(retainedMacKey));
@@ -109,8 +106,7 @@ class KeyringNonceReservationTest {
wipe(reservation);
wipe(macKeyCopy);
}
- try (KeyringPassword password = password();
- KeyringStore reopened = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore reopened = KeyringStore.open(path, password)) {
assertTrue(reopened.aliases().isEmpty());
}
ok();
@@ -153,14 +149,13 @@ class KeyringNonceReservationTest {
Arrays.fill(material, (byte) 0x4a);
try {
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom())) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom())) {
assertEquals(1L, longField(store, "nonceHighWater"));
Files.move(path, saved);
Files.createDirectory(path);
assertThrows(IOException.class,
- () -> store.putSecret("failed", "AES",
- new SecretKeySpec(material, "AES")));
+ () -> store.putSecret("failed", "AES", new SecretKeySpec(material, "AES")));
assertEquals(3L, sidecarHighWater(sidecar(path)));
assertEquals(3L, longField(store, "nonceHighWater"));
Files.delete(path);
@@ -168,17 +163,15 @@ class KeyringNonceReservationTest {
}
try (KeyringPassword password = password();
- KeyringStore reopened = KeyringStore.open(path, password,
- KeyringProtection.standard(), deterministicRandom(51))) {
+ KeyringStore reopened = KeyringStore.open(path, password, KeyringProtection.standard(),
+ deterministicRandom(51))) {
assertEquals(3L, longField(reopened, "nonceHighWater"));
assertTrue(reopened.aliases().isEmpty());
- reopened.putSecret("accepted", "AES",
- new SecretKeySpec(material, "AES"));
+ reopened.putSecret("accepted", "AES", new SecretKeySpec(material, "AES"));
assertEquals(5L, longField(reopened, "nonceHighWater"));
assertEquals(5L, sidecarHighWater(sidecar(path)));
}
- try (KeyringPassword password = password();
- KeyringStore reopened = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore reopened = KeyringStore.open(path, password)) {
assertEquals(5L, longField(reopened, "nonceHighWater"));
assertArrayEquals(material, reopened.getSecret("accepted").getEncoded());
}
@@ -198,24 +191,21 @@ class KeyringNonceReservationTest {
Arrays.fill(material, (byte) 0x35);
RecordingRandom random = new RecordingRandom(1);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), random)) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(), random)) {
byte[] mainBefore = Files.readAllBytes(path);
try {
assertEquals(List.of(32, 32, 16, 11, 3), random.requests());
Files.move(reservation, saved);
Files.createDirectory(reservation);
assertThrows(IOException.class,
- () -> store.putSecret("failed", "AES",
- new SecretKeySpec(material, "AES")));
+ () -> store.putSecret("failed", "AES", new SecretKeySpec(material, "AES")));
assertEquals(1L, longField(store, "nonceHighWater"));
assertArrayEquals(mainBefore, Files.readAllBytes(path));
assertEquals(List.of(32, 32, 16, 11, 3, 16), random.requests());
Files.delete(reservation);
Files.move(saved, reservation);
- store.putSecret("accepted", "AES",
- new SecretKeySpec(material, "AES"));
+ store.putSecret("accepted", "AES", new SecretKeySpec(material, "AES"));
assertEquals(3L, longField(store, "nonceHighWater"));
assertEquals(List.of(32, 32, 16, 11, 3, 16, 16), random.requests());
} finally {
@@ -237,8 +227,7 @@ class KeyringNonceReservationTest {
Arrays.fill(second, (byte) 0x22);
RecordingRandom random = new RecordingRandom(7);
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), random)) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(), random)) {
assertEquals(1L, longField(store, "nonceHighWater"));
assertEquals(List.of(32, 32, 16, 11, 3), random.requests());
store.putSecret("one", "AES", new SecretKeySpec(first, "AES"));
@@ -261,8 +250,8 @@ class KeyringNonceReservationTest {
byte[] image;
byte[] master;
try (KeyringPassword password = password()) {
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom());
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom());
image = Files.readAllBytes(sidecar(path));
master = field(store, "masterKey").clone();
store.close();
@@ -304,14 +293,13 @@ class KeyringNonceReservationTest {
}
}
- private Path sidecarWithVersion(String file, int version, boolean useMasterKey)
- throws Exception {
+ private Path sidecarWithVersion(String file, int version, boolean useMasterKey) throws Exception {
Path path = temporaryDirectory.resolve(file);
byte[] image;
byte[] key;
try (KeyringPassword password = password()) {
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom());
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom());
image = Files.readAllBytes(sidecar(path));
key = field(store, useMasterKey ? "masterKey" : "nonceReservationMacKey").clone();
store.close();
@@ -343,8 +331,7 @@ class KeyringNonceReservationTest {
private Path sidecarWithTrailingByte(String file) throws Exception {
Path path = createAndClose(file);
- Files.write(sidecar(path), new byte[] { 0 },
- java.nio.file.StandardOpenOption.APPEND);
+ Files.write(sidecar(path), new byte[] { 0 }, java.nio.file.StandardOpenOption.APPEND);
return path;
}
@@ -356,11 +343,9 @@ class KeyringNonceReservationTest {
byte[] mainBefore = Files.readAllBytes(path);
byte[] sidecarBefore = Files.readAllBytes(sidecar(path));
try (KeyringPassword password = password()) {
- KeyringException exception = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
+ KeyringException exception = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID, exception.code());
- assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID.name(),
- exception.getMessage());
+ assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID.name(), exception.getMessage());
assertArrayEquals(mainBefore, Files.readAllBytes(path));
assertArrayEquals(sidecarBefore, Files.readAllBytes(sidecar(path)));
} finally {
@@ -376,8 +361,8 @@ class KeyringNonceReservationTest {
private Path createAndClose(String file, int randomSeed) throws Exception {
Path path = temporaryDirectory.resolve(file);
try (KeyringPassword password = password();
- KeyringStore ignored = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom(randomSeed))) {
+ KeyringStore ignored = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom(randomSeed))) {
// Creation writes the initial durable reservation.
}
return path;
@@ -454,8 +439,7 @@ class KeyringNonceReservationTest {
}
private static int indexOf(byte[] haystack, byte[] needle) {
- outer:
- for (int index = 0; index <= haystack.length - needle.length; index++) {
+ outer: for (int index = 0; index <= haystack.length - needle.length; index++) {
for (int offset = 0; offset < needle.length; offset++) {
if (haystack[index + offset] != needle[offset]) {
continue outer;
diff --git a/lib/src/test/java/zeroecho/core/storage/KeyringStoreTest.java b/lib/src/test/java/zeroecho/core/storage/KeyringStoreTest.java
index c3f947f..c35be30 100644
--- a/lib/src/test/java/zeroecho/core/storage/KeyringStoreTest.java
+++ b/lib/src/test/java/zeroecho/core/storage/KeyringStoreTest.java
@@ -39,8 +39,8 @@ class KeyringStoreTest {
KeyPair pair = generator.generateKeyPair();
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom())) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom())) {
store.putPublic("rsa", "RSA", pair.getPublic());
store.putPrivate("rsa", "RSA", pair.getPrivate());
store.putSecret("aes", "AES", aes);
@@ -64,13 +64,11 @@ class KeyringStoreTest {
void wrongPasswordAndCorruptionFailUniformly() throws Exception {
start("wrongPasswordAndCorruptionFailUniformly");
Path path = temporaryDirectory.resolve("wrong.zek");
- try (KeyringPassword password = password();
- KeyringStore ignored = KeyringStore.create(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore ignored = KeyringStore.create(path, password)) {
// empty current-format store
}
try (KeyringPassword wrong = new KeyringPassword(new char[] { 'w', 'r', 'o', 'n', 'g' })) {
- KeyringException exception = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, wrong));
+ KeyringException exception = assertThrows(KeyringException.class, () -> KeyringStore.open(path, wrong));
assertEquals(KeyringException.Code.KEYRING_UNLOCK_FAILED, exception.code());
}
byte[] bytes = Files.readAllBytes(path);
@@ -78,8 +76,7 @@ class KeyringStoreTest {
Files.write(path, bytes);
Arrays.fill(bytes, (byte) 0);
try (KeyringPassword password = password()) {
- KeyringException exception = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
+ KeyringException exception = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID, exception.code());
}
ok();
@@ -90,13 +87,11 @@ class KeyringStoreTest {
start("plaintextV1AndDuplicateOwnerAreRejected");
Path old = temporaryDirectory.resolve("old.txt");
Files.writeString(old, "# KeyringStore v1\n", StandardCharsets.UTF_8);
- Files.setPosixFilePermissions(old, java.util.Set.of(
- java.nio.file.attribute.PosixFilePermission.OWNER_READ,
+ Files.setPosixFilePermissions(old, java.util.Set.of(java.nio.file.attribute.PosixFilePermission.OWNER_READ,
java.nio.file.attribute.PosixFilePermission.OWNER_WRITE));
try (KeyringPassword password = password()) {
assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID,
- assertThrows(KeyringException.class,
- () -> KeyringStore.open(old, password)).code());
+ assertThrows(KeyringException.class, () -> KeyringStore.open(old, password)).code());
}
Path path = temporaryDirectory.resolve("owned.zek");
@@ -104,12 +99,10 @@ class KeyringStoreTest {
KeyringStore first = KeyringStore.create(path, password);
KeyringPassword secondPassword = password()) {
assertEquals(KeyringException.Code.KEYRING_ALREADY_OPEN,
- assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, secondPassword)).code());
+ assertThrows(KeyringException.class, () -> KeyringStore.open(path, secondPassword)).code());
assertTrue(first.aliases().isEmpty());
}
- try (KeyringPassword password = password();
- KeyringStore reopened = KeyringStore.open(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore reopened = KeyringStore.open(path, password)) {
assertTrue(reopened.aliases().isEmpty());
}
ok();
@@ -134,8 +127,7 @@ class KeyringStoreTest {
void trailingDataAndNonExportableKeysAreRejected() throws Exception {
start("trailingDataAndNonExportableKeysAreRejected");
Path path = temporaryDirectory.resolve("strict.zek");
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.create(path, password)) {
SecretKey nonExportable = new SecretKey() {
private static final long serialVersionUID = 1L;
@@ -162,8 +154,7 @@ class KeyringStoreTest {
Files.write(path, new byte[] { 1 }, java.nio.file.StandardOpenOption.APPEND);
try (KeyringPassword password = password()) {
- KeyringException exception = assertThrows(KeyringException.class,
- () -> KeyringStore.open(path, password));
+ KeyringException exception = assertThrows(KeyringException.class, () -> KeyringStore.open(path, password));
assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID, exception.code());
}
ok();
@@ -175,8 +166,8 @@ class KeyringStoreTest {
Path path = temporaryDirectory.resolve("hmac.zek");
List accepted = List.of("HmacSHA256", "HmacSHA384", "HmacSHA512");
try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password,
- KeyringProtection.standard(), deterministicRandom())) {
+ KeyringStore store = KeyringStore.create(path, password, KeyringProtection.standard(),
+ deterministicRandom())) {
for (String variant : accepted) {
byte[] material = new byte[64];
Arrays.fill(material, (byte) variant.length());
@@ -190,23 +181,19 @@ class KeyringStoreTest {
}
byte[] before = Files.readAllBytes(path);
try {
- for (String rejected : List.of("HmacMD5", "HmacSHA1", "HmacSHA224",
- "hmacsha256", "HmacSha384", " HmacSHA512", "HmacSHA512 ",
- "BC:HmacSHA256", "", "X".repeat(4097))) {
+ for (String rejected : List.of("HmacMD5", "HmacSHA1", "HmacSHA224", "hmacsha256", "HmacSha384",
+ " HmacSHA512", "HmacSHA512 ", "BC:HmacSHA256", "", "X".repeat(4097))) {
SecretKey key = controlledSecret(rejected, new byte[32]);
KeyringException exception = assertThrows(KeyringException.class,
() -> store.putSecret("rejected", "HMAC", key));
- assertEquals(KeyringException.Code.KEYRING_IMPORT_METADATA_INVALID,
- exception.code());
- assertEquals(KeyringException.Code.KEYRING_IMPORT_METADATA_INVALID.name(),
- exception.getMessage());
+ assertEquals(KeyringException.Code.KEYRING_IMPORT_METADATA_INVALID, exception.code());
+ assertEquals(KeyringException.Code.KEYRING_IMPORT_METADATA_INVALID.name(), exception.getMessage());
assertArrayEquals(before, Files.readAllBytes(path));
assertFalse(store.contains("rejected"));
}
SecretKey mismatched = controlledSecret("HmacSHA256", new byte[32]);
assertEquals(KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE,
- assertThrows(KeyringException.class,
- () -> store.putSecret("wrong", "AES", mismatched)).code());
+ assertThrows(KeyringException.class, () -> store.putSecret("wrong", "AES", mismatched)).code());
assertArrayEquals(before, Files.readAllBytes(path));
} finally {
Arrays.fill(before, (byte) 0);
@@ -219,19 +206,16 @@ class KeyringStoreTest {
void providerDraftAndUnknownHmacVariantAreRejectedStructurally() throws Exception {
start("providerDraftAndUnknownHmacVariantAreRejectedStructurally");
assertEquals(KeyringException.Code.KEYRING_IMPORT_METADATA_INVALID,
- assertThrows(KeyringException.class,
- () -> KeyringImportRegistry.HmacVariant.fromCode(99)).code());
+ assertThrows(KeyringException.class, () -> KeyringImportRegistry.HmacVariant.fromCode(99)).code());
byte[] staleDraft = staleProviderEntryPlaintext();
try {
- java.lang.reflect.Method decoder = KeyringStore.class.getDeclaredMethod(
- "decodeEntryPlaintext", byte[].class);
+ java.lang.reflect.Method decoder = KeyringStore.class.getDeclaredMethod("decodeEntryPlaintext",
+ byte[].class);
decoder.setAccessible(true);
- java.lang.reflect.InvocationTargetException failure =
- assertThrows(java.lang.reflect.InvocationTargetException.class,
- () -> decoder.invoke(null, (Object) staleDraft));
+ java.lang.reflect.InvocationTargetException failure = assertThrows(
+ java.lang.reflect.InvocationTargetException.class, () -> decoder.invoke(null, (Object) staleDraft));
assertTrue(failure.getCause() instanceof KeyringException);
- assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID,
- ((KeyringException) failure.getCause()).code());
+ assertEquals(KeyringException.Code.KEYRING_FORMAT_INVALID, ((KeyringException) failure.getCause()).code());
} finally {
Arrays.fill(staleDraft, (byte) 0);
}
@@ -242,15 +226,13 @@ class KeyringStoreTest {
void providerBoundOrNoncanonicalKeysFailBeforeMutation() throws Exception {
start("providerBoundOrNoncanonicalKeysFailBeforeMutation");
Path path = temporaryDirectory.resolve("provider-bound.zek");
- try (KeyringPassword password = password();
- KeyringStore store = KeyringStore.create(path, password)) {
+ try (KeyringPassword password = password(); KeyringStore store = KeyringStore.create(path, password)) {
byte[] before = Files.readAllBytes(path);
try {
SecretKey unsupported = controlledSecret("ProviderAES", new byte[32]);
KeyringException failure = assertThrows(KeyringException.class,
() -> store.putSecret("bad", "AES", unsupported));
- assertEquals(KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE,
- failure.code());
+ assertEquals(KeyringException.Code.KEYRING_KEY_NOT_CANONICALIZABLE, failure.code());
assertArrayEquals(before, Files.readAllBytes(path));
assertFalse(store.contains("bad"));
} finally {
@@ -310,8 +292,7 @@ class KeyringStoreTest {
return bytes.toByteArray();
}
- private static void writeString(java.io.DataOutputStream out, String value)
- throws java.io.IOException {
+ private static void writeString(java.io.DataOutputStream out, String value) throws java.io.IOException {
byte[] bytes = value.getBytes(StandardCharsets.UTF_8);
try {
out.writeInt(bytes.length);
@@ -322,8 +303,7 @@ class KeyringStoreTest {
}
private static int indexOf(byte[] haystack, byte[] needle) {
- outer:
- for (int index = 0; index <= haystack.length - needle.length; index++) {
+ outer: for (int index = 0; index <= haystack.length - needle.length; index++) {
for (int offset = 0; offset < needle.length; offset++) {
if (haystack[index + offset] != needle[offset]) {
continue outer;
diff --git a/lib/src/test/java/zeroecho/sdk/ZeroEchoSessionDestroyKeyTest.java b/lib/src/test/java/zeroecho/sdk/ZeroEchoSessionDestroyKeyTest.java
index c85a3da..7d09f61 100644
--- a/lib/src/test/java/zeroecho/sdk/ZeroEchoSessionDestroyKeyTest.java
+++ b/lib/src/test/java/zeroecho/sdk/ZeroEchoSessionDestroyKeyTest.java
@@ -81,10 +81,7 @@ class ZeroEchoSessionDestroyKeyTest {
}
private enum Behavior {
- SUCCESS,
- FAIL_CHECKED,
- FAIL_RUNTIME,
- NO_TRANSITION
+ SUCCESS, FAIL_CHECKED, FAIL_RUNTIME, NO_TRANSITION
}
private static final class TestKey implements Key, Destroyable {
diff --git a/lib/src/test/java/zeroecho/sdk/builders/HybridKexBuilderTest.java b/lib/src/test/java/zeroecho/sdk/builders/HybridKexBuilderTest.java
index 8cb8f94..c6ac45a 100644
--- a/lib/src/test/java/zeroecho/sdk/builders/HybridKexBuilderTest.java
+++ b/lib/src/test/java/zeroecho/sdk/builders/HybridKexBuilderTest.java
@@ -91,22 +91,26 @@ class HybridKexBuilderTest {
HybridKexTranscript transcript = new HybridKexTranscript().addUtf8("suite", "X25519+ML-KEM-768").addUtf8("role",
"builder-test");
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
HybridKexContext alice = null;
HybridKexContext bob = null;
try {
- alice = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcript).classicAgreement()
- .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate())
+ alice = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcript)
+ .classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate())
.peerPublic(bobClassic.getPublic()).pqcKem().algorithm("ML-KEM").peerPublic(bobPqc.getPublic())
.buildInitiator();
- bob = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcript).classicAgreement().algorithm("Xdh")
- .spec(XdhSpec.X25519).privateKey(bobClassic.getPrivate()).peerPublic(aliceClassic.getPublic())
- .pqcKem().algorithm("ML-KEM").privateKey(bobPqc.getPrivate()).buildResponder();
+ bob = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcript)
+ .classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519).privateKey(bobClassic.getPrivate())
+ .peerPublic(aliceClassic.getPublic()).pqcKem().algorithm("ML-KEM").privateKey(bobPqc.getPrivate())
+ .buildResponder();
byte[] aliceMessage = alice.getPeerMessage();
System.out.println("...aliceMessage(" + lens(aliceMessage) + ")=" + hex(aliceMessage));
@@ -137,21 +141,24 @@ class HybridKexBuilderTest {
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
HybridKexContext alice = null;
HybridKexContext bob = null;
try {
- alice = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicPairMessage().algorithm("Xdh")
- .spec(XdhSpec.X25519).keyPair(new KeyPairKey(aliceClassic)).pqcKem().algorithm("ML-KEM")
- .peerPublic(bobPqc.getPublic()).buildInitiator();
+ alice = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicPairMessage()
+ .algorithm("Xdh").spec(XdhSpec.X25519).keyPair(new KeyPairKey(aliceClassic)).pqcKem()
+ .algorithm("ML-KEM").peerPublic(bobPqc.getPublic()).buildInitiator();
- bob = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicPairMessage().algorithm("Xdh").spec(XdhSpec.X25519)
- .keyPair(new KeyPairKey(bobClassic)).pqcKem().algorithm("ML-KEM").privateKey(bobPqc.getPrivate())
- .buildResponder();
+ bob = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicPairMessage()
+ .algorithm("Xdh").spec(XdhSpec.X25519).keyPair(new KeyPairKey(bobClassic)).pqcKem()
+ .algorithm("ML-KEM").privateKey(bobPqc.getPrivate()).buildResponder();
byte[] messageA = alice.getPeerMessage();
System.out.println("...messageA(" + lens(messageA) + ")=" + hex(messageA));
@@ -183,14 +190,17 @@ class HybridKexBuilderTest {
void buildInitiatorWithoutProfileFails() throws Exception {
System.out.println("buildInitiatorWithoutProfileFails");
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
- HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519)
- .privateKey(aliceClassic.getPrivate()).peerPublic(bobClassic.getPublic()).pqcKem()
- .algorithm("ML-KEM").peerPublic(bobPqc.getPublic()).buildInitiator();
+ HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).classicAgreement().algorithm("Xdh")
+ .spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate()).peerPublic(bobClassic.getPublic())
+ .pqcKem().algorithm("ML-KEM").peerPublic(bobPqc.getPublic()).buildInitiator();
});
System.out.println("...exception=" + exception.getMessage());
@@ -204,11 +214,12 @@ class HybridKexBuilderTest {
System.out.println("buildInitiatorWithoutClassicModeFails");
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
- HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).pqcKem().algorithm("ML-KEM").peerPublic(bobPqc.getPublic())
- .buildInitiator();
+ HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).pqcKem().algorithm("ML-KEM")
+ .peerPublic(bobPqc.getPublic()).buildInitiator();
});
System.out.println("...exception=" + exception.getMessage());
@@ -222,13 +233,15 @@ class HybridKexBuilderTest {
System.out.println("buildInitiatorClassicAgreementWithoutPeerPublicFails");
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
- HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519)
- .privateKey(aliceClassic.getPrivate()).pqcKem().algorithm("ML-KEM").peerPublic(bobPqc.getPublic())
- .buildInitiator();
+ HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicAgreement()
+ .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate()).pqcKem()
+ .algorithm("ML-KEM").peerPublic(bobPqc.getPublic()).buildInitiator();
});
System.out.println("...exception=" + exception.getMessage());
@@ -242,11 +255,13 @@ class HybridKexBuilderTest {
System.out.println("buildResponderPairMessageWithoutKeyPairFails");
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
- HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicPairMessage().algorithm("Xdh").spec(XdhSpec.X25519)
- .pqcKem().algorithm("ML-KEM").privateKey(bobPqc.getPrivate()).buildResponder();
+ HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicPairMessage()
+ .algorithm("Xdh").spec(XdhSpec.X25519).pqcKem().algorithm("ML-KEM").privateKey(bobPqc.getPrivate())
+ .buildResponder();
});
System.out.println("...exception=" + exception.getMessage());
@@ -260,13 +275,15 @@ class HybridKexBuilderTest {
System.out.println("buildInitiatorWithoutPqcPeerPublicFails");
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
- HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519)
- .privateKey(aliceClassic.getPrivate()).peerPublic(bobClassic.getPublic()).pqcKem()
- .algorithm("ML-KEM").buildInitiator();
+ HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicAgreement()
+ .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate())
+ .peerPublic(bobClassic.getPublic()).pqcKem().algorithm("ML-KEM").buildInitiator();
});
System.out.println("...exception=" + exception.getMessage());
@@ -280,13 +297,15 @@ class HybridKexBuilderTest {
System.out.println("buildResponderWithoutPqcPrivateFails");
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
IllegalStateException exception = assertThrows(IllegalStateException.class, () -> {
- HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519)
- .privateKey(bobClassic.getPrivate()).peerPublic(aliceClassic.getPublic()).pqcKem()
- .algorithm("ML-KEM").buildResponder();
+ HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).classicAgreement()
+ .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(bobClassic.getPrivate())
+ .peerPublic(aliceClassic.getPublic()).pqcKem().algorithm("ML-KEM").buildResponder();
});
System.out.println("...exception=" + exception.getMessage());
@@ -302,14 +321,18 @@ class HybridKexBuilderTest {
HybridKexProfile profile = HybridKexProfile.defaultProfile(16);
HybridKexPolicy policy = new HybridKexPolicy(0, 0, 32);
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
IllegalArgumentException exception = assertThrows(IllegalArgumentException.class, () -> {
- HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).policy(policy).classicAgreement().algorithm("Xdh")
- .spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate()).peerPublic(bobClassic.getPublic())
- .pqcKem().algorithm("ML-KEM").peerPublic(bobPqc.getPublic()).buildInitiator();
+ HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).policy(policy)
+ .classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate())
+ .peerPublic(bobClassic.getPublic()).pqcKem().algorithm("ML-KEM").peerPublic(bobPqc.getPublic())
+ .buildInitiator();
});
System.out.println("...exception=" + exception.getMessage());
@@ -328,21 +351,18 @@ class HybridKexBuilderTest {
closedContexts.incrementAndGet();
}
};
- ZeroEchoSession session = new ZeroEchoSession()
- .withAuditListener(listener)
- .withAuditMode(AuditMode.WRAP);
+ ZeroEchoSession session = new ZeroEchoSession().withAuditListener(listener).withAuditMode(AuditMode.WRAP);
HybridKexProfile profile = HybridKexProfile.defaultProfile(16);
HybridKexPolicy policy = new HybridKexPolicy(0, 0, 32);
KeyPair aliceClassic = session.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
KeyPair bobClassic = session.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = session.keyBuilders().asymmetric().generateKeyPair("ML-KEM",
- KyberKeyGenSpec.kyber768());
+ KeyPair bobPqc = session.keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
assertThrows(IllegalArgumentException.class,
() -> HybridKexBuilder.builder(session).profile(profile).policy(policy).classicAgreement()
.algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassic.getPrivate())
- .peerPublic(bobClassic.getPublic()).pqcKem().algorithm("ML-KEM")
- .peerPublic(bobPqc.getPublic()).buildInitiator());
+ .peerPublic(bobClassic.getPublic()).pqcKem().algorithm("ML-KEM").peerPublic(bobPqc.getPublic())
+ .buildInitiator());
assertEquals(2, closedContexts.get());
System.out.println("...closedContexts=" + closedContexts.get());
@@ -362,21 +382,18 @@ class HybridKexBuilderTest {
ZeroEchoSession keySession = new ZeroEchoSession();
KeyPair aliceClassic = keySession.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
KeyPair bobClassic = keySession.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = keySession.keyBuilders().asymmetric().generateKeyPair("ML-KEM",
- KyberKeyGenSpec.kyber768());
- ZeroEchoSession operationSession = new ZeroEchoSession()
- .withAuditListener(listener)
- .withAuditMode(AuditMode.WRAP)
- .withPolicy((id, role, key, spec) -> {
+ KeyPair bobPqc = keySession.keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ ZeroEchoSession operationSession = new ZeroEchoSession().withAuditListener(listener)
+ .withAuditMode(AuditMode.WRAP).withPolicy((id, role, key, spec) -> {
if ("ML-KEM".equals(id)) {
throw new IllegalArgumentException("controlled PQ policy denial");
}
});
assertThrows(IllegalArgumentException.class,
- () -> HybridKexContexts.initiator(operationSession, HybridKexProfile.defaultProfile(32),
- "Xdh", aliceClassic.getPrivate(), bobClassic.getPublic(), XdhSpec.X25519,
- "ML-KEM", bobPqc.getPublic(), null));
+ () -> HybridKexContexts.initiator(operationSession, HybridKexProfile.defaultProfile(32), "Xdh",
+ aliceClassic.getPrivate(), bobClassic.getPublic(), XdhSpec.X25519, "ML-KEM", bobPqc.getPublic(),
+ null));
assertEquals(1, closedContexts.get());
System.out.println("...closedContexts=" + closedContexts.get());
@@ -390,21 +407,17 @@ class HybridKexBuilderTest {
AuditListener listener = new AuditListener() {
@Override
public void onContextCreatedMeta(String contextId, String algorithmId, String provider,
- zeroecho.core.KeyUsage role, String keyFingerprint,
- java.util.Map specMeta) {
+ zeroecho.core.KeyUsage role, String keyFingerprint, java.util.Map specMeta) {
createdContexts.incrementAndGet();
}
};
- ZeroEchoSession session = new ZeroEchoSession()
- .withAuditListener(listener)
- .withAuditMode(AuditMode.WRAP);
+ ZeroEchoSession session = new ZeroEchoSession().withAuditListener(listener).withAuditMode(AuditMode.WRAP);
KeyPair aliceClassic = session.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
KeyPair bobClassic = session.keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
assertThrows(NullPointerException.class,
- () -> HybridKexContexts.initiator(session, HybridKexProfile.defaultProfile(32),
- "Xdh", aliceClassic.getPrivate(), bobClassic.getPublic(), XdhSpec.X25519,
- "ML-KEM", null, null));
+ () -> HybridKexContexts.initiator(session, HybridKexProfile.defaultProfile(32), "Xdh",
+ aliceClassic.getPrivate(), bobClassic.getPublic(), XdhSpec.X25519, "ML-KEM", null, null));
assertEquals(0, createdContexts.get());
System.out.println("...createdContexts=0");
@@ -416,9 +429,12 @@ class HybridKexBuilderTest {
System.out.println("switchingClassicModeClearsConflictingStateAndBuildsPairMessage");
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair agreementKeyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair pairMessageKeyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair agreementKeyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair pairMessageKeyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric()
+ .generateKeyPair("Xdh", XdhSpec.X25519);
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
HybridKexContext context = null;
try {
@@ -449,13 +465,19 @@ class HybridKexBuilderTest {
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
- KeyPair aliceClassicA = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassicA = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqcA = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair aliceClassicA = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassicA = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobPqcA = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
- KeyPair aliceClassicB = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassicB = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobPqcB = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair aliceClassicB = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassicB = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobPqcB = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
HybridKexTranscript transcriptA = new HybridKexTranscript().addUtf8("context", "A");
HybridKexTranscript transcriptB = new HybridKexTranscript().addUtf8("context", "B");
@@ -469,13 +491,13 @@ class HybridKexBuilderTest {
HybridKexContext bobB = null;
try {
- aliceA = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcriptA).classicAgreement()
- .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassicA.getPrivate())
- .peerPublic(bobClassicA.getPublic()).pqcKem().algorithm("ML-KEM").peerPublic(bobPqcA.getPublic())
- .buildInitiator();
+ aliceA = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile)
+ .transcript(transcriptA).classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519)
+ .privateKey(aliceClassicA.getPrivate()).peerPublic(bobClassicA.getPublic()).pqcKem()
+ .algorithm("ML-KEM").peerPublic(bobPqcA.getPublic()).buildInitiator();
- bobA = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcriptA).classicAgreement()
- .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(bobClassicA.getPrivate())
+ bobA = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcriptA)
+ .classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519).privateKey(bobClassicA.getPrivate())
.peerPublic(aliceClassicA.getPublic()).pqcKem().algorithm("ML-KEM").privateKey(bobPqcA.getPrivate())
.buildResponder();
@@ -486,13 +508,13 @@ class HybridKexBuilderTest {
System.out.println("...responderA=" + hex(responderA));
assertArrayEquals(secretA, responderA);
- aliceB = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcriptB).classicAgreement()
- .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(aliceClassicB.getPrivate())
- .peerPublic(bobClassicB.getPublic()).pqcKem().algorithm("ML-KEM").peerPublic(bobPqcB.getPublic())
- .buildInitiator();
+ aliceB = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile)
+ .transcript(transcriptB).classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519)
+ .privateKey(aliceClassicB.getPrivate()).peerPublic(bobClassicB.getPublic()).pqcKem()
+ .algorithm("ML-KEM").peerPublic(bobPqcB.getPublic()).buildInitiator();
- bobB = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcriptB).classicAgreement()
- .algorithm("Xdh").spec(XdhSpec.X25519).privateKey(bobClassicB.getPrivate())
+ bobB = HybridKexBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).profile(profile).transcript(transcriptB)
+ .classicAgreement().algorithm("Xdh").spec(XdhSpec.X25519).privateKey(bobClassicB.getPrivate())
.peerPublic(aliceClassicB.getPublic()).pqcKem().algorithm("ML-KEM").privateKey(bobPqcB.getPrivate())
.buildResponder();
diff --git a/lib/src/test/java/zeroecho/sdk/builders/TagTrailerDataContentBuilderTest.java b/lib/src/test/java/zeroecho/sdk/builders/TagTrailerDataContentBuilderTest.java
index 9b8c296..b7d9471 100644
--- a/lib/src/test/java/zeroecho/sdk/builders/TagTrailerDataContentBuilderTest.java
+++ b/lib/src/test/java/zeroecho/sdk/builders/TagTrailerDataContentBuilderTest.java
@@ -179,22 +179,27 @@ public class TagTrailerDataContentBuilderTest {
.generateSecret(AesKeyGenSpec.aes256());
// Ed25519 keys (JCA)
- KeyPair ed = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed25519", Ed25519KeyGenSpec.defaultSpec());
+ KeyPair ed = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed25519",
+ Ed25519KeyGenSpec.defaultSpec());
- TagEngine tagEnc = TagEngineBuilder.ed25519Sign(new zeroecho.sdk.ZeroEchoSession(), ed.getPrivate()).get();
- TagEngine tagDec = TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic()).get();
+ TagEngine tagEnc = TagEngineBuilder.ed25519Sign(new zeroecho.sdk.ZeroEchoSession(), ed.getPrivate())
+ .get();
+ TagEngine tagDec = TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic())
+ .get();
// ENCRYPT: body -> [body||signature] -> AES-GCM
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
- .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader()).build();
+ .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192)).add(AesDataContentBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .build();
byte[] ct = readAll(enc.getStream());
System.out.println("...ct=" + ct.length + " bytes");
// DECRYPT: AES-GCM -> strip trailer -> verify Ed25519 at EOF
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ct))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128)
+ .withHeader())
.add(new TagTrailerDataContentBuilder<>(tagDec).bufferSize(8192).throwOnMismatch()).build();
byte[] pt = readAll(dec.getStream());
@@ -217,23 +222,28 @@ public class TagTrailerDataContentBuilderTest {
// SPHINCS+ key pair via registry (uses default param set from
// SphincsPlusKeyGenSpec)
- KeyPair spx = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("SPHINCS+", SphincsPlusKeyGenSpec.defaultSpec());
+ KeyPair spx = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("SPHINCS+",
+ SphincsPlusKeyGenSpec.defaultSpec());
// Tag engines (SPHINCS+)
- TagEngine tagEnc = TagEngineBuilder.sphincsPlusSign(new zeroecho.sdk.ZeroEchoSession(), spx.getPrivate()).get();
- TagEngine tagDec = TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()).get();
+ TagEngine tagEnc = TagEngineBuilder
+ .sphincsPlusSign(new zeroecho.sdk.ZeroEchoSession(), spx.getPrivate()).get();
+ TagEngine tagDec = TagEngineBuilder
+ .sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()).get();
// ENCRYPT: body -> [body||spxSig] -> AES-GCM
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
- .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader()).build();
+ .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192)).add(AesDataContentBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .build();
byte[] ct = readAll(enc.getStream());
System.out.println("...ct=" + ct.length + " bytes");
// DECRYPT: AES-GCM -> strip trailer -> verify SPHINCS+ at EOF
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ct))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128)
+ .withHeader())
.add(new TagTrailerDataContentBuilder<>(tagDec).bufferSize(8192).throwOnMismatch()).build();
byte[] pt = readAll(dec.getStream());
@@ -255,24 +265,29 @@ public class TagTrailerDataContentBuilderTest {
.generateSecret(AesKeyGenSpec.aes256());
// RSA-2048 keys (use registry for convenience)
- KeyPair rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
// Tag engines (SHA-256, saltLen=32)
RsaSigSpec pss = RsaSigSpec.pss(RsaSigSpec.Hash.SHA256, 32);
- TagEngine tagEnc = TagEngineBuilder.rsaSign(new zeroecho.sdk.ZeroEchoSession(), rsa.getPrivate(), pss).get();
- TagEngine tagDec = TagEngineBuilder.rsaVerify(new zeroecho.sdk.ZeroEchoSession(), rsa.getPublic(), pss).get();
+ TagEngine tagEnc = TagEngineBuilder
+ .rsaSign(new zeroecho.sdk.ZeroEchoSession(), rsa.getPrivate(), pss).get();
+ TagEngine tagDec = TagEngineBuilder
+ .rsaVerify(new zeroecho.sdk.ZeroEchoSession(), rsa.getPublic(), pss).get();
// ENCRYPT: body -> [body||pssSig] -> AES-GCM
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
- .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader()).build();
+ .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192)).add(AesDataContentBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .build();
byte[] ct = readAll(enc.getStream());
System.out.println("...ct=" + ct.length + " bytes");
// DECRYPT: AES-GCM -> strip trailer -> verify PSS at EOF
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ct))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128)
+ .withHeader())
.add(new TagTrailerDataContentBuilder<>(tagDec).bufferSize(8192).throwOnMismatch()).build();
byte[] pt = readAll(dec.getStream());
@@ -297,9 +312,12 @@ public class TagTrailerDataContentBuilderTest {
// ENCRYPT: [source] -> [tag trailer] -> [aes gcm]
DataContent encChain = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader()) // writes IV/AAD headers
- // into stream
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192))
+ .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128)
+ .withHeader()) // writes IV/AAD headers
+ // into stream
.build();
byte[] ciphertext = readAll(encChain.getStream());
@@ -307,10 +325,12 @@ public class TagTrailerDataContentBuilderTest {
// DECRYPT: [source(ct)] -> [aes gcm] -> [tag trailer verify]
DataContent decChain = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader()) // reads IV/AAD headers
- // back
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192)
- .throwOnMismatch())
+ .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128)
+ .withHeader()) // reads IV/AAD headers
+ // back
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192).throwOnMismatch())
.build();
byte[] plain = readAll(decChain.getStream());
@@ -330,12 +350,16 @@ public class TagTrailerDataContentBuilderTest {
msg = Arrays.copyOf(msg, SIZE); // pad deterministic length for the test
System.out.println("...msg=" + msg.length + " bytes");
- KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair kp = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
// ENCRYPT: [source] -> [tag trailer] -> [rsa/oaep]
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192))
- .add(RsaEncDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).oaep(RsaEncSpec.Hash.SHA256).withPublicKey(kp.getPublic()))
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192))
+ .add(RsaEncDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).oaep(RsaEncSpec.Hash.SHA256)
+ .withPublicKey(kp.getPublic()))
.build();
byte[] ct = readAll(enc.getStream());
@@ -343,9 +367,11 @@ public class TagTrailerDataContentBuilderTest {
// DECRYPT: [source(ct)] -> [rsa/oaep] -> [tag verify]
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ct))
- .add(RsaEncDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).oaep(RsaEncSpec.Hash.SHA256).withPrivateKey(kp.getPrivate()))
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192)
- .throwOnMismatch())
+ .add(RsaEncDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).oaep(RsaEncSpec.Hash.SHA256)
+ .withPrivateKey(kp.getPrivate()))
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192).throwOnMismatch())
.build();
byte[] pt = readAll(dec.getStream());
@@ -379,17 +405,21 @@ public class TagTrailerDataContentBuilderTest {
System.out.println("...msg=" + msg.length + " bytes");
// ENCRYPT: [source] -> [tag trailer] -> [KEM envelope with AES/GCM payload]
- AesDataContentBuilder aesEnc = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128) // 128-bit tag
+ AesDataContentBuilder aesEnc = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128) // 128-bit
+ // tag
.withHeader(); // carry IV etc.
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192))
- .add(KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId).recipientPublic(kemKeys.getPublic()).derivedKeyBytes(32) // AES-256
- // key
- // derived
- // from
- // KEM
- // secret
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192))
+ .add(KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId)
+ .recipientPublic(kemKeys.getPublic()).derivedKeyBytes(32) // AES-256
+ // key
+ // derived
+ // from
+ // KEM
+ // secret
.hkdfSha256("KEM-tag-demo".getBytes(java.nio.charset.StandardCharsets.US_ASCII))
.withAes(aesEnc))
.build();
@@ -398,15 +428,17 @@ public class TagTrailerDataContentBuilderTest {
System.out.println("...envelope=" + envelope.length + " bytes");
// DECRYPT: [source(envelope)] -> [KEM] -> [tag verify]
- AesDataContentBuilder aesDec = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
+ AesDataContentBuilder aesDec = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128)
+ .withHeader();
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(envelope))
- .add(KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId).recipientPrivate(kemKeys.getPrivate())
- .derivedKeyBytes(32)
+ .add(KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId)
+ .recipientPrivate(kemKeys.getPrivate()).derivedKeyBytes(32)
.hkdfSha256("KEM-tag-demo".getBytes(java.nio.charset.StandardCharsets.US_ASCII))
.withAes(aesDec))
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192)
- .throwOnMismatch())
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192).throwOnMismatch())
.build();
byte[] pt = readAll(dec.getStream());
@@ -430,26 +462,34 @@ public class TagTrailerDataContentBuilderTest {
// --- recipients ---
// RSA
- KeyPair rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
// ML-KEM (Kyber768 as a good mid-level)
- KeyPair kem = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair kem = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
// --- symmetric payload (AES-256/GCM, tag 128) ---
// IV length is handled internally (12 bytes for GCM) and persisted via header.
- AesDataContentBuilder aesEnc = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader(); // write
- // IV/tagBits/AAD-hash
- // header for decrypt
- // side
+ AesDataContentBuilder aesEnc = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128)
+ .withHeader(); // write
+ // IV/tagBits/AAD-hash
+ // header for decrypt
+ // side
// --- tag trailer (SHA-256 digest as a trailer) ---
TagTrailerDataContentBuilder tagEnc = new TagTrailerDataContentBuilder<>(
TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192);
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
- KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE, kem.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
+ KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE,
+ kem.getPublic());
// --- envelope (ENCRYPT) with 3 recipients ---
- MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesEnc)
+ MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesEnc)
// .addRsaOaepRecipient(rsa.getPublic()) // RSA-OAEP with SHA-256 MGF1
// .addKemRecipient("ML-KEM", kem.getPublic(), 32 /* kekBytes */, 16 /*
// hkdfSaltLen */)
@@ -467,36 +507,48 @@ public class TagTrailerDataContentBuilderTest {
// -------------- Decrypt three ways on the same ciphertext --------------
// a) by RSA private key
- AesDataContentBuilder aesDecRsa = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader(); // read header to
- // recover
- // IV/tagBits
- MultiRecipientDataSourceBuilder envDecRsa = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesDecRsa)
- .unlockWith(new UnlockMaterial.Private(rsa.getPrivate()));
+ AesDataContentBuilder aesDecRsa = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128)
+ .withHeader(); // read header to
+ // recover
+ // IV/tagBits
+ MultiRecipientDataSourceBuilder envDecRsa = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesDecRsa).unlockWith(new UnlockMaterial.Private(rsa.getPrivate()));
byte[] ptRsa = readAll(DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(encrypted)).add(envDecRsa)
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192)
- .throwOnMismatch())
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192).throwOnMismatch())
.build().getStream());
System.out.println("...decrypted(RSA)=" + ptRsa.length);
assertArrayEquals(msg, ptRsa, "RSA path failed to recover the original");
// b) by KEM private key
- AesDataContentBuilder aesDecKem = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
- MultiRecipientDataSourceBuilder envDecKem = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesDecKem)
- .unlockWith(new UnlockMaterial.Private(kem.getPrivate()));
+ AesDataContentBuilder aesDecKem = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128)
+ .withHeader();
+ MultiRecipientDataSourceBuilder envDecKem = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesDecKem).unlockWith(new UnlockMaterial.Private(kem.getPrivate()));
byte[] ptKem = readAll(DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(encrypted)).add(envDecKem)
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192)
- .throwOnMismatch())
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192).throwOnMismatch())
.build().getStream());
System.out.println("...decrypted(KEM)=" + ptKem.length);
assertArrayEquals(msg, ptKem, "KEM path failed to recover the original");
// c) by password
- AesDataContentBuilder aesDecPwd = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
- MultiRecipientDataSourceBuilder envDecPwd = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesDecPwd)
- .unlockWith(new UnlockMaterial.Password(PASSWORD));
+ AesDataContentBuilder aesDecPwd = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128)
+ .withHeader();
+ MultiRecipientDataSourceBuilder envDecPwd = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesDecPwd).unlockWith(new UnlockMaterial.Password(PASSWORD));
byte[] ptPwd = readAll(DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(encrypted)).add(envDecPwd)
- .add(new TagTrailerDataContentBuilder<>(TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192)
- .throwOnMismatch())
+ .add(new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256()))
+ .bufferSize(8192).throwOnMismatch())
.build().getStream());
System.out.println("...decrypted(PASSWORD)=" + ptPwd.length);
assertArrayEquals(msg, ptPwd, "Password path failed to recover the original");
@@ -516,10 +568,12 @@ public class TagTrailerDataContentBuilderTest {
byte[] msg = random(SIZE);
System.out.println("...input=" + msg.length);
- KeyPair rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
// AES-256/CBC with header so IV/params are serialized by the AES stage
- AesDataContentBuilder aesCbc = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5().withHeader();
+ AesDataContentBuilder aesCbc = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5()
+ .withHeader();
TagTrailerDataContentBuilder tagEnc = new TagTrailerDataContentBuilder<>(
TagEngineBuilder.digest(new zeroecho.sdk.ZeroEchoSession(), DigestSpec.sha256())).bufferSize(8192);
@@ -529,10 +583,14 @@ public class TagTrailerDataContentBuilderTest {
// explicit for clarity
.throwOnMismatch();
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
// Envelope: recipient table (RSA-OAEP) + AES payload (CBC/PKCS7 with header)
- MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc)
+ MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc)
// CEK length for AES-256
.payloadKeyBytes(32)
// .addRsaOaepRecipient(rsa.getPublic()); old API
@@ -545,7 +603,9 @@ public class TagTrailerDataContentBuilderTest {
byte[] encrypted = readAll(encTail.getStream());
System.out.println("...encrypted=" + encrypted.length);
- MultiRecipientDataSourceBuilder envDec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ MultiRecipientDataSourceBuilder envDec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
.withAes(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5()
// must match encrypt side
.withHeader())
@@ -577,23 +637,28 @@ public class TagTrailerDataContentBuilderTest {
.generateSecret(AesKeyGenSpec.aes256());
// ECDSA P-256 keys (via your unified ECDSA algorithm)
- KeyPair ecdsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ECDSA", zeroecho.core.alg.ecdsa.EcdsaCurveSpec.P256);
+ KeyPair ecdsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ECDSA",
+ zeroecho.core.alg.ecdsa.EcdsaCurveSpec.P256);
// Tag engines (ECDSA/P-256 using P1363 format, fixed 64-byte tag)
- TagEngine tagEnc = TagEngineBuilder.ecdsaP256Sign(new zeroecho.sdk.ZeroEchoSession(), ecdsa.getPrivate()).get();
- TagEngine tagDec = TagEngineBuilder.ecdsaP256Verify(new zeroecho.sdk.ZeroEchoSession(), ecdsa.getPublic()).get();
+ TagEngine tagEnc = TagEngineBuilder
+ .ecdsaP256Sign(new zeroecho.sdk.ZeroEchoSession(), ecdsa.getPrivate()).get();
+ TagEngine tagDec = TagEngineBuilder
+ .ecdsaP256Verify(new zeroecho.sdk.ZeroEchoSession(), ecdsa.getPublic()).get();
// ENCRYPT: body -> [body||ecdsaSig] -> AES-GCM
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
- .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader()).build();
+ .add(new TagTrailerDataContentBuilder<>(tagEnc).bufferSize(8192)).add(AesDataContentBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .build();
byte[] ct = readAll(enc.getStream());
System.out.println("...ct=" + ct.length + " bytes");
// DECRYPT: AES-GCM -> strip trailer -> verify ECDSA at EOF
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ct))
- .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128).withHeader())
+ .add(AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withKey(aesKey).modeGcm(128)
+ .withHeader())
.add(new TagTrailerDataContentBuilder<>(tagDec).bufferSize(8192).throwOnMismatch()).build();
byte[] pt = readAll(dec.getStream());
diff --git a/lib/src/test/java/zeroecho/sdk/builders/alg/KemHybridRoundTripTest.java b/lib/src/test/java/zeroecho/sdk/builders/alg/KemHybridRoundTripTest.java
index f1c8bd8..c36e203 100644
--- a/lib/src/test/java/zeroecho/sdk/builders/alg/KemHybridRoundTripTest.java
+++ b/lib/src/test/java/zeroecho/sdk/builders/alg/KemHybridRoundTripTest.java
@@ -243,25 +243,29 @@ class KemHybridRoundTripTest {
}
private static DataContent encryptStage(String kemId, KeyPair kp, String mode) {
- KemDataContentBuilder kem = KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId).recipientPublic(kp.getPublic())
- .derivedKeyBytes(32); // AES-256 or ChaCha20 key
+ KemDataContentBuilder kem = KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId)
+ .recipientPublic(kp.getPublic()).derivedKeyBytes(32); // AES-256 or ChaCha20 key
switch (mode) {
case "GCM": {
- AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader().withAad(AAD);
+ AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader().withAad(AAD);
return kem.withAes(aes).build(true);
}
case "CBC": {
- AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5().withHeader();
+ AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeCbcPkcs5().withHeader();
return kem.withAes(aes).build(true);
}
case "CTR": {
- AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCtr().withHeader();
+ AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCtr()
+ .withHeader();
return kem.withAes(aes).build(true);
}
case "CHACHA20-POLY1305": {
- ChaChaDataContentBuilder ch = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withAad(AAD) // non-empty → AEAD
- // variant
+ ChaChaDataContentBuilder ch = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .withAad(AAD) // non-empty → AEAD
+ // variant
.withHeader(); // carry nonce
return kem.withChaCha(ch).build(true);
}
@@ -271,24 +275,28 @@ class KemHybridRoundTripTest {
}
private static DataContent decryptStage(String kemId, KeyPair kp, String mode) {
- KemDataContentBuilder kem = KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId).recipientPrivate(kp.getPrivate())
- .derivedKeyBytes(32);
+ KemDataContentBuilder kem = KemDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).kem(kemId)
+ .recipientPrivate(kp.getPrivate()).derivedKeyBytes(32);
switch (mode) {
case "GCM": {
- AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader().withAad(AAD);
+ AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader().withAad(AAD);
return kem.withAes(aes).build(false);
}
case "CBC": {
- AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5().withHeader();
+ AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeCbcPkcs5().withHeader();
return kem.withAes(aes).build(false);
}
case "CTR": {
- AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCtr().withHeader();
+ AesDataContentBuilder aes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCtr()
+ .withHeader();
return kem.withAes(aes).build(false);
}
case "CHACHA20-POLY1305": {
- ChaChaDataContentBuilder ch = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withAad(AAD).withHeader();
+ ChaChaDataContentBuilder ch = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .withAad(AAD).withHeader();
return kem.withChaCha(ch).build(false);
}
default:
diff --git a/lib/src/test/java/zeroecho/sdk/builders/alg/SessionBoundBuilderTest.java b/lib/src/test/java/zeroecho/sdk/builders/alg/SessionBoundBuilderTest.java
index e27827e..b156ec1 100644
--- a/lib/src/test/java/zeroecho/sdk/builders/alg/SessionBoundBuilderTest.java
+++ b/lib/src/test/java/zeroecho/sdk/builders/alg/SessionBoundBuilderTest.java
@@ -42,15 +42,12 @@ class SessionBoundBuilderTest {
void policyDenialOccursBeforeContextCreation() {
System.out.println("policyDenialOccursBeforeContextCreation");
RecordingListener listener = new RecordingListener();
- ZeroEchoSession session = new ZeroEchoSession()
- .withAuditListener(listener)
+ ZeroEchoSession session = new ZeroEchoSession().withAuditListener(listener)
.withPolicy((id, role, key, spec) -> {
throw new IllegalArgumentException("controlled policy denial");
});
- DataContent encryption = AesDataContentBuilder.builder(session)
- .withKey(new SecretKeySpec(new byte[16], "AES"))
- .modeGcm(128)
- .build(true);
+ DataContent encryption = AesDataContentBuilder.builder(session).withKey(new SecretKeySpec(new byte[16], "AES"))
+ .modeGcm(128).build(true);
encryption.setInput(new PlainBytes(new byte[] { 1 }));
assertThrows(IllegalArgumentException.class, encryption::getStream);
@@ -63,13 +60,9 @@ class SessionBoundBuilderTest {
void wrappedContextUsesBuilderSessionAuditConfiguration() throws Exception {
System.out.println("wrappedContextUsesBuilderSessionAuditConfiguration");
RecordingListener listener = new RecordingListener();
- ZeroEchoSession session = new ZeroEchoSession()
- .withAuditListener(listener)
- .withAuditMode(AuditMode.WRAP);
- DataContent encryption = AesDataContentBuilder.builder(session)
- .withKey(new SecretKeySpec(new byte[16], "AES"))
- .modeGcm(128)
- .build(true);
+ ZeroEchoSession session = new ZeroEchoSession().withAuditListener(listener).withAuditMode(AuditMode.WRAP);
+ DataContent encryption = AesDataContentBuilder.builder(session).withKey(new SecretKeySpec(new byte[16], "AES"))
+ .modeGcm(128).build(true);
encryption.setInput(new PlainBytes(new byte[] { 1, 2, 3 }));
try (InputStream input = encryption.getStream()) {
diff --git a/lib/src/test/java/zeroecho/sdk/guard/DecryptorCekCleanupTest.java b/lib/src/test/java/zeroecho/sdk/guard/DecryptorCekCleanupTest.java
index a855e8f..bfe832d 100644
--- a/lib/src/test/java/zeroecho/sdk/guard/DecryptorCekCleanupTest.java
+++ b/lib/src/test/java/zeroecho/sdk/guard/DecryptorCekCleanupTest.java
@@ -58,8 +58,8 @@ class DecryptorCekCleanupTest {
System.out.println("acceptedCekIsClearedWhenPayloadSetupFails");
byte[] accepted = new byte[16];
RecipientOpener opener = (entryId, entryBlob, material) -> accepted;
- Decryptor decryptor = new Decryptor(List.of(opener), new UnlockMaterial.Password(new char[] { 'p' }),
- null, null, 16, 4, 128);
+ Decryptor decryptor = new Decryptor(List.of(opener), new UnlockMaterial.Password(new char[] { 'p' }), null,
+ null, 16, 4, 128);
decryptor.setInput(() -> new ByteArrayInputStream(envelopeHeader()));
assertThrows(NullPointerException.class, decryptor::getStream);
@@ -104,8 +104,7 @@ class DecryptorCekCleanupTest {
private static Decryptor decryptor(RecipientOpener opener) {
AesDataContentBuilder aes = AesDataContentBuilder.builder(new ZeroEchoSession()).withHeader().modeGcm(128);
- return new Decryptor(List.of(opener), new UnlockMaterial.Password(new char[] { 'p' }),
- aes, null, 16, 4, 128);
+ return new Decryptor(List.of(opener), new UnlockMaterial.Password(new char[] { 'p' }), aes, null, 16, 4, 128);
}
private static byte[] envelopeHeader() throws IOException {
diff --git a/lib/src/test/java/zeroecho/sdk/guard/EncryptorCekAllocationTest.java b/lib/src/test/java/zeroecho/sdk/guard/EncryptorCekAllocationTest.java
index 603459b..2d5914d 100644
--- a/lib/src/test/java/zeroecho/sdk/guard/EncryptorCekAllocationTest.java
+++ b/lib/src/test/java/zeroecho/sdk/guard/EncryptorCekAllocationTest.java
@@ -83,8 +83,8 @@ class EncryptorCekAllocationTest {
void recipientLimitIsCheckedBeforeCekGeneration() {
System.out.print("EncryptorCekAllocation/recipientLimitIsCheckedBeforeCekGeneration...");
RecordingRandomFactory randomFactory = new RecordingRandomFactory();
- Encryptor encryptor = newEncryptor(List.of(new CapturingRecipient(false), new CapturingRecipient(false)),
- 1, randomFactory);
+ Encryptor encryptor = newEncryptor(List.of(new CapturingRecipient(false), new CapturingRecipient(false)), 1,
+ randomFactory);
encryptor.setInput(() -> new ByteArrayInputStream(new byte[0]));
assertThrows(IOException.class, encryptor::getStream);
@@ -97,8 +97,8 @@ class EncryptorCekAllocationTest {
void recipientFailureClearsGenuineAndDecoyCeks() {
System.out.print("EncryptorCekAllocation/recipientFailureClearsGenuineAndDecoyCeks...");
RecordingRandomFactory randomFactory = new RecordingRandomFactory();
- Encryptor encryptor = newEncryptor(List.of(new CapturingRecipient(false), new FailingRecipient(true)),
- 8, randomFactory);
+ Encryptor encryptor = newEncryptor(List.of(new CapturingRecipient(false), new FailingRecipient(true)), 8,
+ randomFactory);
encryptor.setInput(() -> new ByteArrayInputStream(new byte[0]));
assertThrows(IOException.class, encryptor::getStream);
@@ -124,8 +124,8 @@ class EncryptorCekAllocationTest {
void failedRecipientProcessingDestroysOwnedPassword() {
System.out.print("EncryptorCekAllocation/failedRecipientProcessingDestroysOwnedPassword...");
PasswordRecipient passwordRecipient = passwordRecipient();
- Encryptor encryptor = newEncryptor(List.of(passwordRecipient, new FailingRecipient(false)),
- 8, new RecordingRandomFactory());
+ Encryptor encryptor = newEncryptor(List.of(passwordRecipient, new FailingRecipient(false)), 8,
+ new RecordingRandomFactory());
encryptor.setInput(() -> new ByteArrayInputStream(new byte[0]));
assertThrows(IOException.class, encryptor::getStream);
@@ -143,8 +143,8 @@ class EncryptorCekAllocationTest {
private static Encryptor newEncryptor(List recipients, int maxRecipients,
IntFunction randomFactory) {
- return new Encryptor(recipients, AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128), null, KEY_BYTES,
- maxRecipients, 1024, randomFactory);
+ return new Encryptor(recipients, AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128),
+ null, KEY_BYTES, maxRecipients, 1024, randomFactory);
}
private static byte[] repeated(byte value) {
diff --git a/lib/src/test/java/zeroecho/sdk/guard/KemRecipientLifecycleTest.java b/lib/src/test/java/zeroecho/sdk/guard/KemRecipientLifecycleTest.java
index 8bdc5df..f0065c5 100644
--- a/lib/src/test/java/zeroecho/sdk/guard/KemRecipientLifecycleTest.java
+++ b/lib/src/test/java/zeroecho/sdk/guard/KemRecipientLifecycleTest.java
@@ -49,27 +49,23 @@ class KemRecipientLifecycleTest {
void constructorsAndBuilderRejectUnsupportedKekBeforeOwnershipTransfer() throws Exception {
System.out.println("constructorsAndBuilderRejectUnsupportedKekBeforeOwnershipTransfer");
int[] invalidValues = { -1, 0, 1, 15, 17, 24, 31, 33, Integer.MAX_VALUE };
- ZeroEchoSession session = new ZeroEchoSession()
- .withPbkdf2Limits(new Pbkdf2Limits(20_000, 30_000));
+ ZeroEchoSession session = new ZeroEchoSession().withPbkdf2Limits(new Pbkdf2Limits(20_000, 30_000));
MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
.withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader());
for (int kekBytes : invalidValues) {
ControlledKemContext direct = new ControlledKemContext(filled(32, (byte) 0x11));
- assertThrows(IllegalArgumentException.class,
- () -> new KemCtxRecipient(direct, kekBytes, 16));
+ assertThrows(IllegalArgumentException.class, () -> new KemCtxRecipient(direct, kekBytes, 16));
assertFalse(direct.closed);
direct.close();
ControlledKemContext normal = new ControlledKemContext(filled(32, (byte) 0x22));
- assertThrows(IllegalArgumentException.class,
- () -> builder.addRecipient(normal, kekBytes, 16));
+ assertThrows(IllegalArgumentException.class, () -> builder.addRecipient(normal, kekBytes, 16));
assertEquals(0, recipients(builder).size());
assertFalse(normal.closed);
normal.close();
ControlledKemContext decoy = new ControlledKemContext(filled(32, (byte) 0x33));
- assertThrows(IllegalArgumentException.class,
- () -> builder.addRecipientDecoy(decoy, kekBytes, 16));
+ assertThrows(IllegalArgumentException.class, () -> builder.addRecipientDecoy(decoy, kekBytes, 16));
assertEquals(0, recipients(builder).size());
assertFalse(decoy.closed);
decoy.close();
diff --git a/lib/src/test/java/zeroecho/sdk/guard/MultiRecipientEnvelopeTest.java b/lib/src/test/java/zeroecho/sdk/guard/MultiRecipientEnvelopeTest.java
index 89700e0..6f888fd 100644
--- a/lib/src/test/java/zeroecho/sdk/guard/MultiRecipientEnvelopeTest.java
+++ b/lib/src/test/java/zeroecho/sdk/guard/MultiRecipientEnvelopeTest.java
@@ -103,11 +103,14 @@ public class MultiRecipientEnvelopeTest {
final char[] password = "CorrectHorseBatteryStaple".toCharArray();
// AES-256-GCM with header so IV/tag are persisted in-band
- Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
+ Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader();
// Encrypt
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32)
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.addPasswordRecipient(password, /* iterations */ 10000, /* saltLen */ 16, /* kekBytes */ 32);
DataContent encryptor = enc.build(true);
@@ -120,8 +123,10 @@ public class MultiRecipientEnvelopeTest {
// Decrypt
UnlockMaterial.Password unlockMaterial = new UnlockMaterial.Password(password);
- MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32).unlockWith(unlockMaterial);
+ MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32).unlockWith(unlockMaterial);
DataContent decryptor = dec.build(false);
decryptor.setInput(new BytesContent(encrypted));
@@ -144,15 +149,12 @@ public class MultiRecipientEnvelopeTest {
System.out.println("passwordRecipientWithAes128KekRoundTrips");
byte[] input = randomInput(257);
char[] password = "controlled-password".toCharArray();
- ZeroEchoSession session = new ZeroEchoSession()
- .withPbkdf2Limits(new Pbkdf2Limits(1_000_000, 1_000_000));
+ ZeroEchoSession session = new ZeroEchoSession().withPbkdf2Limits(new Pbkdf2Limits(1_000_000, 1_000_000));
byte[] encrypted;
try (MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
- .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader())
- .payloadKeyBytes(32)
- .addPasswordRecipient(password, 10_000, 16, 16);
- MultiRecipientContent content = builder.build(true)) {
+ .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader()).payloadKeyBytes(32)
+ .addPasswordRecipient(password, 10_000, 16, 16); MultiRecipientContent content = builder.build(true)) {
content.setInput(new BytesContent(input));
try (InputStream stream = content.getStream()) {
encrypted = stream.readAllBytes();
@@ -162,10 +164,8 @@ public class MultiRecipientEnvelopeTest {
UnlockMaterial.Password unlock = new UnlockMaterial.Password(password);
byte[] decrypted;
try (MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
- .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader())
- .payloadKeyBytes(32)
- .unlockWith(unlock);
- MultiRecipientContent content = builder.build(false)) {
+ .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader()).payloadKeyBytes(32)
+ .unlockWith(unlock); MultiRecipientContent content = builder.build(false)) {
content.setInput(new BytesContent(encrypted));
try (InputStream stream = content.getStream()) {
decrypted = stream.readAllBytes();
@@ -192,10 +192,13 @@ public class MultiRecipientEnvelopeTest {
final char[] password = "Tr0ub4dor&3".toCharArray();
// AES-256-CBC with PKCS7 padding, header persists IV
- Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5().withHeader();
+ Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeCbcPkcs5().withHeader();
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc.get())
- .payloadKeyBytes(32)
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc.get()).payloadKeyBytes(32)
.addPasswordRecipient(password, /* iterations */ 10000, /* saltLen */ 16, /* kekBytes */ 32);
DataContent encryptor = enc.build(true);
@@ -206,8 +209,10 @@ public class MultiRecipientEnvelopeTest {
encrypted = readAllBytesAndPrint(es, "... encrypted size");
}
- MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc.get())
- .payloadKeyBytes(32).unlockWith(new UnlockMaterial.Password(password));
+ MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc.get()).payloadKeyBytes(32).unlockWith(new UnlockMaterial.Password(password));
DataContent decryptor = dec.build(false);
decryptor.setInput(new BytesContent(encrypted));
@@ -234,13 +239,18 @@ public class MultiRecipientEnvelopeTest {
final byte[] input = randomInput(128 * 1024 + 7);
System.out.println("... input size: " + input.length);
- KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
- EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, elg.getPublic());
+ KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
+ EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ elg.getPublic());
- Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
+ Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader();
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32).addRecipient(elgEnc);
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32).addRecipient(elgEnc);
DataContent encryptor = enc.build(true);
encryptor.setInput(new BytesContent(input));
@@ -250,8 +260,10 @@ public class MultiRecipientEnvelopeTest {
encrypted = readAllBytesAndPrint(es, "... encrypted size");
}
- MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(elg.getPrivate()));
+ MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(elg.getPrivate()));
DataContent decryptor = dec.build(false);
decryptor.setInput(new BytesContent(encrypted));
@@ -274,13 +286,18 @@ public class MultiRecipientEnvelopeTest {
final byte[] input = randomInput(128 * 1024 + 13); // cross blocks
System.out.println("... input size: " + input.length);
- KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
- EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, elg.getPublic());
+ KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
+ EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ elg.getPublic());
- Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5().withHeader();
+ Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeCbcPkcs5().withHeader();
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc.get())
- .payloadKeyBytes(32).addRecipient(elgEnc);
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc.get()).payloadKeyBytes(32).addRecipient(elgEnc);
DataContent encryptor = enc.build(true);
encryptor.setInput(new BytesContent(input));
@@ -290,8 +307,10 @@ public class MultiRecipientEnvelopeTest {
encrypted = readAllBytesAndPrint(es, "... encrypted size");
}
- MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc.get())
- .payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(elg.getPrivate()));
+ MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc.get()).payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(elg.getPrivate()));
DataContent decryptor = dec.build(false);
decryptor.setInput(new BytesContent(encrypted));
@@ -322,12 +341,16 @@ public class MultiRecipientEnvelopeTest {
kpg.initialize(3072, new SecureRandom());
KeyPair rsa = kpg.generateKeyPair();
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
- Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
+ Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader();
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32).addRecipient(rsaEnc);
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32).addRecipient(rsaEnc);
DataContent encryptor = enc.build(true);
encryptor.setInput(new BytesContent(input));
@@ -337,8 +360,10 @@ public class MultiRecipientEnvelopeTest {
encrypted = readAllBytesAndPrint(es, "... encrypted size");
}
- MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(rsa.getPrivate()));
+ MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(rsa.getPrivate()));
DataContent decryptor = dec.build(false);
decryptor.setInput(new BytesContent(encrypted));
@@ -365,12 +390,16 @@ public class MultiRecipientEnvelopeTest {
kpg.initialize(3072, new SecureRandom());
KeyPair rsa = kpg.generateKeyPair();
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
- Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5().withHeader();
+ Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeCbcPkcs5().withHeader();
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc.get())
- .payloadKeyBytes(32).addRecipient(rsaEnc);
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc.get()).payloadKeyBytes(32).addRecipient(rsaEnc);
DataContent encryptor = enc.build(true);
encryptor.setInput(new BytesContent(input));
@@ -380,8 +409,10 @@ public class MultiRecipientEnvelopeTest {
encrypted = readAllBytesAndPrint(es, "... encrypted size");
}
- MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc.get())
- .payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(rsa.getPrivate()));
+ MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc.get()).payloadKeyBytes(32).unlockWith(new UnlockMaterial.Private(rsa.getPrivate()));
DataContent decryptor = dec.build(false);
decryptor.setInput(new BytesContent(encrypted));
@@ -403,12 +434,12 @@ public class MultiRecipientEnvelopeTest {
void testKemRecipientWith128BitKekRoundTrip() throws Exception {
System.out.println("testKemRecipientWith128BitKekRoundTrip");
byte[] input = randomInput(257);
- KeyPair keyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric()
- .generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
+ KeyPair keyPair = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber512());
byte[] encrypted = encryptKemRecipients(input, new KeyPair[] { keyPair }, new int[] { 16 });
- decryptAndAssert("...128-bit KEK", aesGcmSupplier(), new UnlockMaterial.Private(keyPair.getPrivate()),
- input, encrypted);
+ decryptAndAssert("...128-bit KEK", aesGcmSupplier(), new UnlockMaterial.Private(keyPair.getPrivate()), input,
+ encrypted);
System.out.println("...encryptedLength=" + encrypted.length);
System.out.println("testKemRecipientWith128BitKekRoundTrip...ok");
@@ -418,17 +449,15 @@ public class MultiRecipientEnvelopeTest {
void testMixedKemRecipientKekSizesRoundTrip() throws Exception {
System.out.println("testMixedKemRecipientKekSizesRoundTrip");
zeroecho.sdk.ZeroEchoSession session = new zeroecho.sdk.ZeroEchoSession();
- KeyPair first = session.keyBuilders().asymmetric()
- .generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
- KeyPair second = session.keyBuilders().asymmetric()
- .generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
+ KeyPair first = session.keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
+ KeyPair second = session.keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
byte[] input = randomInput(513);
byte[] encrypted = encryptKemRecipients(input, new KeyPair[] { first, second }, new int[] { 16, 32 });
- decryptAndAssert("...mixed 16-byte KEK", aesGcmSupplier(),
- new UnlockMaterial.Private(first.getPrivate()), input, encrypted);
- decryptAndAssert("...mixed 32-byte KEK", aesGcmSupplier(),
- new UnlockMaterial.Private(second.getPrivate()), input, encrypted);
+ decryptAndAssert("...mixed 16-byte KEK", aesGcmSupplier(), new UnlockMaterial.Private(first.getPrivate()),
+ input, encrypted);
+ decryptAndAssert("...mixed 32-byte KEK", aesGcmSupplier(), new UnlockMaterial.Private(second.getPrivate()),
+ input, encrypted);
System.out.println("...recipientCount=2");
System.out.println("testMixedKemRecipientKekSizesRoundTrip...ok");
@@ -438,22 +467,16 @@ public class MultiRecipientEnvelopeTest {
void defaultKemOpenerContinuesAfterSameAlgorithmDecoy() throws Exception {
System.out.println("defaultKemOpenerContinuesAfterSameAlgorithmDecoy");
ZeroEchoSession session = new ZeroEchoSession();
- KeyPair decoy = session.keyBuilders().asymmetric()
- .generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
- KeyPair legitimate = session.keyBuilders().asymmetric()
- .generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
+ KeyPair decoy = session.keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
+ KeyPair legitimate = session.keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
byte[] input = randomInput(385);
byte[] encrypted;
- KemContext decoyContext =
- session.createContext("ML-KEM", KeyUsage.ENCAPSULATE, decoy.getPublic());
- KemContext legitimateContext =
- session.createContext("ML-KEM", KeyUsage.ENCAPSULATE, legitimate.getPublic());
+ KemContext decoyContext = session.createContext("ML-KEM", KeyUsage.ENCAPSULATE, decoy.getPublic());
+ KemContext legitimateContext = session.createContext("ML-KEM", KeyUsage.ENCAPSULATE, legitimate.getPublic());
try (MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
- .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader())
- .payloadKeyBytes(32)
- .addRecipient(decoyContext, 32, 16)
- .addRecipient(legitimateContext, 32, 16);
+ .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader()).payloadKeyBytes(32)
+ .addRecipient(decoyContext, 32, 16).addRecipient(legitimateContext, 32, 16);
MultiRecipientContent content = builder.build(true)) {
content.setInput(new BytesContent(input));
try (InputStream stream = content.getStream()) {
@@ -463,8 +486,7 @@ public class MultiRecipientEnvelopeTest {
byte[] decrypted;
try (MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
- .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader())
- .payloadKeyBytes(32)
+ .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(legitimate.getPrivate()));
MultiRecipientContent content = builder.build(false)) {
content.setInput(new BytesContent(encrypted));
@@ -482,22 +504,16 @@ public class MultiRecipientEnvelopeTest {
void defaultEncryptionOpenerContinuesAfterSameAlgorithmDecoy() throws Exception {
System.out.println("defaultEncryptionOpenerContinuesAfterSameAlgorithmDecoy");
ZeroEchoSession session = new ZeroEchoSession();
- KeyPair decoy = session.keyBuilders().asymmetric()
- .generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
- KeyPair legitimate = session.keyBuilders().asymmetric()
- .generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair decoy = session.keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
+ KeyPair legitimate = session.keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
byte[] input = randomInput(385);
byte[] encrypted;
- EncryptionContext decoyContext =
- session.createContext("RSA", KeyUsage.ENCRYPT, decoy.getPublic());
- EncryptionContext legitimateContext =
- session.createContext("RSA", KeyUsage.ENCRYPT, legitimate.getPublic());
+ EncryptionContext decoyContext = session.createContext("RSA", KeyUsage.ENCRYPT, decoy.getPublic());
+ EncryptionContext legitimateContext = session.createContext("RSA", KeyUsage.ENCRYPT, legitimate.getPublic());
try (MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
- .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader())
- .payloadKeyBytes(32)
- .addRecipient(decoyContext)
- .addRecipient(legitimateContext);
+ .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader()).payloadKeyBytes(32)
+ .addRecipient(decoyContext).addRecipient(legitimateContext);
MultiRecipientContent content = builder.build(true)) {
content.setInput(new BytesContent(input));
try (InputStream stream = content.getStream()) {
@@ -507,8 +523,7 @@ public class MultiRecipientEnvelopeTest {
byte[] decrypted;
try (MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
- .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader())
- .payloadKeyBytes(32)
+ .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(legitimate.getPrivate()));
MultiRecipientContent content = builder.build(false)) {
content.setInput(new BytesContent(encrypted));
@@ -537,17 +552,25 @@ public class MultiRecipientEnvelopeTest {
kpg.initialize(3072, new SecureRandom());
KeyPair rsa = kpg.generateKeyPair();
- KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
- KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
+ KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber512());
+ KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
- EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, elg.getPublic());
- KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE, kyber.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
+ EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ elg.getPublic());
+ KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE,
+ kyber.getPublic());
- Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
+ Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader();
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32)
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.addPasswordRecipient(password, /* iterations */ 10000, /* saltLen */ 16, /* kekBytes */ 32)
.addRecipient(rsaEnc).addRecipient(elgEnc).addRecipient(kybKem, /* kekBytes */ 32, /* saltLen */ 32);
@@ -585,18 +608,27 @@ public class MultiRecipientEnvelopeTest {
kpg.initialize(3072, new SecureRandom());
KeyPair rsa = kpg.generateKeyPair();
- rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA", RsaKeyGenSpec.rsa2048());
- KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
- KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
+ rsa = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("RSA",
+ RsaKeyGenSpec.rsa2048());
+ KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
+ KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
- EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, elg.getPublic());
- KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE, kyber.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
+ EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ elg.getPublic());
+ KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE,
+ kyber.getPublic());
- Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeCbcPkcs5().withHeader();
+ Supplier aesCbc = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeCbcPkcs5().withHeader();
- MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesCbc.get())
- .payloadKeyBytes(32)
+ MultiRecipientDataSourceBuilder enc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesCbc.get()).payloadKeyBytes(32)
.addPasswordRecipient(password, /* iterations */ 10000, /* saltLen */ 16, /* kekBytes */ 32)
.addRecipient(rsaEnc).addRecipient(elgEnc).addRecipient(kybKem, /* kekBytes */ 32, /* saltLen */ 32);
@@ -636,23 +668,32 @@ public class MultiRecipientEnvelopeTest {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(3072, new SecureRandom());
KeyPair rsa = kpg.generateKeyPair();
- KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
- KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
+ KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
+ KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
// Sender signature keys (Ed25519)
- KeyPair ed = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed25519", Ed25519KeyGenSpec.defaultSpec());
+ KeyPair ed = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Ed25519",
+ Ed25519KeyGenSpec.defaultSpec());
// AES-256-GCM payload builder
- Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
+ Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader();
// Context recipients
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
- EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, elg.getPublic());
- KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE, kyber.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
+ EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ elg.getPublic());
+ KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE,
+ kyber.getPublic());
// Envelope (encrypt)
- MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32).addRecipient(rsaEnc).addRecipient(elgEnc)
+ MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32).addRecipient(rsaEnc).addRecipient(elgEnc)
.addRecipient(kybKem, /* kekBytes */ 32, /* saltLen */ 16)
.addPasswordRecipient(password, /* iterations */ 100_000, /* saltLen */ 16, /* kekBytes */ 32);
@@ -673,10 +714,13 @@ public class MultiRecipientEnvelopeTest {
TagTrailerDataContentBuilder verifyTrailer;
// via Password
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic()))
- .bufferSize(8192).throwOnMismatch();
- DataContent decPwd = DataContentChainBuilder
- .decrypt().add(BytesSourceBuilder.of(ciphertext)).add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic())).bufferSize(8192)
+ .throwOnMismatch();
+ DataContent decPwd = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
.withAes(aesGcm.get()).payloadKeyBytes(32).unlockWith(new UnlockMaterial.Password(password)))
.add(verifyTrailer).build();
byte[] ptPwd;
@@ -686,10 +730,14 @@ public class MultiRecipientEnvelopeTest {
assertArrayEquals(msg, ptPwd);
// via RSA
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic()))
- .bufferSize(8192).throwOnMismatch();
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic())).bufferSize(8192)
+ .throwOnMismatch();
DataContent decRsa = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
- .add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get()).payloadKeyBytes(32)
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(rsa.getPrivate())))
.add(verifyTrailer).build();
byte[] ptRsa;
@@ -699,10 +747,14 @@ public class MultiRecipientEnvelopeTest {
assertArrayEquals(msg, ptRsa);
// via ElGamal
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic()))
- .bufferSize(8192).throwOnMismatch();
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic())).bufferSize(8192)
+ .throwOnMismatch();
DataContent decElgamal = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
- .add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get()).payloadKeyBytes(32)
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(elg.getPrivate())))
.add(verifyTrailer).build();
byte[] ptElgamal;
@@ -712,10 +764,14 @@ public class MultiRecipientEnvelopeTest {
assertArrayEquals(msg, ptElgamal);
// via ML-KEM
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic()))
- .bufferSize(8192).throwOnMismatch();
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.ed25519Verify(new zeroecho.sdk.ZeroEchoSession(), ed.getPublic())).bufferSize(8192)
+ .throwOnMismatch();
DataContent decKem = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
- .add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get()).payloadKeyBytes(32)
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(kyber.getPrivate())))
.add(verifyTrailer).build();
byte[] ptKem;
@@ -741,28 +797,38 @@ public class MultiRecipientEnvelopeTest {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(3072, new SecureRandom());
KeyPair rsa = kpg.generateKeyPair();
- KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber512());
- KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal", ElgamalParamSpec.ffdhe2048());
+ KeyPair kyber = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber512());
+ KeyPair elg = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ElGamal",
+ ElgamalParamSpec.ffdhe2048());
// Sender signature keys (SPHINCS+, default/best)
- KeyPair spx = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("SPHINCS+", SphincsPlusKeyGenSpec.defaultSpec());
+ KeyPair spx = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("SPHINCS+",
+ SphincsPlusKeyGenSpec.defaultSpec());
- Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
+ Supplier aesGcm = () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .modeGcm(128).withHeader();
// Context recipients
- EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT, rsa.getPublic());
- EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT, elg.getPublic());
- KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE, kyber.getPublic());
+ EncryptionContext rsaEnc = new zeroecho.sdk.ZeroEchoSession().createContext("RSA", KeyUsage.ENCRYPT,
+ rsa.getPublic());
+ EncryptionContext elgEnc = new zeroecho.sdk.ZeroEchoSession().createContext("ElGamal", KeyUsage.ENCRYPT,
+ elg.getPublic());
+ KemContext kybKem = new zeroecho.sdk.ZeroEchoSession().createContext("ML-KEM", KeyUsage.ENCAPSULATE,
+ kyber.getPublic());
// Envelope recipients
- MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get())
- .payloadKeyBytes(32).addRecipient(rsaEnc).addRecipient(elgEnc)
+ MultiRecipientDataSourceBuilder envEnc = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32).addRecipient(rsaEnc).addRecipient(elgEnc)
.addRecipient(kybKem, /* kekBytes */ 32, /* saltLen */ 16)
.addPasswordRecipient(password, /* iterations */ 120_000, /* saltLen */ 16, /* kekBytes */ 32);
// Tag trailer for SIGNING (SPHINCS+)
TagTrailerDataContentBuilder signTrailer = new TagTrailerDataContentBuilder<>(
- TagEngineBuilder.sphincsPlusSign(new zeroecho.sdk.ZeroEchoSession(), spx.getPrivate())).bufferSize(8192);
+ TagEngineBuilder.sphincsPlusSign(new zeroecho.sdk.ZeroEchoSession(), spx.getPrivate()))
+ .bufferSize(8192);
// Encrypt chain
DataContent encryptChain = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg)).add(signTrailer)
@@ -776,10 +842,13 @@ public class MultiRecipientEnvelopeTest {
TagTrailerDataContentBuilder verifyTrailer;
// via Password
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
.bufferSize(8192).throwOnMismatch();
- DataContent decPwd = DataContentChainBuilder
- .decrypt().add(BytesSourceBuilder.of(ciphertext)).add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ DataContent decPwd = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
.withAes(aesGcm.get()).payloadKeyBytes(32).unlockWith(new UnlockMaterial.Password(password)))
.add(verifyTrailer).build();
byte[] ptPwd;
@@ -789,10 +858,14 @@ public class MultiRecipientEnvelopeTest {
assertArrayEquals(msg, ptPwd);
// via RSA
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
.bufferSize(8192).throwOnMismatch();
DataContent decRsa = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
- .add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get()).payloadKeyBytes(32)
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(rsa.getPrivate())))
.add(verifyTrailer).build();
byte[] ptRsa;
@@ -802,10 +875,14 @@ public class MultiRecipientEnvelopeTest {
assertArrayEquals(msg, ptRsa);
// via ElGamal
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
.bufferSize(8192).throwOnMismatch();
DataContent decElgamal = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
- .add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get()).payloadKeyBytes(32)
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(elg.getPrivate())))
.add(verifyTrailer).build();
byte[] ptElgamal;
@@ -815,10 +892,14 @@ public class MultiRecipientEnvelopeTest {
assertArrayEquals(msg, ptElgamal);
// via ML-KEM
- verifyTrailer = new TagTrailerDataContentBuilder<>(TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
+ verifyTrailer = new TagTrailerDataContentBuilder<>(
+ TagEngineBuilder.sphincsPlusVerify(new zeroecho.sdk.ZeroEchoSession(), spx.getPublic()))
.bufferSize(8192).throwOnMismatch();
DataContent decKem = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(ciphertext))
- .add(MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesGcm.get()).payloadKeyBytes(32)
+ .add(MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesGcm.get()).payloadKeyBytes(32)
.unlockWith(new UnlockMaterial.Private(kyber.getPrivate())))
.add(verifyTrailer).build();
byte[] ptKem;
@@ -834,14 +915,12 @@ public class MultiRecipientEnvelopeTest {
// Helpers
// ------------------------------------------------------------------------------------
- private static byte[] encryptKemRecipients(byte[] input, KeyPair[] keyPairs, int[] kekSizes)
- throws Exception {
+ private static byte[] encryptKemRecipients(byte[] input, KeyPair[] keyPairs, int[] kekSizes) throws Exception {
zeroecho.sdk.ZeroEchoSession session = new zeroecho.sdk.ZeroEchoSession();
MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
.withAes(aesGcmSupplier().get()).payloadKeyBytes(32);
for (int index = 0; index < keyPairs.length; index++) {
- KemContext context = session.createContext("ML-KEM", KeyUsage.ENCAPSULATE,
- keyPairs[index].getPublic());
+ KemContext context = session.createContext("ML-KEM", KeyUsage.ENCAPSULATE, keyPairs[index].getPublic());
builder.addRecipient(context, kekSizes[index], 16);
}
DataContent encryptor = builder.build(true);
@@ -852,8 +931,7 @@ public class MultiRecipientEnvelopeTest {
}
private static Supplier aesGcmSupplier() {
- return () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
- .modeGcm(128).withHeader();
+ return () -> AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).modeGcm(128).withHeader();
}
/** Minimal source builder so we can compose pull-style chains. */
@@ -885,8 +963,10 @@ public class MultiRecipientEnvelopeTest {
private static void decryptAndAssert(String banner, Supplier aesFactory,
UnlockMaterial material, byte[] original, byte[] encrypted) throws IOException {
- MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder.builder(new zeroecho.sdk.ZeroEchoSession().withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000))).withAes(aesFactory.get())
- .payloadKeyBytes(32).unlockWith(material);
+ MultiRecipientDataSourceBuilder dec = MultiRecipientDataSourceBuilder
+ .builder(new zeroecho.sdk.ZeroEchoSession()
+ .withPbkdf2Limits(new zeroecho.sdk.Pbkdf2Limits(1_000_000, 1_000_000)))
+ .withAes(aesFactory.get()).payloadKeyBytes(32).unlockWith(material);
DataContent decryptor = dec.build(false);
decryptor.setInput(new BytesContent(encrypted));
diff --git a/lib/src/test/java/zeroecho/sdk/guard/PasswordRecipientTest.java b/lib/src/test/java/zeroecho/sdk/guard/PasswordRecipientTest.java
index 0c8b34e..7b1a948 100644
--- a/lib/src/test/java/zeroecho/sdk/guard/PasswordRecipientTest.java
+++ b/lib/src/test/java/zeroecho/sdk/guard/PasswordRecipientTest.java
@@ -75,10 +75,8 @@ class PasswordRecipientTest {
() -> new PasswordRecipient(new char[] { 'p' }, 10_000, 16, kekBytes, false, LIMITS));
}
- PasswordRecipient aes128 =
- new PasswordRecipient(new char[] { 'p' }, 10_000, 16, 16, false, LIMITS);
- PasswordRecipient aes256 =
- new PasswordRecipient(new char[] { 'p' }, 10_000, 16, 32, false, LIMITS);
+ PasswordRecipient aes128 = new PasswordRecipient(new char[] { 'p' }, 10_000, 16, 16, false, LIMITS);
+ PasswordRecipient aes256 = new PasswordRecipient(new char[] { 'p' }, 10_000, 16, 32, false, LIMITS);
aes128.close();
aes256.close();
System.out.println("...acceptedKekBytes=16,32");
@@ -131,9 +129,8 @@ class PasswordRecipientTest {
ByteArrayOutputStream blob = new ByteArrayOutputStream();
Util.writePack7I(blob, 9_999);
- assertThrows(IOException.class, () -> new PasswordOpener(LIMITS).tryOpen(
- "PWD:PBKDF2-SHA256:GCM-WRAP", blob.toByteArray(),
- new UnlockMaterial.Password(new char[] { 'p' })));
+ assertThrows(IOException.class, () -> new PasswordOpener(LIMITS).tryOpen("PWD:PBKDF2-SHA256:GCM-WRAP",
+ blob.toByteArray(), new UnlockMaterial.Password(new char[] { 'p' })));
System.out.println("ok");
}
@@ -143,11 +140,9 @@ class PasswordRecipientTest {
PasswordOpener opener = new PasswordOpener(LIMITS);
UnlockMaterial.Password material = new UnlockMaterial.Password(new char[] { 'p' });
- assertThrows(IOException.class,
- () -> opener.tryOpen("PWD:PBKDF2-SHA256:GCM-WRAP", new byte[] { 1 }, material));
- assertThrows(IOException.class,
- () -> opener.tryOpen("PWD:PBKDF2-SHA256:GCM-WRAP",
- new byte[] { 1, 1, 1, 1, 1, (byte) 0x80 }, material));
+ assertThrows(IOException.class, () -> opener.tryOpen("PWD:PBKDF2-SHA256:GCM-WRAP", new byte[] { 1 }, material));
+ assertThrows(IOException.class, () -> opener.tryOpen("PWD:PBKDF2-SHA256:GCM-WRAP",
+ new byte[] { 1, 1, 1, 1, 1, (byte) 0x80 }, material));
System.out.println("...malformedCases=2");
System.out.println("ok");
}
@@ -201,8 +196,7 @@ class PasswordRecipientTest {
assertTrue(content.isDestroyed());
assertTrue(recipient.isDestroyed());
- assertThrows(IllegalStateException.class,
- () -> content.setInput(() -> new ByteArrayInputStream(new byte[0])));
+ assertThrows(IllegalStateException.class, () -> content.setInput(() -> new ByteArrayInputStream(new byte[0])));
assertThrows(IllegalStateException.class, content::getStream);
System.out.println("...contentDestroyed=true");
System.out.println("abandonedBuiltContentOwnsAndDestroysTransferredRecipient...ok");
@@ -218,14 +212,13 @@ class PasswordRecipientTest {
DataContent limited = limitedBuilder.build(true);
limited.setInput(() -> new ByteArrayInputStream(new byte[0]));
assertThrows(IOException.class, limited::getStream);
- assertTrue(limitedRecipients.stream()
- .map(PasswordRecipient.class::cast).allMatch(PasswordRecipient::isDestroyed));
+ assertTrue(
+ limitedRecipients.stream().map(PasswordRecipient.class::cast).allMatch(PasswordRecipient::isDestroyed));
- PasswordRecipient randomRecipient =
- new PasswordRecipient(new char[] { 'c' }, 10_000, 16, 32, false, LIMITS);
+ PasswordRecipient randomRecipient = new PasswordRecipient(new char[] { 'c' }, 10_000, 16, 32, false, LIMITS);
Encryptor randomFailure = new Encryptor(List.of(randomRecipient),
- AesDataContentBuilder.builder(new ZeroEchoSession()).modeGcm(128).withHeader(),
- null, 32, 4, 1024, ignored -> {
+ AesDataContentBuilder.builder(new ZeroEchoSession()).modeGcm(128).withHeader(), null, 32, 4, 1024,
+ ignored -> {
throw new IllegalStateException("controlled random failure");
});
randomFailure.setInput(() -> new ByteArrayInputStream(new byte[0]));
diff --git a/lib/src/test/java/zeroecho/sdk/guard/SessionRecipientOpenerContractTest.java b/lib/src/test/java/zeroecho/sdk/guard/SessionRecipientOpenerContractTest.java
index 86250a7..f4b33ba 100644
--- a/lib/src/test/java/zeroecho/sdk/guard/SessionRecipientOpenerContractTest.java
+++ b/lib/src/test/java/zeroecho/sdk/guard/SessionRecipientOpenerContractTest.java
@@ -32,8 +32,7 @@ class SessionRecipientOpenerContractTest {
assertSessionOnlyConstructor(EncCtxOpener.class);
List addOpenerMethods = Arrays.stream(MultiRecipientDataSourceBuilder.class.getMethods())
- .filter(method -> method.getName().equals("addOpener"))
- .toList();
+ .filter(method -> method.getName().equals("addOpener")).toList();
assertEquals(1, addOpenerMethods.size());
assertEquals(RecipientOpener.class, addOpenerMethods.get(0).getParameterTypes()[0]);
@@ -47,10 +46,8 @@ class SessionRecipientOpenerContractTest {
ZeroEchoSession session = new ZeroEchoSession();
UnlockMaterial.Password material = new UnlockMaterial.Password(new char[] { 'p' });
try {
- assertNull(new KemCtxOpener(session).tryOpen(
- "CTX-ENC:RSA", new byte[0], material));
- assertNull(new EncCtxOpener(session).tryOpen(
- "KEM:ML-KEM:GCM-WRAP", new byte[0], material));
+ assertNull(new KemCtxOpener(session).tryOpen("CTX-ENC:RSA", new byte[0], material));
+ assertNull(new EncCtxOpener(session).tryOpen("KEM:ML-KEM:GCM-WRAP", new byte[0], material));
} finally {
material.destroy();
}
@@ -61,15 +58,12 @@ class SessionRecipientOpenerContractTest {
@Test
void customReusableOpenerScansEveryEntryAndClosesOnce() throws Exception {
System.out.println("customReusableOpenerScansEveryEntryAndClosesOnce");
- ZeroEchoSession session = new ZeroEchoSession()
- .withPbkdf2Limits(new Pbkdf2Limits(20_000, 30_000));
+ ZeroEchoSession session = new ZeroEchoSession().withPbkdf2Limits(new Pbkdf2Limits(20_000, 30_000));
TrackingOpener opener = new TrackingOpener();
UnlockMaterial.Password material = new UnlockMaterial.Password(new char[] { 'p' });
try (MultiRecipientDataSourceBuilder builder = MultiRecipientDataSourceBuilder.builder(session)
- .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader())
- .unlockWith(material)
- .addOpener(opener);
- MultiRecipientContent content = builder.build(false)) {
+ .withAes(AesDataContentBuilder.builder(session).modeGcm(128).withHeader()).unlockWith(material)
+ .addOpener(opener); MultiRecipientContent content = builder.build(false)) {
content.setInput(() -> new ByteArrayInputStream(twoEntryHeader()));
assertThrows(IOException.class, content::getStream);
} finally {
diff --git a/lib/src/test/java/zeroecho/sdk/hybrid/derived/HybridDerivedTest.java b/lib/src/test/java/zeroecho/sdk/hybrid/derived/HybridDerivedTest.java
index a0e08b9..4622d78 100644
--- a/lib/src/test/java/zeroecho/sdk/hybrid/derived/HybridDerivedTest.java
+++ b/lib/src/test/java/zeroecho/sdk/hybrid/derived/HybridDerivedTest.java
@@ -76,7 +76,8 @@ public class HybridDerivedTest {
byte[] aad = "aad".getBytes(StandardCharsets.UTF_8);
byte[] msg = fixedBytes(1024, (byte) 0x5A);
- AesDataContentBuilder encAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader().modeGcm(128);
+ AesDataContentBuilder encAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader()
+ .modeGcm(128);
AesDataContentBuilder returnedEnc = HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript)
.aad(aad).applyToAesGcm(encAes, 256);
@@ -88,10 +89,10 @@ public class HybridDerivedTest {
System.out.println("...ciphertextLen=" + ciphertext.length);
System.out.println("...ciphertextPrefix=" + shortHex(ciphertext, 32));
- AesDataContentBuilder decAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader().modeGcm(128);
+ AesDataContentBuilder decAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader()
+ .modeGcm(128);
- HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad)
- .applyToAesGcm(decAes, 256);
+ HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad).applyToAesGcm(decAes, 256);
byte[] out = runDecrypt(decAes, ciphertext);
System.out.println("...outPrefix=" + shortHex(out, 32));
@@ -109,15 +110,16 @@ public class HybridDerivedTest {
byte[] aad = "aad".getBytes(StandardCharsets.UTF_8);
byte[] msg = fixedBytes(256, (byte) 0x1C);
- AesDataContentBuilder encAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader().modeGcm(128);
+ AesDataContentBuilder encAes = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader()
+ .modeGcm(128);
- HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad)
- .applyToAesGcm(encAes, 256);
+ HybridDerived.from(exporter).label("app/enc/aes").transcript(transcript).aad(aad).applyToAesGcm(encAes, 256);
byte[] ciphertext = runEncrypt(encAes, msg);
System.out.println("...ciphertextLen=" + ciphertext.length);
- AesDataContentBuilder decAesWrong = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader().modeGcm(128);
+ AesDataContentBuilder decAesWrong = AesDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .withHeader().modeGcm(128);
// ...label mismatch -> wrong key/iv/aad -> decryption must fail
HybridDerived.from(exporter).label("app/enc/aes_WRONG").transcript(transcript).aad(aad)
@@ -137,7 +139,8 @@ public class HybridDerivedTest {
byte[] aad = "aad".getBytes(StandardCharsets.UTF_8);
byte[] msg = fixedBytes(777, (byte) 0x33);
- ChaChaDataContentBuilder encChaCha = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader();
+ ChaChaDataContentBuilder encChaCha = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .withHeader();
ChaChaDataContentBuilder returnedEnc = HybridDerived.from(exporter).label("app/enc/chacha")
.transcript(transcript).aad(aad).applyToChaChaAead(encChaCha, 256);
@@ -149,7 +152,8 @@ public class HybridDerivedTest {
System.out.println("...ciphertextLen=" + ciphertext.length);
System.out.println("...ciphertextPrefix=" + shortHex(ciphertext, 32));
- ChaChaDataContentBuilder decChaCha = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).withHeader();
+ ChaChaDataContentBuilder decChaCha = ChaChaDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .withHeader();
HybridDerived.from(exporter).label("app/enc/chacha").transcript(transcript).aad(aad)
.applyToChaChaAead(decChaCha, 256);
@@ -174,7 +178,8 @@ public class HybridDerivedTest {
// recommended bits
// --------------------
- HmacDataContentBuilder macBuilder = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).sha256().emitHexTag();
+ HmacDataContentBuilder macBuilder = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).sha256()
+ .emitHexTag();
int recommendedBits = macBuilder.recommendedKeyBits();
System.out.println("...recommendedBits=" + recommendedBits);
@@ -184,8 +189,8 @@ public class HybridDerivedTest {
String tagHex = runHmacHex(macBuilder, msg);
System.out.println("...tagHexPrefix=" + shortText(tagHex, 64));
- HmacDataContentBuilder verifyBuilder = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).sha256().expectedTagHex(tagHex)
- .emitVerificationBoolean();
+ HmacDataContentBuilder verifyBuilder = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .sha256().expectedTagHex(tagHex).emitVerificationBoolean();
HybridDerived.from(exporter).label("app/mac/hmac-default").transcript(transcript).applyToHmac(verifyBuilder);
@@ -197,7 +202,8 @@ public class HybridDerivedTest {
// Override key size path: applyToHmac(hmac, keyBits)
// --------------------
- HmacDataContentBuilder macBuilderOv = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).sha256().emitHexTag();
+ HmacDataContentBuilder macBuilderOv = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .sha256().emitHexTag();
// ...override to 512-bit keying material (still valid for HMAC; explicit expert
// choice)
@@ -207,8 +213,8 @@ public class HybridDerivedTest {
String tagHexOv = runHmacHex(macBuilderOv, msg);
System.out.println("...tagHexOvPrefix=" + shortText(tagHexOv, 64));
- HmacDataContentBuilder verifyBuilderOv = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession()).sha256().expectedTagHex(tagHexOv)
- .emitVerificationBoolean();
+ HmacDataContentBuilder verifyBuilderOv = HmacDataContentBuilder.builder(new zeroecho.sdk.ZeroEchoSession())
+ .sha256().expectedTagHex(tagHexOv).emitVerificationBoolean();
HybridDerived.from(exporter).label("app/mac/hmac-override").transcript(transcript).applyToHmac(verifyBuilderOv,
512);
diff --git a/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexFrameCodecTest.java b/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexFrameCodecTest.java
index 4acb18a..26dc5de 100644
--- a/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexFrameCodecTest.java
+++ b/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexFrameCodecTest.java
@@ -67,17 +67,9 @@ class HybridKexFrameCodecTest {
@Test
void rejectsMalformedFrames() {
String name = start("rejectsMalformedFrames");
- byte[][] malformed = {
- new byte[7],
- ints(-1, 0),
- ints(0, -1),
- ints(1, 0),
- ints(0, 1),
- append(ints(0, 0), (byte) 0x7f),
- new byte[HybridKexContext.MAX_FRAME_BYTES + 1],
- ints(0, HybridKexContext.MAX_FRAME_BYTES),
- ints(Integer.MAX_VALUE, 0)
- };
+ byte[][] malformed = { new byte[7], ints(-1, 0), ints(0, -1), ints(1, 0), ints(0, 1),
+ append(ints(0, 0), (byte) 0x7f), new byte[HybridKexContext.MAX_FRAME_BYTES + 1],
+ ints(0, HybridKexContext.MAX_FRAME_BYTES), ints(Integer.MAX_VALUE, 0) };
for (byte[] frame : malformed) {
assertThrows(IOException.class, () -> HybridKexContext.decode(frame));
diff --git a/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexTest.java b/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexTest.java
index 194e844..fec779e 100644
--- a/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexTest.java
+++ b/lib/src/test/java/zeroecho/sdk/hybrid/kex/HybridKexTest.java
@@ -128,11 +128,14 @@ public class HybridKexTest {
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
// Classic: X25519 key pairs (Xdh + XdhSpec.X25519)
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
// PQC: ML-KEM key pair (Kyber variant)
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
HybridKexContext alice = null;
HybridKexContext bob = null;
@@ -140,13 +143,15 @@ public class HybridKexTest {
try {
// Initiator: classic uses Alice private + Bob classic public; PQC uses Bob PQC
// public
- alice = HybridKexContexts.initiator(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh", aliceClassic.getPrivate(), bobClassic.getPublic(),
- XdhSpec.X25519, "ML-KEM", bobPqc.getPublic(), null);
+ alice = HybridKexContexts.initiator(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh",
+ aliceClassic.getPrivate(), bobClassic.getPublic(), XdhSpec.X25519, "ML-KEM", bobPqc.getPublic(),
+ null);
// Responder: classic uses Bob private + Alice classic public; PQC uses Bob PQC
// private
- bob = HybridKexContexts.responder(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh", bobClassic.getPrivate(), aliceClassic.getPublic(),
- XdhSpec.X25519, "ML-KEM", bobPqc.getPrivate(), null);
+ bob = HybridKexContexts.responder(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh",
+ bobClassic.getPrivate(), aliceClassic.getPublic(), XdhSpec.X25519, "ML-KEM", bobPqc.getPrivate(),
+ null);
// Alice produces message (contains PQC ciphertext; classic part is empty here)
byte[] aliceMsg = alice.getPeerMessage();
@@ -189,11 +194,14 @@ public class HybridKexTest {
HybridKexProfile profile = HybridKexProfile.defaultProfile(32);
// Classic: X25519 key pairs (Xdh + XdhSpec.X25519)
- KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
- KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh", XdhSpec.X25519);
+ KeyPair aliceClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
+ KeyPair bobClassic = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("Xdh",
+ XdhSpec.X25519);
// PQC: ML-KEM key pair (recipient/responder)
- KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM", KyberKeyGenSpec.kyber768());
+ KeyPair bobPqc = new zeroecho.sdk.ZeroEchoSession().keyBuilders().asymmetric().generateKeyPair("ML-KEM",
+ KyberKeyGenSpec.kyber768());
HybridKexContext alice = null;
HybridKexContext bob = null;
@@ -203,11 +211,11 @@ public class HybridKexTest {
// KeyPairKey + ContextSpec).
// PQC leg is KEM-style: initiator uses recipient public key; responder uses
// recipient private key.
- alice = HybridKexContexts.initiatorPairMessage(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh", new KeyPairKey(aliceClassic), XdhSpec.X25519,
- "ML-KEM", bobPqc.getPublic(), null);
+ alice = HybridKexContexts.initiatorPairMessage(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh",
+ new KeyPairKey(aliceClassic), XdhSpec.X25519, "ML-KEM", bobPqc.getPublic(), null);
- bob = HybridKexContexts.responderPairMessage(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh", new KeyPairKey(bobClassic), XdhSpec.X25519,
- "ML-KEM", bobPqc.getPrivate(), null);
+ bob = HybridKexContexts.responderPairMessage(new zeroecho.sdk.ZeroEchoSession(), profile, "Xdh",
+ new KeyPairKey(bobClassic), XdhSpec.X25519, "ML-KEM", bobPqc.getPrivate(), null);
// Step 1: Alice -> Bob (classic SPKI + PQC ciphertext)
byte[] msgA = alice.getPeerMessage();
diff --git a/lib/src/test/java/zeroecho/sdk/hybrid/signature/HybridSignatureTest.java b/lib/src/test/java/zeroecho/sdk/hybrid/signature/HybridSignatureTest.java
index 0851d08..bc40c4e 100644
--- a/lib/src/test/java/zeroecho/sdk/hybrid/signature/HybridSignatureTest.java
+++ b/lib/src/test/java/zeroecho/sdk/hybrid/signature/HybridSignatureTest.java
@@ -242,8 +242,7 @@ public class HybridSignatureTest {
System.out.println("...msg=" + msg.length + " bytes");
ZeroEchoSession session = new ZeroEchoSession();
- KeyPair ed = session.keyBuilders().asymmetric().generateKeyPair("Ed25519",
- Ed25519KeyGenSpec.defaultSpec());
+ KeyPair ed = session.keyBuilders().asymmetric().generateKeyPair("Ed25519", Ed25519KeyGenSpec.defaultSpec());
KeyPair spx = session.keyBuilders().asymmetric().generateKeyPair("SPHINCS+",
SphincsPlusKeyGenSpec.defaultSpec());
@@ -256,15 +255,15 @@ public class HybridSignatureTest {
HybridSignatureProfile.VerifyRule.AND);
byte[] sigAnd;
- try (SignatureContext signer = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), andProfile, ed.getPrivate(), spx.getPrivate(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext signer = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), andProfile,
+ ed.getPrivate(), spx.getPrivate(), 2 * 1024 * 1024)) {
sigAnd = signTrailer(signer, msg);
}
System.out.println("...sig(AND).len=" + sigAnd.length + ", head=" + hexShort(sigAnd));
// verify OK
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), andProfile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), andProfile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(sigAnd);
try (InputStream in = verifier.wrap(new ByteArrayInputStream(msg))) {
@@ -275,8 +274,8 @@ public class HybridSignatureTest {
// corrupt classic => must fail
byte[] badClassic = concat(flipOneBit(sub(sigAnd, 0, edLen), 0), sub(sigAnd, edLen, spxLen));
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), andProfile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), andProfile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(badClassic);
assertThrows(java.io.IOException.class, () -> {
@@ -289,8 +288,8 @@ public class HybridSignatureTest {
// corrupt pqc => must fail
byte[] badPqc = concat(sub(sigAnd, 0, edLen), flipOneBit(sub(sigAnd, edLen, spxLen), 0));
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), andProfile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), andProfile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(badPqc);
assertThrows(java.io.IOException.class, () -> {
@@ -306,16 +305,16 @@ public class HybridSignatureTest {
HybridSignatureProfile.VerifyRule.OR);
byte[] sigOr;
- try (SignatureContext signer = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), orProfile, ed.getPrivate(), spx.getPrivate(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext signer = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), orProfile,
+ ed.getPrivate(), spx.getPrivate(), 2 * 1024 * 1024)) {
sigOr = signTrailer(signer, msg);
}
System.out.println("...sig(OR).len=" + sigOr.length + ", head=" + hexShort(sigOr));
// corrupt classic => OR must pass
byte[] orBadClassic = concat(flipOneBit(sub(sigOr, 0, edLen), 0), sub(sigOr, edLen, spxLen));
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), orProfile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), orProfile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(orBadClassic);
try (InputStream in = verifier.wrap(new ByteArrayInputStream(msg))) {
@@ -326,8 +325,8 @@ public class HybridSignatureTest {
// corrupt pqc => OR must pass
byte[] orBadPqc = concat(sub(sigOr, 0, edLen), flipOneBit(sub(sigOr, edLen, spxLen), 0));
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), orProfile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), orProfile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(orBadPqc);
try (InputStream in = verifier.wrap(new ByteArrayInputStream(msg))) {
@@ -338,8 +337,8 @@ public class HybridSignatureTest {
// corrupt both => OR must fail
byte[] orBadBoth = concat(flipOneBit(sub(sigOr, 0, edLen), 0), flipOneBit(sub(sigOr, edLen, spxLen), 0));
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), orProfile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), orProfile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(orBadBoth);
assertThrows(java.io.IOException.class, () -> {
@@ -377,14 +376,14 @@ public class HybridSignatureTest {
HybridSignatureProfile.VerifyRule.AND);
byte[] sig;
- try (SignatureContext signer = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile, rsa.getPrivate(), spx.getPrivate(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext signer = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile,
+ rsa.getPrivate(), spx.getPrivate(), 2 * 1024 * 1024)) {
sig = signTrailer(signer, msg);
}
System.out.println("...sig.len=" + sig.length + ", head=" + hexShort(sig));
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile, rsa.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile,
+ rsa.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(sig);
try (InputStream in = verifier.wrap(new ByteArrayInputStream(msg))) {
@@ -395,8 +394,8 @@ public class HybridSignatureTest {
// negative sanity: corrupt classic => must fail (AND)
byte[] badClassic = concat(flipOneBit(sub(sig, 0, rsaLen), 0), sub(sig, rsaLen, spxLen));
- try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile, rsa.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext verifier = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile,
+ rsa.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
verifier.setVerificationApproach(verifier.getVerificationCore().getThrowOnMismatch());
verifier.setExpectedTag(badClassic);
assertThrows(java.io.IOException.class, () -> {
@@ -426,8 +425,7 @@ public class HybridSignatureTest {
System.out.println("...msg=" + msg.length + " bytes");
ZeroEchoSession session = new ZeroEchoSession();
- KeyPair ed = session.keyBuilders().asymmetric().generateKeyPair("Ed25519",
- Ed25519KeyGenSpec.defaultSpec());
+ KeyPair ed = session.keyBuilders().asymmetric().generateKeyPair("Ed25519", Ed25519KeyGenSpec.defaultSpec());
KeyPair spx = session.keyBuilders().asymmetric().generateKeyPair("SPHINCS+",
SphincsPlusKeyGenSpec.defaultSpec());
@@ -437,8 +435,8 @@ public class HybridSignatureTest {
byte[] out;
int tagLen;
- try (SignatureContext tagEnc = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile, ed.getPrivate(), spx.getPrivate(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagEnc = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile,
+ ed.getPrivate(), spx.getPrivate(), 2 * 1024 * 1024)) {
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
.add(new TagTrailerDataContentBuilder(tagEnc).bufferSize(8192)).build();
@@ -449,8 +447,8 @@ public class HybridSignatureTest {
System.out.println("...out=" + out.length + " bytes");
- try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
tagDec.setVerificationApproach(tagDec.getVerificationCore().getThrowOnMismatch());
// IMPORTANT: TagTrailerDataContentBuilder supplies expectedTag internally
@@ -481,8 +479,7 @@ public class HybridSignatureTest {
System.out.println("...msg=" + msg.length + " bytes");
ZeroEchoSession session = new ZeroEchoSession();
- KeyPair ed = session.keyBuilders().asymmetric().generateKeyPair("Ed25519",
- Ed25519KeyGenSpec.defaultSpec());
+ KeyPair ed = session.keyBuilders().asymmetric().generateKeyPair("Ed25519", Ed25519KeyGenSpec.defaultSpec());
KeyPair spx = session.keyBuilders().asymmetric().generateKeyPair("SPHINCS+",
SphincsPlusKeyGenSpec.defaultSpec());
@@ -496,8 +493,8 @@ public class HybridSignatureTest {
byte[] out;
int tagLen;
- try (SignatureContext tagEnc = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile, ed.getPrivate(), spx.getPrivate(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagEnc = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile,
+ ed.getPrivate(), spx.getPrivate(), 2 * 1024 * 1024)) {
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
.add(new TagTrailerDataContentBuilder(tagEnc).bufferSize(8192)).build();
@@ -515,8 +512,8 @@ public class HybridSignatureTest {
byte[] badClassic = concat(flipOneBit(sub(tag, 0, edLen), 0), sub(tag, edLen, spxLen));
byte[] outBadClassic = concat(body, badClassic);
- try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
tagDec.setVerificationApproach(tagDec.getVerificationCore().getThrowOnMismatch());
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(outBadClassic))
@@ -533,8 +530,8 @@ public class HybridSignatureTest {
byte[] badPqc = concat(sub(tag, 0, edLen), flipOneBit(sub(tag, edLen, spxLen), 0));
byte[] outBadPqc = concat(body, badPqc);
- try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
tagDec.setVerificationApproach(tagDec.getVerificationCore().getThrowOnMismatch());
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(outBadPqc))
@@ -551,8 +548,8 @@ public class HybridSignatureTest {
byte[] badBoth = concat(flipOneBit(sub(tag, 0, edLen), 0), flipOneBit(sub(tag, edLen, spxLen), 0));
byte[] outBadBoth = concat(body, badBoth);
- try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile, ed.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile,
+ ed.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
tagDec.setVerificationApproach(tagDec.getVerificationCore().getThrowOnMismatch());
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(outBadBoth))
@@ -589,8 +586,8 @@ public class HybridSignatureTest {
byte[] out;
- try (SignatureContext tagEnc = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile, rsa.getPrivate(), spx.getPrivate(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagEnc = HybridSignatureContexts.sign(new zeroecho.sdk.ZeroEchoSession(), profile,
+ rsa.getPrivate(), spx.getPrivate(), 2 * 1024 * 1024)) {
DataContent enc = DataContentChainBuilder.encrypt().add(BytesSourceBuilder.of(msg))
.add(new TagTrailerDataContentBuilder(tagEnc).bufferSize(8192)).build();
@@ -600,8 +597,8 @@ public class HybridSignatureTest {
System.out.println("...out=" + out.length + " bytes");
- try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile, rsa.getPublic(), spx.getPublic(),
- 2 * 1024 * 1024)) {
+ try (SignatureContext tagDec = HybridSignatureContexts.verify(new zeroecho.sdk.ZeroEchoSession(), profile,
+ rsa.getPublic(), spx.getPublic(), 2 * 1024 * 1024)) {
tagDec.setVerificationApproach(tagDec.getVerificationCore().getThrowOnMismatch());
DataContent dec = DataContentChainBuilder.decrypt().add(BytesSourceBuilder.of(out))
diff --git a/pki/src/main/java/zeroecho/pki/api/ProfileService.java b/pki/src/main/java/zeroecho/pki/api/ProfileService.java
index 68e8fb6..cd8d7af 100644
--- a/pki/src/main/java/zeroecho/pki/api/ProfileService.java
+++ b/pki/src/main/java/zeroecho/pki/api/ProfileService.java
@@ -17,8 +17,8 @@ import zeroecho.pki.api.profile.ImportedCertificateProfileVersion;
* Versioned certificate-profile import, activation, and lookup service.
*
*
- * Import never activates a profile. All versions of one logical profile ID
- * have one immutable certificate kind. End-entity issuance resolves only an
+ * Import never activates a profile. All versions of one logical profile ID have
+ * one immutable certificate kind. End-entity issuance resolves only an
* explicitly activated persisted version through
* {@link #requireActiveProfile(String)}. Root and intermediate issuance use the
* same authoritative active-profile lookup and bind issued credentials to the
diff --git a/pki/src/main/java/zeroecho/pki/api/credential/Credential.java b/pki/src/main/java/zeroecho/pki/api/credential/Credential.java
index 5190e5a..50d7f2c 100644
--- a/pki/src/main/java/zeroecho/pki/api/credential/Credential.java
+++ b/pki/src/main/java/zeroecho/pki/api/credential/Credential.java
@@ -66,17 +66,16 @@ import zeroecho.pki.api.attr.AttributeSet;
* @param publicKeyId stable identifier derived from the subject public key
* @param profileBinding closed profile identity governing issuance
* @param status persisted issuance and inventory metadata; this value
- * is not sufficient for a trust decision because current
- * revocation state and evaluation time are external
- * runtime inputs. Security-sensitive callers must use
- * {@link EffectiveCredentialStatusResolver}.
+ * is not sufficient for a trust decision because
+ * current revocation state and evaluation time are
+ * external runtime inputs. Security-sensitive callers
+ * must use {@link EffectiveCredentialStatusResolver}.
* @param encoded encoded credential bytes
* @param attributes universal attribute set
*/
public record Credential(PkiId credentialId, FormatId formatId, IssuerRef issuerRef, SubjectRef subjectRef,
Validity validity, String serialOrUniqueId, PkiId publicKeyId, CredentialProfileBinding profileBinding,
- CredentialStatus status,
- EncodedObject encoded, AttributeSet attributes) {
+ CredentialStatus status, EncodedObject encoded, AttributeSet attributes) {
/**
* Creates a credential record.
diff --git a/pki/src/main/java/zeroecho/pki/api/credential/EffectiveCredentialStatusResolver.java b/pki/src/main/java/zeroecho/pki/api/credential/EffectiveCredentialStatusResolver.java
index be5593c..1c0c2a2 100644
--- a/pki/src/main/java/zeroecho/pki/api/credential/EffectiveCredentialStatusResolver.java
+++ b/pki/src/main/java/zeroecho/pki/api/credential/EffectiveCredentialStatusResolver.java
@@ -75,7 +75,7 @@ public interface EffectiveCredentialStatusResolver {
* @param credential credential to resolve
* @return effective runtime status
* @throws NullPointerException if {@code credential} is {@code null}
- * @throws PkiException if current status cannot be resolved safely
+ * @throws PkiException if current status cannot be resolved safely
*/
EffectiveCredentialStatus resolve(Credential credential);
@@ -83,11 +83,11 @@ public interface EffectiveCredentialStatusResolver {
* Requires a credential to be usable for the supplied operation category.
*
* @param credential credential to check
- * @param use trust-decision category
+ * @param use trust-decision category
* @return the supplied credential when usable
* @throws NullPointerException if an argument is {@code null}
- * @throws PkiException if status resolution fails or the credential is not
- * usable
+ * @throws PkiException if status resolution fails or the credential is
+ * not usable
*/
Credential requireUsable(Credential credential, CredentialUse use);
}
diff --git a/pki/src/main/java/zeroecho/pki/api/issuance/VerificationPolicy.java b/pki/src/main/java/zeroecho/pki/api/issuance/VerificationPolicy.java
index 5020cc8..6be792b 100644
--- a/pki/src/main/java/zeroecho/pki/api/issuance/VerificationPolicy.java
+++ b/pki/src/main/java/zeroecho/pki/api/issuance/VerificationPolicy.java
@@ -44,9 +44,10 @@ import java.util.Optional;
*
*
*
- * Setting {@code requireProofOfPossession} to {@code false} is suitable only for
- * diagnostic or policy-evaluation workflows. It cannot authorize credential
- * issuance; the issuance boundary always applies its own mandatory proof policy.
+ * Setting {@code requireProofOfPossession} to {@code false} is suitable only
+ * for diagnostic or policy-evaluation workflows. It cannot authorize credential
+ * issuance; the issuance boundary always applies its own mandatory proof
+ * policy.
*
*
* @param requireProofOfPossession whether proof-of-possession is required
diff --git a/pki/src/main/java/zeroecho/pki/api/orch/SigningSubmissionId.java b/pki/src/main/java/zeroecho/pki/api/orch/SigningSubmissionId.java
index 76d2a06..216ed06 100644
--- a/pki/src/main/java/zeroecho/pki/api/orch/SigningSubmissionId.java
+++ b/pki/src/main/java/zeroecho/pki/api/orch/SigningSubmissionId.java
@@ -44,11 +44,14 @@ import zeroecho.pki.api.PkiId;
/**
* Versioned ZeroEcho signing-submission identifier.
*
- * The format is {@code zsign:v1:::<128-bit-random>}.
- * Creation time remains store-authoritative: stores must validate the embedded
- * time against their own clock and persist it with the intent.
+ *
+ * The format is
+ * {@code zsign:v1:::<128-bit-random>}. Creation
+ * time remains store-authoritative: stores must validate the embedded time
+ * against their own clock and persist it with the intent.
+ *
*
- * @param id identifier value
+ * @param id identifier value
* @param namespace provider/store namespace
* @param createdAt embedded creation time with millisecond precision
*/
@@ -67,8 +70,8 @@ public record SigningSubmissionId(PkiId id, String namespace, Instant createdAt)
* Creates a new identifier using a cryptographically strong random source.
*
* @param namespace provider/store namespace
- * @param now trusted caller creation time
- * @param random secure random source
+ * @param now trusted caller creation time
+ * @param random secure random source
* @return new identifier
*/
public static SigningSubmissionId create(String namespace, Instant now, SecureRandom random) {
@@ -117,9 +120,9 @@ public record SigningSubmissionId(PkiId id, String namespace, Instant createdAt)
* Validates namespace and lifetime against store-authoritative time.
*
* @param requiredNamespace expected namespace
- * @param now store-authoritative time
- * @param horizon maximum accepted age
- * @param permittedSkew allowed future clock skew
+ * @param now store-authoritative time
+ * @param horizon maximum accepted age
+ * @param permittedSkew allowed future clock skew
* @throws IllegalArgumentException if namespace or lifetime is invalid
*/
public void validate(String requiredNamespace, Instant now, Duration horizon, Duration permittedSkew) {
@@ -147,8 +150,8 @@ public record SigningSubmissionId(PkiId id, String namespace, Instant createdAt)
}
for (int index = 0; index < namespace.length(); index++) {
char value = namespace.charAt(index);
- boolean valid = value >= 'a' && value <= 'z' || value >= '0' && value <= '9'
- || value == '.' || value == '_' || value == '-';
+ boolean valid = value >= 'a' && value <= 'z' || value >= '0' && value <= '9' || value == '.' || value == '_'
+ || value == '-';
if (!valid) {
throw new IllegalArgumentException("namespace contains an unsupported character");
}
diff --git a/pki/src/main/java/zeroecho/pki/api/profile/ActiveCertificateProfile.java b/pki/src/main/java/zeroecho/pki/api/profile/ActiveCertificateProfile.java
index 1035d77..413cf63 100644
--- a/pki/src/main/java/zeroecho/pki/api/profile/ActiveCertificateProfile.java
+++ b/pki/src/main/java/zeroecho/pki/api/profile/ActiveCertificateProfile.java
@@ -11,11 +11,10 @@ import java.util.Objects;
/**
* Validated active profile resolution result used by end-entity issuance.
*
- * @param reference exact active version reference
+ * @param reference exact active version reference
* @param definition authoritative immutable definition
*/
-public record ActiveCertificateProfile(CertificateProfileRef reference,
- CertificateProfileDefinition definition) {
+public record ActiveCertificateProfile(CertificateProfileRef reference, CertificateProfileDefinition definition) {
/** Creates an active profile result. */
public ActiveCertificateProfile {
Objects.requireNonNull(reference, "reference");
diff --git a/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileCatalog.java b/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileCatalog.java
index 0953fce..e4bf1f0 100644
--- a/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileCatalog.java
+++ b/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileCatalog.java
@@ -50,12 +50,10 @@ import zeroecho.pki.api.PkiException;
public final class BuiltInCertificateProfileCatalog {
/** Fixed packaged catalogue manifest resource. */
- public static final String MANIFEST_RESOURCE =
- "zeroecho/pki/profiles/v1/catalog.json";
+ public static final String MANIFEST_RESOURCE = "zeroecho/pki/profiles/v1/catalog.json";
private static final String PROFILE_RESOURCE_ROOT = "zeroecho/pki/profiles/v1/";
- private static final int MAXIMUM_RESOURCE_BYTES =
- CertificateProfileDocumentCodec.MAXIMUM_DOCUMENT_BYTES;
+ private static final int MAXIMUM_RESOURCE_BYTES = CertificateProfileDocumentCodec.MAXIMUM_DOCUMENT_BYTES;
private static final int MAXIMUM_MANIFEST_ENTRIES = 128;
private static final int MAXIMUM_MANIFEST_DEPTH = 16;
private static final int MAXIMUM_MANIFEST_STRING_BYTES = 4_096;
@@ -65,11 +63,10 @@ public final class BuiltInCertificateProfileCatalog {
private static final String FIELD_SCHEMA_VERSION = "schemaVersion";
private static final String FIELD_PROFILES = "profiles";
private static final String FIELD_RESOURCE = "resource";
- private static final String ERROR_PREFIX =
- "Built-in certificate profile catalogue rejected: code=";
- private static final Set EXPECTED_PROFILE_IDS =
- Set.of("server-tls", "vpn-server", "vpn-client", "email-signing",
- "root-ca", "intermediate-ca");
+ private static final String ERROR_PREFIX = "Built-in certificate profile catalogue rejected: code=";
+ private static final Set EXPECTED_PROFILE_IDS = Set.of("server-tls", "vpn-server", "vpn-client",
+ "email-signing", "root-ca", "intermediate-ca");
+
private BuiltInCertificateProfileCatalog() {
}
@@ -98,15 +95,13 @@ public final class BuiltInCertificateProfileCatalog {
}
}
- private static BuiltInCertificateProfileTemplate loadTemplate(ClassLoader classLoader,
- String resourceName) {
+ private static BuiltInCertificateProfileTemplate loadTemplate(ClassLoader classLoader, String resourceName) {
byte[] resourceBytes = readUniqueResource(classLoader, resourceName);
CertificateProfileDefinition definition = parseProfile(resourceBytes);
byte[] canonicalJson = canonicalize(definition);
requireCanonicalResource(resourceBytes, canonicalJson);
requireCanonicalRoundTrip(definition, canonicalJson);
- return new BuiltInCertificateProfileTemplate(definition, canonicalJson,
- sha256(canonicalJson), resourceName);
+ return new BuiltInCertificateProfileTemplate(definition, canonicalJson, sha256(canonicalJson), resourceName);
}
private static void requireCanonicalResource(byte[] resourceBytes, byte[] canonicalJson) {
@@ -115,17 +110,15 @@ public final class BuiltInCertificateProfileCatalog {
}
}
- private static void requireCanonicalRoundTrip(CertificateProfileDefinition definition,
- byte[] canonicalJson) {
+ private static void requireCanonicalRoundTrip(CertificateProfileDefinition definition, byte[] canonicalJson) {
if (!definition.equals(parseProfile(canonicalJson))) {
throw failure("PROFILE_CANONICALIZATION_INVALID");
}
}
private static void validateResourceName(String resourceName) {
- if (resourceName == null || resourceName.isEmpty()
- || resourceName.startsWith("/") || resourceName.contains("..")
- || resourceName.indexOf('\\') >= 0 || resourceName.indexOf(':') >= 0
+ if (resourceName == null || resourceName.isEmpty() || resourceName.startsWith("/")
+ || resourceName.contains("..") || resourceName.indexOf('\\') >= 0 || resourceName.indexOf(':') >= 0
|| !resourceName.startsWith(PROFILE_RESOURCE_ROOT)
|| resourceName.length() <= PROFILE_RESOURCE_ROOT.length()) {
throw failure("MANIFEST_RESOURCE_INVALID");
@@ -156,8 +149,7 @@ public final class BuiltInCertificateProfileCatalog {
}
private static byte[] readBounded(InputStream input) throws IOException {
- ByteArrayOutputStream output = new ByteArrayOutputStream(
- Math.min(READ_BUFFER_BYTES, MAXIMUM_RESOURCE_BYTES));
+ ByteArrayOutputStream output = new ByteArrayOutputStream(Math.min(READ_BUFFER_BYTES, MAXIMUM_RESOURCE_BYTES));
byte[] buffer = new byte[READ_BUFFER_BYTES];
int total = 0;
while (true) {
@@ -236,12 +228,10 @@ public final class BuiltInCertificateProfileCatalog {
if (!hashes.add(ByteBuffer.wrap(template.canonicalSha256()))) {
throw failure("DUPLICATE_PROFILE_HASH");
}
- if (!identities.add(new ProfileIdentity(definition.profileId(),
- definition.profileVersion()))) {
+ if (!identities.add(new ProfileIdentity(definition.profileId(), definition.profileVersion()))) {
throw failure("DUPLICATE_PROFILE_IDENTITY");
}
- if (definition.profileVersion() != EXPECTED_PROFILE_VERSION
- || !profileIds.add(definition.profileId())) {
+ if (definition.profileVersion() != EXPECTED_PROFILE_VERSION || !profileIds.add(definition.profileId())) {
throw failure("BUILT_IN_PROFILE_SET_INVALID");
}
switch (definition.certificateType()) {
@@ -253,8 +243,7 @@ public final class BuiltInCertificateProfileCatalog {
}
private List finish() {
- if (templates.size() != EXPECTED_PROFILE_IDS.size()
- || !profileIds.equals(EXPECTED_PROFILE_IDS)
+ if (templates.size() != EXPECTED_PROFILE_IDS.size() || !profileIds.equals(EXPECTED_PROFILE_IDS)
|| endEntityCount != 4 || rootCount != 1 || intermediateCount != 1) {
throw failure("BUILT_IN_PROFILE_SET_INVALID");
}
@@ -271,32 +260,23 @@ public final class BuiltInCertificateProfileCatalog {
if (encoded.length == 0) {
throw failure("MANIFEST_EMPTY");
}
- try (JsonParser parser = JSON_FACTORY.createParser(ObjectReadContext.empty(),
- encoded, 0, encoded.length)) {
+ try (JsonParser parser = JSON_FACTORY.createParser(ObjectReadContext.empty(), encoded, 0, encoded.length)) {
ManifestDocument document = readDocument(parser);
requireEndOfInput(parser);
return validate(document);
} catch (StreamConstraintsException ex) {
throw failure("MANIFEST_LIMIT_EXCEEDED");
} catch (JacksonException ex) {
- throw failure(isDuplicateFailure(ex)
- ? "MANIFEST_DUPLICATE_FIELD" : "MANIFEST_MALFORMED");
+ throw failure(isDuplicateFailure(ex) ? "MANIFEST_DUPLICATE_FIELD" : "MANIFEST_MALFORMED");
}
}
private static JsonFactory createJsonFactory() {
- StreamReadConstraints constraints = StreamReadConstraints.builder()
- .maxNestingDepth(MAXIMUM_MANIFEST_DEPTH)
- .maxDocumentLength(MAXIMUM_RESOURCE_BYTES)
- .maxTokenCount(1_024)
- .maxNumberLength(10)
- .maxStringLength(MAXIMUM_MANIFEST_STRING_BYTES)
- .maxNameLength(32)
- .build();
- JsonFactoryBuilder builder = JsonFactory.builder()
- .streamReadConstraints(constraints)
- .enable(StreamReadFeature.STRICT_DUPLICATE_DETECTION)
- .disable(StreamReadFeature.AUTO_CLOSE_SOURCE);
+ StreamReadConstraints constraints = StreamReadConstraints.builder().maxNestingDepth(MAXIMUM_MANIFEST_DEPTH)
+ .maxDocumentLength(MAXIMUM_RESOURCE_BYTES).maxTokenCount(1_024).maxNumberLength(10)
+ .maxStringLength(MAXIMUM_MANIFEST_STRING_BYTES).maxNameLength(32).build();
+ JsonFactoryBuilder builder = JsonFactory.builder().streamReadConstraints(constraints)
+ .enable(StreamReadFeature.STRICT_DUPLICATE_DETECTION).disable(StreamReadFeature.AUTO_CLOSE_SOURCE);
for (JsonReadFeature feature : JsonReadFeature.values()) {
builder.disable(feature);
}
diff --git a/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileTemplate.java b/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileTemplate.java
index d3b3091..cfc3db5 100644
--- a/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileTemplate.java
+++ b/pki/src/main/java/zeroecho/pki/api/profile/BuiltInCertificateProfileTemplate.java
@@ -81,12 +81,10 @@ public final class BuiltInCertificateProfileTemplate {
@Override
public boolean equals(Object other) {
- return this == other
- || other instanceof BuiltInCertificateProfileTemplate template
- && definition.equals(template.definition)
- && Arrays.equals(canonicalJson, template.canonicalJson)
- && Arrays.equals(canonicalSha256, template.canonicalSha256)
- && resourceName.equals(template.resourceName);
+ return this == other || other instanceof BuiltInCertificateProfileTemplate template
+ && definition.equals(template.definition) && Arrays.equals(canonicalJson, template.canonicalJson)
+ && Arrays.equals(canonicalSha256, template.canonicalSha256)
+ && resourceName.equals(template.resourceName);
}
@Override
@@ -98,8 +96,7 @@ public final class BuiltInCertificateProfileTemplate {
@Override
public String toString() {
- return "BuiltInCertificateProfileTemplate[profileId=" + definition.profileId()
- + ", profileVersion=" + definition.profileVersion()
- + ", resourceName=" + resourceName + "]";
+ return "BuiltInCertificateProfileTemplate[profileId=" + definition.profileId() + ", profileVersion="
+ + definition.profileVersion() + ", resourceName=" + resourceName + "]";
}
}
diff --git a/pki/src/main/java/zeroecho/pki/api/profile/CaCertificatePolicy.java b/pki/src/main/java/zeroecho/pki/api/profile/CaCertificatePolicy.java
index 684c078..e24598b 100644
--- a/pki/src/main/java/zeroecho/pki/api/profile/CaCertificatePolicy.java
+++ b/pki/src/main/java/zeroecho/pki/api/profile/CaCertificatePolicy.java
@@ -25,15 +25,13 @@ import java.util.Set;
* @param allowedSubjectKeyAlgorithmIds exact canonical ZeroEcho subject-key
* algorithm identifiers
*/
-public record CaCertificatePolicy(boolean basicConstraintsCritical, int pathLengthConstraint,
- boolean keyUsageCritical, Set keyUsages,
- Set allowedSubjectKeyAlgorithmIds) implements CertificatePolicy {
+public record CaCertificatePolicy(boolean basicConstraintsCritical, int pathLengthConstraint, boolean keyUsageCritical,
+ Set keyUsages, Set allowedSubjectKeyAlgorithmIds) implements CertificatePolicy {
/** Maximum supported path-length constraint. */
public static final int MAXIMUM_PATH_LENGTH = 32;
- private static final Set SUPPORTED_SUBJECT_KEY_ALGORITHMS =
- Set.of("RSA", "ECDSA", "Ed25519", "Ed448");
+ private static final Set SUPPORTED_SUBJECT_KEY_ALGORITHMS = Set.of("RSA", "ECDSA", "Ed25519", "Ed448");
/** Validates and constructs the CA policy. */
public CaCertificatePolicy {
@@ -51,8 +49,7 @@ public record CaCertificatePolicy(boolean basicConstraintsCritical, int pathLeng
}
keyUsages = Set.copyOf(keyUsages);
allowedSubjectKeyAlgorithmIds = Set.copyOf(allowedSubjectKeyAlgorithmIds);
- if (!keyUsages.contains(CaKeyUsage.KEY_CERT_SIGN)
- || !keyUsages.contains(CaKeyUsage.CRL_SIGN)) {
+ if (!keyUsages.contains(CaKeyUsage.KEY_CERT_SIGN) || !keyUsages.contains(CaKeyUsage.CRL_SIGN)) {
throw new IllegalArgumentException("CA Key Usage must permit certificate and CRL signing");
}
if (allowedSubjectKeyAlgorithmIds.isEmpty()
diff --git a/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfile.java b/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfile.java
index f679d68..7085754 100644
--- a/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfile.java
+++ b/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfile.java
@@ -41,8 +41,8 @@ import zeroecho.pki.api.FormatId;
* Defines issuance constraints and mapping hints for a class of credentials.
*
*
- * A profile is referenced by {@code profileId} during issuance. It defines
- * the complete deny-by-default identity and extension policy for an end-entity
+ * A profile is referenced by {@code profileId} during issuance. It defines the
+ * complete deny-by-default identity and extension policy for an end-entity
* credential. Requester fields absent from the profile are forbidden.
*
*
@@ -50,15 +50,15 @@ import zeroecho.pki.api.FormatId;
* Profiles must not include secrets.
*
*
- * @param profileId stable profile identifier
- * @param formatId framework/format supported by the profile
- * @param displayName human-readable name
- * @param maximumValidity positive maximum validity
- * @param subjectPolicy complete end-entity subject policy
- * @param leafPolicy complete end-entity extension policy
+ * @param profileId stable profile identifier
+ * @param formatId framework/format supported by the profile
+ * @param displayName human-readable name
+ * @param maximumValidity positive maximum validity
+ * @param subjectPolicy complete end-entity subject policy
+ * @param leafPolicy complete end-entity extension policy
*/
-public record CertificateProfile(String profileId, FormatId formatId, String displayName,
- Duration maximumValidity, SubjectPolicy subjectPolicy, LeafCertificatePolicy leafPolicy) {
+public record CertificateProfile(String profileId, FormatId formatId, String displayName, Duration maximumValidity,
+ SubjectPolicy subjectPolicy, LeafCertificatePolicy leafPolicy) {
/**
* Creates a certificate profile.
@@ -76,8 +76,8 @@ public record CertificateProfile(String profileId, FormatId formatId, String dis
if (displayName == null || displayName.isBlank()) {
throw new IllegalArgumentException("displayName must not be null/blank");
}
- if (maximumValidity == null || maximumValidity.isZero() || maximumValidity.isNegative()
- || subjectPolicy == null || leafPolicy == null) {
+ if (maximumValidity == null || maximumValidity.isZero() || maximumValidity.isNegative() || subjectPolicy == null
+ || leafPolicy == null) {
throw new IllegalArgumentException("profile policies and maximum validity must be valid");
}
}
diff --git a/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDefinition.java b/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDefinition.java
index c8cbcce..e3cfc5f 100644
--- a/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDefinition.java
+++ b/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDefinition.java
@@ -17,19 +17,18 @@ import zeroecho.pki.api.FormatId;
* Runtime activation state is deliberately excluded.
*
*
- * @param certificateType kind of certificate governed by the profile
- * @param profileId stable profile identifier
- * @param profileVersion positive configuration version
- * @param formatId framework/format identifier
- * @param displayName human-readable profile name
- * @param maximumValidity positive maximum validity
- * @param subjectPolicy complete subject policy
+ * @param certificateType kind of certificate governed by the profile
+ * @param profileId stable profile identifier
+ * @param profileVersion positive configuration version
+ * @param formatId framework/format identifier
+ * @param displayName human-readable profile name
+ * @param maximumValidity positive maximum validity
+ * @param subjectPolicy complete subject policy
* @param certificatePolicy closed certificate-specific policy variant
*/
-public record CertificateProfileDefinition(CertificateProfileKind certificateType,
- String profileId, long profileVersion, FormatId formatId, String displayName,
- Duration maximumValidity, SubjectPolicy subjectPolicy,
- CertificatePolicy certificatePolicy) {
+public record CertificateProfileDefinition(CertificateProfileKind certificateType, String profileId,
+ long profileVersion, FormatId formatId, String displayName, Duration maximumValidity,
+ SubjectPolicy subjectPolicy, CertificatePolicy certificatePolicy) {
/** Current certificate-profile document schema version. */
public static final int SCHEMA_VERSION = 2;
@@ -37,8 +36,8 @@ public record CertificateProfileDefinition(CertificateProfileKind certificateTyp
/**
* Creates a certificate-profile definition.
*
- * @throws IllegalArgumentException if a required value is absent or the
- * profile version is not positive
+ * @throws IllegalArgumentException if a required value is absent or the profile
+ * version is not positive
*/
public CertificateProfileDefinition {
if (certificateType == null) {
diff --git a/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDocumentCodec.java b/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDocumentCodec.java
index 3b59767..5f773c0 100644
--- a/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDocumentCodec.java
+++ b/pki/src/main/java/zeroecho/pki/api/profile/CertificateProfileDocumentCodec.java
@@ -44,8 +44,8 @@ import zeroecho.pki.api.PkiException;
*/
// The closed streaming grammar intentionally keeps all bounded field handlers in one codec.
@SuppressWarnings({ "PMD.AvoidDuplicateLiterals", "PMD.AvoidInstantiatingObjectsInLoops",
- "PMD.AvoidUncheckedExceptionsInSignatures", "PMD.CyclomaticComplexity",
- "PMD.PreserveStackTrace", "PMD.TooManyMethods" })
+ "PMD.AvoidUncheckedExceptionsInSignatures", "PMD.CyclomaticComplexity", "PMD.PreserveStackTrace",
+ "PMD.TooManyMethods" })
public final class CertificateProfileDocumentCodec {
/** Maximum accepted encoded document size. */
@@ -88,8 +88,8 @@ public final class CertificateProfileDocumentCodec {
throw failure("MALFORMED_JSON", "$");
}
preflight(encodedDocument);
- try (JsonParser parser = JSON_FACTORY.createParser(ObjectReadContext.empty(),
- encodedDocument, 0, encodedDocument.length)) {
+ try (JsonParser parser = JSON_FACTORY.createParser(ObjectReadContext.empty(), encodedDocument, 0,
+ encodedDocument.length)) {
CertificateProfileDefinition definition = parseDocument(parser);
if (parser.nextToken() != null) {
throw failure("MALFORMED_JSON", "$");
@@ -106,9 +106,9 @@ public final class CertificateProfileDocumentCodec {
* Reads and parses an encoded certificate-profile document.
*
*
- * This method does not close {@code input}; ownership remains with the
- * caller. It reads at most one byte beyond the document limit in order to
- * detect oversize input without unbounded buffering.
+ * This method does not close {@code input}; ownership remains with the caller.
+ * It reads at most one byte beyond the document limit in order to detect
+ * oversize input without unbounded buffering.
*
*
* @param input caller-owned stream containing UTF-8 JSON
@@ -119,8 +119,7 @@ public final class CertificateProfileDocumentCodec {
if (input == null) {
throw failure("WRONG_TYPE", "$");
}
- ByteArrayOutputStream output = new ByteArrayOutputStream(
- Math.min(READ_BUFFER_BYTES, MAXIMUM_DOCUMENT_BYTES));
+ ByteArrayOutputStream output = new ByteArrayOutputStream(Math.min(READ_BUFFER_BYTES, MAXIMUM_DOCUMENT_BYTES));
byte[] buffer = new byte[READ_BUFFER_BYTES];
int total = 0;
try {
@@ -163,8 +162,7 @@ public final class CertificateProfileDocumentCodec {
public static byte[] writeCanonical(CertificateProfileDefinition definition) {
validateDefinition(definition);
ByteArrayOutputStream output = new ByteArrayOutputStream(2_048);
- try (JsonGenerator generator = JSON_FACTORY.createGenerator(ObjectWriteContext.empty(),
- output)) {
+ try (JsonGenerator generator = JSON_FACTORY.createGenerator(ObjectWriteContext.empty(), output)) {
writeDocument(generator, definition);
} catch (JacksonException ex) {
throw failure("CANONICALIZATION_FAILED", "$");
@@ -177,18 +175,11 @@ public final class CertificateProfileDocumentCodec {
}
private static JsonFactory createJsonFactory() {
- StreamReadConstraints constraints = StreamReadConstraints.builder()
- .maxNestingDepth(MAXIMUM_DEPTH)
- .maxDocumentLength(MAXIMUM_DOCUMENT_BYTES)
- .maxTokenCount(8_192)
- .maxNumberLength(20)
- .maxStringLength(MAXIMUM_STRING_UTF8_BYTES)
- .maxNameLength(64)
- .build();
- JsonFactoryBuilder builder = JsonFactory.builder()
- .streamReadConstraints(constraints)
- .enable(StreamReadFeature.STRICT_DUPLICATE_DETECTION)
- .disable(StreamReadFeature.AUTO_CLOSE_SOURCE);
+ StreamReadConstraints constraints = StreamReadConstraints.builder().maxNestingDepth(MAXIMUM_DEPTH)
+ .maxDocumentLength(MAXIMUM_DOCUMENT_BYTES).maxTokenCount(8_192).maxNumberLength(20)
+ .maxStringLength(MAXIMUM_STRING_UTF8_BYTES).maxNameLength(64).build();
+ JsonFactoryBuilder builder = JsonFactory.builder().streamReadConstraints(constraints)
+ .enable(StreamReadFeature.STRICT_DUPLICATE_DETECTION).disable(StreamReadFeature.AUTO_CLOSE_SOURCE);
for (JsonReadFeature feature : JsonReadFeature.values()) {
builder.disable(feature);
}
@@ -196,8 +187,8 @@ public final class CertificateProfileDocumentCodec {
}
private static void preflight(byte[] encodedDocument) {
- try (JsonParser parser = JSON_FACTORY.createParser(ObjectReadContext.empty(),
- encodedDocument, 0, encodedDocument.length)) {
+ try (JsonParser parser = JSON_FACTORY.createParser(ObjectReadContext.empty(), encodedDocument, 0,
+ encodedDocument.length)) {
while (parser.nextToken() != null) {
parser.finishToken();
}
@@ -224,12 +215,9 @@ public final class CertificateProfileDocumentCodec {
if (document.profileVersion <= 0) {
throw failure("PROFILE_VERSION_INVALID", "$.profileVersion");
}
- validateProfileString(document.profileId, MAXIMUM_PROFILE_ID_UTF8_BYTES, "$.profileId",
- "TOKEN_INVALID");
- validateProfileString(document.formatId, MAXIMUM_FORMAT_ID_UTF8_BYTES, "$.formatId",
- "TOKEN_INVALID");
- validateProfileString(document.displayName, MAXIMUM_DISPLAY_NAME_UTF8_BYTES, "$.displayName",
- "TOKEN_INVALID");
+ validateProfileString(document.profileId, MAXIMUM_PROFILE_ID_UTF8_BYTES, "$.profileId", "TOKEN_INVALID");
+ validateProfileString(document.formatId, MAXIMUM_FORMAT_ID_UTF8_BYTES, "$.formatId", "TOKEN_INVALID");
+ validateProfileString(document.displayName, MAXIMUM_DISPLAY_NAME_UTF8_BYTES, "$.displayName", "TOKEN_INVALID");
requirePolicyFields(document.certificateType, document.seen);
return constructDefinition(document);
}
@@ -259,8 +247,7 @@ public final class CertificateProfileDocumentCodec {
}
case "displayName" -> {
document.seen = mark(document.seen, 5, "$.displayName");
- document.displayName =
- readBoundedString(parser, "$.displayName", MAXIMUM_DISPLAY_NAME_UTF8_BYTES);
+ document.displayName = readBoundedString(parser, "$.displayName", MAXIMUM_DISPLAY_NAME_UTF8_BYTES);
}
case "maxValidity" -> {
document.seen = mark(document.seen, 6, "$.maxValidity");
@@ -277,28 +264,23 @@ public final class CertificateProfileDocumentCodec {
}
}
- private static void readDocumentSan(JsonParser parser, DocumentFields document)
- throws JacksonException {
- if (document.certificateType != null
- && document.certificateType != CertificateProfileKind.END_ENTITY) {
+ private static void readDocumentSan(JsonParser parser, DocumentFields document) throws JacksonException {
+ if (document.certificateType != null && document.certificateType != CertificateProfileKind.END_ENTITY) {
throw failure("FIELD_FORBIDDEN_FOR_CERTIFICATE_TYPE", "$.subjectAlternativeNames");
}
document.seen = mark(document.seen, 8, "$.subjectAlternativeNames");
document.san = readSan(parser, "$.subjectAlternativeNames");
}
- private static void readDocumentLeaf(JsonParser parser, DocumentFields document)
- throws JacksonException {
- if (document.certificateType != null
- && document.certificateType != CertificateProfileKind.END_ENTITY) {
+ private static void readDocumentLeaf(JsonParser parser, DocumentFields document) throws JacksonException {
+ if (document.certificateType != null && document.certificateType != CertificateProfileKind.END_ENTITY) {
throw failure("FIELD_FORBIDDEN_FOR_CERTIFICATE_TYPE", "$.leafCertificate");
}
document.seen = mark(document.seen, 9, "$.leafCertificate");
document.leaf = readLeaf(parser, "$.leafCertificate");
}
- private static void readDocumentCa(JsonParser parser, DocumentFields document)
- throws JacksonException {
+ private static void readDocumentCa(JsonParser parser, DocumentFields document) throws JacksonException {
if (document.certificateType == CertificateProfileKind.END_ENTITY) {
throw failure("FIELD_FORBIDDEN_FOR_CERTIFICATE_TYPE", "$.caCertificate");
}
@@ -328,33 +310,30 @@ public final class CertificateProfileDocumentCodec {
}
/*
- * Typed policy constructors are the authoritative semantic validators, so
- * their validation exceptions are deliberately normalized at this boundary.
+ * Typed policy constructors are the authoritative semantic validators, so their
+ * validation exceptions are deliberately normalized at this boundary.
*/
@SuppressWarnings("PMD.ExceptionAsFlowControl")
private static CertificateProfileDefinition constructDefinition(DocumentFields document) {
try {
- SubjectPolicy subjectPolicy = new SubjectPolicy(document.subject.allowEmpty(),
- document.subject.rules());
+ SubjectPolicy subjectPolicy = new SubjectPolicy(document.subject.allowEmpty(), document.subject.rules());
CertificatePolicy policy;
if (document.certificateType == CertificateProfileKind.END_ENTITY) {
- SubjectAlternativeNamePolicy sanPolicy = new SubjectAlternativeNamePolicy(
- document.san.minimumTotal(), document.san.maximumTotal(), document.san.rules(),
- document.san.wildcardAllowed(), document.san.allowedSchemes(),
- document.san.criticalWhenSubjectNonEmpty(),
+ SubjectAlternativeNamePolicy sanPolicy = new SubjectAlternativeNamePolicy(document.san.minimumTotal(),
+ document.san.maximumTotal(), document.san.rules(), document.san.wildcardAllowed(),
+ document.san.allowedSchemes(), document.san.criticalWhenSubjectNonEmpty(),
document.san.serviceIdentityRequired(), document.san.emailIdentityRequired());
if (document.subject.allowEmpty() && document.san.minimumTotal() < 1) {
throw new IllegalArgumentException("An empty subject requires at least one SAN");
}
policy = new LeafCertificatePolicy(sanPolicy, document.leaf.keyUsage(),
document.leaf.extendedKeyUsage(), document.leaf.keyUsageCritical(),
- document.leaf.extendedKeyUsageCritical(),
- document.leaf.basicConstraintsCritical(),
+ document.leaf.extendedKeyUsageCritical(), document.leaf.basicConstraintsCritical(),
document.leaf.allowedKeyAlgorithms());
} else {
policy = new CaCertificatePolicy(document.ca.basicConstraintsCritical(),
- document.ca.pathLengthConstraint(), document.ca.keyUsageCritical(),
- document.ca.keyUsages(), document.ca.allowedKeyAlgorithms());
+ document.ca.pathLengthConstraint(), document.ca.keyUsageCritical(), document.ca.keyUsages(),
+ document.ca.allowedKeyAlgorithms());
}
return new CertificateProfileDefinition(document.certificateType, document.profileId,
document.profileVersion, new FormatId(document.formatId), document.displayName,
@@ -500,8 +479,8 @@ public final class CertificateProfileDocumentCodec {
}
}
requireAll(seen, 6, path);
- return new SanSection(minimum, maximum, serviceRequired, emailRequired, critical,
- rules.rules(), rules.wildcardAllowed(), rules.allowedSchemes());
+ return new SanSection(minimum, maximum, serviceRequired, emailRequired, critical, rules.rules(),
+ rules.wildcardAllowed(), rules.allowedSchemes());
}
private static SanRules readSanRules(JsonParser parser, String path) throws JacksonException {
@@ -572,8 +551,7 @@ public final class CertificateProfileDocumentCodec {
SubjectAlternativeNameType type = parseSanType(typeValue, path + ".type");
validateSanShape(type, seen, path);
try {
- SubjectAlternativeNameRule rule = new SubjectAlternativeNameRule(type, minimum, maximum,
- ipv4, ipv6);
+ SubjectAlternativeNameRule rule = new SubjectAlternativeNameRule(type, minimum, maximum, ipv4, ipv6);
return new ParsedSanRule(rule, wildcard, schemes == null ? Set.of() : schemes);
} catch (IllegalArgumentException ex) {
throw failure("SEMANTIC_INVALID", path);
@@ -601,10 +579,8 @@ public final class CertificateProfileDocumentCodec {
Set values = new LinkedHashSet<>();
while (parser.nextToken() != JsonToken.END_ARRAY) {
checkArrayBound(values.size(), path);
- String value = readBoundedString(parser, path + "[" + values.size() + "]",
- MAXIMUM_URI_SCHEME_ASCII_BYTES);
- if (!isAscii(value) || !value.equals(value.toLowerCase(java.util.Locale.ROOT))
- || !values.add(value)) {
+ String value = readBoundedString(parser, path + "[" + values.size() + "]", MAXIMUM_URI_SCHEME_ASCII_BYTES);
+ if (!isAscii(value) || !value.equals(value.toLowerCase(java.util.Locale.ROOT)) || !values.add(value)) {
throw failure("TOKEN_INVALID", path);
}
}
@@ -653,8 +629,7 @@ public final class CertificateProfileDocumentCodec {
}
}
requireAll(seen, 6, path);
- return new LeafSection(basicCritical, keyCritical, keyUsage, extendedCritical, extended,
- algorithms);
+ return new LeafSection(basicCritical, keyCritical, keyUsage, extendedCritical, extended, algorithms);
}
private static Set readKeyUsages(JsonParser parser, String path) throws JacksonException {
@@ -716,8 +691,7 @@ public final class CertificateProfileDocumentCodec {
return new CaSection(basicCritical, pathLength, keyCritical, keyUsages, algorithms);
}
- private static Set readCaKeyUsages(JsonParser parser, String path)
- throws JacksonException {
+ private static Set readCaKeyUsages(JsonParser parser, String path) throws JacksonException {
requireToken(parser.currentToken(), JsonToken.START_ARRAY, path);
Set values = EnumSet.noneOf(CaKeyUsage.class);
while (parser.nextToken() != JsonToken.END_ARRAY) {
@@ -793,16 +767,14 @@ public final class CertificateProfileDocumentCodec {
generator.writeEndObject();
}
- private static void writeSubject(JsonGenerator generator, SubjectPolicy policy)
- throws JacksonException {
+ private static void writeSubject(JsonGenerator generator, SubjectPolicy policy) throws JacksonException {
generator.writeObjectPropertyStart("subject");
generator.writeBooleanProperty("allowEmpty", policy.allowEmpty());
generator.writeArrayPropertyStart("rules");
for (SubjectRdnRule rule : policy.rules()) {
generator.writeStartObject();
generator.writeStringProperty("oid", rule.type().oid());
- generator.writeStringProperty("source",
- rule.requesterSupplied() ? REQUESTER_SOURCE : PROFILE_FIXED_SOURCE);
+ generator.writeStringProperty("source", rule.requesterSupplied() ? REQUESTER_SOURCE : PROFILE_FIXED_SOURCE);
generator.writeNumberProperty("minimumOccurrences", rule.minimumOccurrences());
generator.writeNumberProperty("maximumOccurrences", rule.maximumOccurrences());
generator.writeNumberProperty("maximumUtf8Bytes", rule.maximumUtf8Bytes());
@@ -815,15 +787,13 @@ public final class CertificateProfileDocumentCodec {
generator.writeEndObject();
}
- private static void writeSan(JsonGenerator generator, SubjectAlternativeNamePolicy policy)
- throws JacksonException {
+ private static void writeSan(JsonGenerator generator, SubjectAlternativeNamePolicy policy) throws JacksonException {
generator.writeObjectPropertyStart("subjectAlternativeNames");
generator.writeNumberProperty("minimumTotal", policy.minimumTotal());
generator.writeNumberProperty("maximumTotal", policy.maximumTotal());
generator.writeBooleanProperty("serviceIdentityRequired", policy.requireServiceIdentity());
generator.writeBooleanProperty("emailIdentityRequired", policy.requireEmailIdentity());
- generator.writeBooleanProperty("criticalWhenSubjectNonEmpty",
- policy.criticalWithNonemptySubject());
+ generator.writeBooleanProperty("criticalWhenSubjectNonEmpty", policy.criticalWithNonemptySubject());
generator.writeArrayPropertyStart("rules");
List rules = policy.rules().stream()
.sorted(Comparator.comparing(rule -> rule.type().name())).toList();
@@ -833,14 +803,12 @@ public final class CertificateProfileDocumentCodec {
generator.writeNumberProperty("minimumOccurrences", rule.minimum());
generator.writeNumberProperty("maximumOccurrences", rule.maximum());
switch (rule.type()) {
- case DNS_NAME -> generator.writeBooleanProperty("wildcardAllowed",
- policy.allowDnsWildcard());
+ case DNS_NAME -> generator.writeBooleanProperty("wildcardAllowed", policy.allowDnsWildcard());
case IP_ADDRESS -> {
generator.writeBooleanProperty("ipv4Allowed", rule.allowIpv4());
generator.writeBooleanProperty("ipv6Allowed", rule.allowIpv6());
}
- case URI -> writeSortedStrings(generator, "allowedSchemes",
- policy.allowedUriSchemes());
+ case URI -> writeSortedStrings(generator, "allowedSchemes", policy.allowedUriSchemes());
case RFC822_NAME -> {
// No type-specific fields.
}
@@ -851,39 +819,30 @@ public final class CertificateProfileDocumentCodec {
generator.writeEndObject();
}
- private static void writeLeaf(JsonGenerator generator, LeafCertificatePolicy policy)
- throws JacksonException {
+ private static void writeLeaf(JsonGenerator generator, LeafCertificatePolicy policy) throws JacksonException {
generator.writeObjectPropertyStart("leafCertificate");
- generator.writeBooleanProperty("basicConstraintsCritical",
- policy.basicConstraintsCritical());
+ generator.writeBooleanProperty("basicConstraintsCritical", policy.basicConstraintsCritical());
generator.writeBooleanProperty("keyUsageCritical", policy.keyUsageCritical());
- writeSortedStrings(generator, "keyUsage",
- policy.keyUsages().stream().map(Enum::name).toList());
- generator.writeBooleanProperty("extendedKeyUsageCritical",
- policy.extendedKeyUsageCritical());
+ writeSortedStrings(generator, "keyUsage", policy.keyUsages().stream().map(Enum::name).toList());
+ generator.writeBooleanProperty("extendedKeyUsageCritical", policy.extendedKeyUsageCritical());
writeSortedStrings(generator, "extendedKeyUsage",
policy.extendedKeyUsages().stream().map(ExtendedKeyUsageId::oid).toList());
- writeSortedStrings(generator, "allowedKeyAlgorithms",
- policy.allowedSubjectKeyAlgorithmIds());
+ writeSortedStrings(generator, "allowedKeyAlgorithms", policy.allowedSubjectKeyAlgorithmIds());
generator.writeEndObject();
}
- private static void writeCa(JsonGenerator generator, CaCertificatePolicy policy)
- throws JacksonException {
+ private static void writeCa(JsonGenerator generator, CaCertificatePolicy policy) throws JacksonException {
generator.writeObjectPropertyStart("caCertificate");
- generator.writeBooleanProperty("basicConstraintsCritical",
- policy.basicConstraintsCritical());
+ generator.writeBooleanProperty("basicConstraintsCritical", policy.basicConstraintsCritical());
generator.writeNumberProperty("pathLengthConstraint", policy.pathLengthConstraint());
generator.writeBooleanProperty("keyUsageCritical", policy.keyUsageCritical());
- writeSortedStrings(generator, "keyUsages",
- policy.keyUsages().stream().map(Enum::name).toList());
- writeSortedStrings(generator, "allowedSubjectKeyAlgorithms",
- policy.allowedSubjectKeyAlgorithmIds());
+ writeSortedStrings(generator, "keyUsages", policy.keyUsages().stream().map(Enum::name).toList());
+ writeSortedStrings(generator, "allowedSubjectKeyAlgorithms", policy.allowedSubjectKeyAlgorithmIds());
generator.writeEndObject();
}
- private static void writeSortedStrings(JsonGenerator generator, String field,
- java.util.Collection values) throws JacksonException {
+ private static void writeSortedStrings(JsonGenerator generator, String field, java.util.Collection values)
+ throws JacksonException {
generator.writeArrayPropertyStart(field);
for (String value : values.stream().sorted().toList()) {
generator.writeString(value);
@@ -895,20 +854,19 @@ public final class CertificateProfileDocumentCodec {
if (definition == null) {
throw failure("CANONICALIZATION_FAILED", "$");
}
- validateProfileString(definition.profileId(), MAXIMUM_PROFILE_ID_UTF8_BYTES,
- "$.profileId", "CANONICALIZATION_FAILED");
- validateProfileString(definition.formatId().value(), MAXIMUM_FORMAT_ID_UTF8_BYTES,
- "$.formatId", "CANONICALIZATION_FAILED");
- validateProfileString(definition.displayName(), MAXIMUM_DISPLAY_NAME_UTF8_BYTES,
- "$.displayName", "CANONICALIZATION_FAILED");
- validateWritableString(definition.maximumValidity().toString(), MAXIMUM_STRING_UTF8_BYTES,
- "$.maxValidity");
+ validateProfileString(definition.profileId(), MAXIMUM_PROFILE_ID_UTF8_BYTES, "$.profileId",
+ "CANONICALIZATION_FAILED");
+ validateProfileString(definition.formatId().value(), MAXIMUM_FORMAT_ID_UTF8_BYTES, "$.formatId",
+ "CANONICALIZATION_FAILED");
+ validateProfileString(definition.displayName(), MAXIMUM_DISPLAY_NAME_UTF8_BYTES, "$.displayName",
+ "CANONICALIZATION_FAILED");
+ validateWritableString(definition.maximumValidity().toString(), MAXIMUM_STRING_UTF8_BYTES, "$.maxValidity");
if (definition.subjectPolicy().rules().size() > MAXIMUM_ARRAY_ELEMENTS) {
throw failure("CANONICALIZATION_FAILED", "$");
}
for (SubjectRdnRule rule : definition.subjectPolicy().rules()) {
- rule.fixedValue().ifPresent(value -> validateWritableString(value,
- MAXIMUM_STRING_UTF8_BYTES, "$.subject.rules.fixedValue"));
+ rule.fixedValue().ifPresent(
+ value -> validateWritableString(value, MAXIMUM_STRING_UTF8_BYTES, "$.subject.rules.fixedValue"));
}
if (definition.certificateType() != CertificateProfileKind.END_ENTITY) {
CaCertificatePolicy ca = definition.caPolicy();
@@ -920,8 +878,7 @@ public final class CertificateProfileDocumentCodec {
}
LeafCertificatePolicy leaf = definition.leafPolicy();
if (leaf.subjectAlternativeNamePolicy().rules().size() > MAXIMUM_ARRAY_ELEMENTS
- || leaf.subjectAlternativeNamePolicy().allowedUriSchemes().size()
- > MAXIMUM_ARRAY_ELEMENTS
+ || leaf.subjectAlternativeNamePolicy().allowedUriSchemes().size() > MAXIMUM_ARRAY_ELEMENTS
|| leaf.keyUsages().size() > MAXIMUM_ARRAY_ELEMENTS
|| leaf.extendedKeyUsages().size() > MAXIMUM_ARRAY_ELEMENTS
|| leaf.allowedSubjectKeyAlgorithmIds().size() > MAXIMUM_ARRAY_ELEMENTS) {
@@ -931,13 +888,11 @@ public final class CertificateProfileDocumentCodec {
validateWritableString(scheme, MAXIMUM_URI_SCHEME_ASCII_BYTES,
"$.subjectAlternativeNames.rules.allowedSchemes");
if (!isAscii(scheme)) {
- throw failure("CANONICALIZATION_FAILED",
- "$.subjectAlternativeNames.rules.allowedSchemes");
+ throw failure("CANONICALIZATION_FAILED", "$.subjectAlternativeNames.rules.allowedSchemes");
}
}
for (ExtendedKeyUsageId usage : leaf.extendedKeyUsages()) {
- validateWritableString(usage.oid(), MAXIMUM_STRING_UTF8_BYTES,
- "$.leafCertificate.extendedKeyUsage");
+ validateWritableString(usage.oid(), MAXIMUM_STRING_UTF8_BYTES, "$.leafCertificate.extendedKeyUsage");
}
}
@@ -947,10 +902,9 @@ public final class CertificateProfileDocumentCodec {
}
}
- private static void validateProfileString(String value, int maximum, String path,
- String failureCode) {
- if (value == null || value.isBlank() || !value.equals(value.strip())
- || hasUnpairedSurrogate(value) || utf8Length(value) > maximum) {
+ private static void validateProfileString(String value, int maximum, String path, String failureCode) {
+ if (value == null || value.isBlank() || !value.equals(value.strip()) || hasUnpairedSurrogate(value)
+ || utf8Length(value) > maximum) {
throw failure(failureCode, path);
}
}
@@ -1021,8 +975,7 @@ public final class CertificateProfileDocumentCodec {
}
}
- private static CertificateProfileKind readCertificateType(JsonParser parser, String path)
- throws JacksonException {
+ private static CertificateProfileKind readCertificateType(JsonParser parser, String path) throws JacksonException {
String token = readString(parser, path);
try {
return CertificateProfileKind.valueOf(token);
@@ -1102,8 +1055,8 @@ public final class CertificateProfileDocumentCodec {
}
private static boolean hasUnpairedSurrogate(String value) {
- return value.codePoints().anyMatch(codePoint ->
- codePoint >= Character.MIN_SURROGATE && codePoint <= Character.MAX_SURROGATE);
+ return value.codePoints()
+ .anyMatch(codePoint -> codePoint >= Character.MIN_SURROGATE && codePoint <= Character.MAX_SURROGATE);
}
private static boolean isAscii(String value) {
@@ -1116,13 +1069,11 @@ public final class CertificateProfileDocumentCodec {
}
private static boolean isAllowedAlgorithm(String value) {
- return "RSA".equals(value) || "ECDSA".equals(value)
- || "Ed25519".equals(value) || "Ed448".equals(value);
+ return "RSA".equals(value) || "ECDSA".equals(value) || "Ed25519".equals(value) || "Ed448".equals(value);
}
private static boolean hasUtf8Bom(byte[] value) {
- return value.length >= 3 && value[0] == (byte) 0xef
- && value[1] == (byte) 0xbb && value[2] == (byte) 0xbf;
+ return value.length >= 3 && value[0] == (byte) 0xef && value[1] == (byte) 0xbb && value[2] == (byte) 0xbf;
}
private static boolean isDuplicateFailure(JacksonException exception) {
@@ -1154,26 +1105,23 @@ public final class CertificateProfileDocumentCodec {
}
private record SanSection(int minimumTotal, int maximumTotal, boolean serviceIdentityRequired,
- boolean emailIdentityRequired, boolean criticalWhenSubjectNonEmpty,
- List rules, boolean wildcardAllowed,
- Set allowedSchemes) {
+ boolean emailIdentityRequired, boolean criticalWhenSubjectNonEmpty, List rules,
+ boolean wildcardAllowed, Set allowedSchemes) {
}
private record SanRules(List rules, boolean wildcardAllowed,
Set