Class AuthenticatedSdk
- All Implemented Interfaces:
AutoCloseable
This class represents an authenticated session with the ANKASecure© API. Each instance is bound to a specific JWT access token and provides all cryptographic operations available to that authenticated identity.
Thread Safety
Fully thread-safe. Instances are immutable and can be safely shared across thousands of concurrent threads. The underlying HTTP client uses connection pooling and HTTP/2 multiplexing for efficient resource usage.
Lifecycle Management
Instances are created by AnkaSecureSdk.authenticateApplication(String, co.ankatech.ankasecure.sdk.security.SecretChars)
or AnkaSecureSdk.authenticateUser(String, co.ankatech.ankasecure.sdk.security.SecretChars, String). They remain
valid until the token expires. Use isTokenExpiredLocally() to check validity.
Token Expiry Handling
AuthenticatedSdk sdk = factory.authenticateApplication(clientId, clientSecret);
// Use for multiple operations
EncryptResult r1 = sdk.encrypt("key1", data1);
EncryptResult r2 = sdk.encrypt("key2", data2);
// Check expiry before long-running tasks
if (sdk.isTokenExpiredLocally()) {
sdk = factory.authenticateApplication(clientId, clientSecret);
}
// Continue with new token
EncryptResult r3 = sdk.encrypt("key3", data3);
Concurrent Usage Pattern
// Single AuthenticatedSdk shared across all threads
AuthenticatedSdk sdk = factory.authenticateApplication(clientId, clientSecret);
// Virtual threads (Java 21+) - 10,000+ concurrent operations
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
List<CompletableFuture<EncryptResult>> futures = dataList.stream()
.map(data -> CompletableFuture.supplyAsync(
() -> sdk.encrypt("my-key", data),
executor
))
.toList();
List<EncryptResult> results = futures.stream()
.map(CompletableFuture::join)
.toList();
}
Memory Characteristics
- Instance size: ~250 bytes (token string + references)
- Shared HTTP client: single connection pool across all instances
- 10,000 instances: ~2.5 MB total overhead
File-Output Overwrite Policy
Every file-output method (the *File, *FileCompact, *FileStream and
combined/migration families) quarantines its result to a sidecar (<output>.part) and
atomically renames it onto output. By default
(OverwritePolicy.FAIL_IF_EXISTS) an operation fails if output already exists,
throwing DestinationExistsException and leaving the
pre-existing file untouched. To replace an existing destination, derive an overwrite-enabled
instance with withOverwrite() (or
withOverwritePolicy(OverwritePolicy.OVERWRITE)); the
derived instance shares this instance's JWT and HTTP client with no re-authentication.
- Since:
- 3.0.0
- Author:
- ANKATech Solutions Inc.
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionco.ankatech.secure.client.model.Pkcs7AnalysisResponseanalyzePkcs7(co.ankatech.secure.client.model.Pkcs7AnalysisRequest request) Analyzes a PKCS#7 file to extract metadata and certificate information.co.ankatech.secure.client.model.Pkcs7AnalysisResponseanalyzePkcs7Stream(co.ankatech.secure.client.model.Pkcs7AnalysisStreamRequest metadata, File file) Analyzes a PKCS#7 file using streaming to avoid loading the entire file into memory.voidclose()SDK-006 (secure-memory-cutover Slice 4): clears the bearer token from the underlyingAnkaSecureOpenApiClient'sHttpBearerAuth.co.ankatech.secure.client.model.Pkcs7ConversionResponseconvertPkcs7ToJose(co.ankatech.secure.client.model.Pkcs7ConversionRequest request) Converts a PKCS#7 signature to JOSE (JWS) format.convertPkcs7ToJoseStream(co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest metadata, File inputFile, File outputFile) Converts a PKCS#7 signature to JOSE using streaming.Decrypts a compact JWE (RFC 7516) token to recover the original plaintext.decryptFile(Path input, Path output) Decrypts a file.decryptFileCompact(Path input, Path output) Decrypts a file with forced compact format.decryptFileStream(Path input, Path output) Decrypts a file with forced streaming format.decryptThenVerify(String jweToken) Decrypts a JWE then verifies the inner JWS signature.decryptThenVerifyFileCompact(Path input, Path output) Decrypts and verifies a nested JWE(JWS) file with forced compact format.decryptThenVerifyFileStream(Path input, Path output) Decrypts a nested JWE(JWS) file then verifies the inner signature in streaming mode — the large-file counterpart ofdecryptThenVerifyFileCompact(Path, Path), and the inverse ofsignThenEncryptFileStream(String, String, Path, Path).Encrypts raw bytes using the key identified bykid.encryptFile(String kid, Path input, Path output) Encrypts a file.encryptFileCompact(String kid, Path input, Path output) Encrypts a file with forced compact format.encryptFileStream(String kid, Path input, Path output) Encrypts a file with forced streaming format.Encrypts a file using a provided public key (without requiring key in ANKASecure).getKeyMetadata(String kid) Retrieves metadata for a specific key.Retrieves the complete list of cryptographic algorithms supported by the server.Retrieves cryptographic algorithms matching the specified filter criteria.Extracts the expiration time from the JWT token.booleanisClosed()booleanChecks whether the access token has expired according to its localexpclaim only.listAllKeys(KeyFilters filters) Lists ALL keys matching the filters by auto-paginating through the server's paginated listing (the AWS-CLI pattern: the API pages, the client iterates).listKeys(KeyFilters filters, int page, int size) Lists ONE PAGE of the keys accessible to the authenticated client.Returns the file-output overwrite policy in effect for this instance.performMigrationWorkflow(File pkcs7File, co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest conversionRequest, File outputFile) Performs a complete PKCS#7-to-JOSE migration workflow with analysis and conversion.Re-encrypts data with a different key without decrypting to plaintext.reencryptFile(String newKid, Path input, Path output) Re-encrypts a file.reencryptFileCompact(String newKid, Path input, Path output) Re-encrypts a file with forced compact format.reencryptFileStream(String newKid, String sourceKidOverride, Path input, Path output) Re-encrypts a file with forced streaming format.Re-signs data with a different key without verifying the original signature.resign(String newKid, String jws, JwsSerialization serialization) Re-signs a JWS, explicitly selecting the JWS serialization (PRD §60).resignFileCompact(String newKid, Path input, Path output) Re-signs a compact JWS file with forced compact format.resignFileCompact(String newKid, Path input, Path output, JwsSerialization serialization) Re-signs a JWS file (attached), explicitly selecting the JWS serialization (PRD §60).resignFileStream(Path oldJwsHeader, String newKid, Path input, Path output) Re-signs a detached JWS signature with forced streaming format.Signs raw bytes using the key identified bykid.sign(String kid, byte[] data, JwsSerialization serialization) Signs raw bytes, explicitly selecting the JWS serialization (PRD §60).Signs a file.signFileCompact(String kid, Path input, Path output) Signs a file with forced compact format.signFileCompact(String kid, Path input, Path output, JwsSerialization serialization) Signs a file (attached), explicitly selecting the JWS serialization (PRD §60).signFileStream(String kid, Path input, Path output) Signs a file with forced streaming format.signThenEncrypt(String signKid, String encryptKid, byte[] data) Signs then encrypts data in a single operation (nested JWE containing JWS).signThenEncrypt(String signKid, String encryptKid, byte[] data, JwsSerialization serialization) Signs then encrypts, explicitly selecting the inner-JWS serialization (PRD §60).signThenEncryptFileCompact(String signKid, String encryptKid, Path input, Path output) Signs then encrypts a file with forced compact format.signThenEncryptFileCompact(String signKid, String encryptKid, Path input, Path output, JwsSerialization serialization) Signs a file then encrypts it, explicitly selecting the inner-JWS serialization (PRD §60).signThenEncryptFileStream(String signKid, String encryptKid, Path input, Path output) Signs a file then encrypts it in streaming mode (nested JWE(JWS), bounded memory) — the large-file counterpart ofsignThenEncryptFileCompact(String, String, Path, Path).verifySignature(String jws) Verifies a compact JWS (RFC 7515) signature.verifySignature(Path jwsFile) Verifies a JWS signature from a file, accepting either the compact form or the JWS-JSON form (serialization-agnostic; PRD §60).verifySignatureStream(Path dataFile, Path signatureFile) Verifies a detached JWS signature with forced streaming format.verifySignatureUtilityStream(String kty, String alg, String publicKeyB64, String signatureB64, Path dataFile) Verifies a signature using a provided public key (without requiring key in ANKASecure).Convenience wither equivalent towithOverwritePolicy(OverwritePolicy.OVERWRITE): returns a NEW immutableAuthenticatedSdkwhose file-output operations atomically replace an existing destination.withOverwritePolicy(OverwritePolicy overwritePolicy) Returns a NEW immutableAuthenticatedSdkthat appliesoverwritePolicyto every file-output operation, sharing this instance's JWT and HTTP client.
-
Method Details
-
close
public void close()SDK-006 (secure-memory-cutover Slice 4): clears the bearer token from the underlyingAnkaSecureOpenApiClient'sHttpBearerAuth. After this call:- Subsequent operations on this instance throw
IllegalStateException. - The bearer token is no longer reachable via the OkHttp request chain.
Idempotent. Use try-with-resources for deterministic cleanup:
try (AuthenticatedSdk sdk = factory.authenticateApplication(clientId, secret)) { sdk.encrypt(...); } // close() runs here, clearing the bearer tokenNote: the
accessTokenfield is aString(immutable, interned-eligible) and cannot be reliably zeroized — this is documented in SECURE_MEMORY.md as a known JVM-level limitation.close()reduces the in-memory lifetime by clearing the OkHttp interceptor reference, but theStringitself remains until GC.Wither ownership (security REQ-3.x)
Instances derived via
withOverwritePolicy(OverwritePolicy)/withOverwrite()SHARE the root's single bearer token and HTTP client. Only the factory-created ROOT owns the token: closing a DERIVED instance marks that instance closed but MUST NOT clear the token still in use by the root (and by any sibling derived instance), preventing a use-after-free of a zeroized secret. Closing the ROOT clears the shared token, ending the session for all views.- Specified by:
closein interfaceAutoCloseable
- Subsequent operations on this instance throw
-
overwritePolicy
Returns the file-output overwrite policy in effect for this instance.- Returns:
- the
OverwritePolicy(defaultOverwritePolicy.FAIL_IF_EXISTS) - Since:
- 3.0.0
- See Also:
-
withOverwritePolicy
Returns a NEW immutableAuthenticatedSdkthat appliesoverwritePolicyto every file-output operation, sharing this instance's JWT and HTTP client.This is a pure, local, immutable derivation: it performs NO network round-trip and NO re-authentication. The derived instance shares the SAME JWT reference and the SAME HTTP client (there is no plaintext copy of the token). Per the wither ownership model, only the original factory-created instance owns the token —
closingthe derived instance never clears the token still in use by the original (security REQ-3.x).- Parameters:
overwritePolicy- the overwrite policy for the derived instance; must not benull- Returns:
- a distinct immutable instance with the requested policy; never
null - Throws:
NullPointerException- ifoverwritePolicyisnull- Since:
- 3.0.0
- See Also:
-
withOverwrite
Convenience wither equivalent towithOverwritePolicy(OverwritePolicy.OVERWRITE): returns a NEW immutableAuthenticatedSdkwhose file-output operations atomically replace an existing destination.Like
withOverwritePolicy(OverwritePolicy), this performs NO network round-trip and NO re-authentication and shares the same JWT and HTTP client (see the wither ownership model).- Returns:
- a distinct immutable instance with
OverwritePolicy.OVERWRITE; nevernull - Since:
- 3.0.0
- See Also:
-
isClosed
public boolean isClosed()- Returns:
trueifclose()has been called; never throws
-
isTokenExpiredLocally
public boolean isTokenExpiredLocally()Checks whether the access token has expired according to its localexpclaim only.This is a local, offline check. It extracts the
expclaim from the JWT payload and compares it with the current time; it does NOT contact the server and therefore does NOT detect server-side revocation — a token that was revoked (logout / blacklist) or superseded by the subject's revocation epoch (bulk revoke, e.g. an admin force-reset, a suspend/delete, or a role scope shrink) is still unexpired locally and returnsfalsehere while the server rejects it. To detect that case, perform an operation and handleTokenRevokedException(thrown on a 401), then re-authenticate.Usage Pattern
AuthenticatedSdk sdk = factory.authenticateApplication(id, secret); // Before an expensive batch operation, cheaply skip a definitely-expired token if (sdk.isTokenExpiredLocally()) { sdk = factory.authenticateApplication(id, secret); } try { processBatch(sdk, largeDataset); } catch (TokenRevokedException revoked) { // The server rejected the still-unexpired token — re-authenticate and retry. sdk = factory.authenticateApplication(id, secret); }- Returns:
trueif the token is locally expired or malformed,falseif still valid by its localexpclaim (which does not imply the server will accept it)
-
getTokenExpiration
Extracts the expiration time from the JWT token.Decodes the JWT payload (Base64URL) and reads the
expclaim (seconds since Unix epoch). Returnsnullif the token is malformed.- Returns:
- the token expiration as
Instant, ornullif malformed
-
encrypt
Encrypts raw bytes using the key identified bykid.The key type determines the algorithm automatically: asymmetric keys (ML-KEM, RSA, ECC) perform key encapsulation + symmetric encryption; symmetric keys (AES) encrypt directly. The result is a compact JWE (RFC 7516) string containing the ciphertext and all metadata needed for decryption.
This method is suitable for in-memory payloads up to ~100 MB. For larger files, use
encryptFileStream(String, Path, Path)to avoid loading the entire payload into memory.Example
byte[] plaintext = "Sensitive data".getBytes(StandardCharsets.UTF_8); EncryptResult result = sdk.encrypt("my-ml-kem-768-key", plaintext); // The JWE token is self-contained and can be stored or transmitted String jweToken = result.getJweToken(); // Decrypt later DecryptResult decrypted = sdk.decrypt(jweToken); byte[] recovered = decrypted.getDecryptedData();- Parameters:
kid- key identifier referencing a key stored in ANKASecure©; must not benullplaintext- the raw bytes to encrypt; must not benull- Returns:
- encryption result containing the JWE token and operation metadata;
never
null - Throws:
AnkaSecureSdkException- if the key identified bykiddoes not exist, does not support encryption, the authenticated client lacks permission, or the server returns an errorNullPointerException- ifkidorplaintextisnull- Since:
- 3.0.0
- See Also:
-
encryptFileCompact
public EncryptResult encryptFileCompact(String kid, Path input, Path output) throws AnkaSecureSdkException Encrypts a file with forced compact format. Use when you need a single-line string for API/JSON transmission. Fails if the input exceeds the server's configured compact limit (maxPlaintextBytes, default 4 MB).When to Use Compact Format
- API transmission: JSON responses, HTTP headers, query parameters
- Storage: Single database field (text/varchar)
- Interoperability: JWE standard format (RFC 7516)
Output Format
eyJhbGc...header...XVCJ9.eyJkYXRh...encrypted-payload...9.dBjftJ...tag...
Single-line base64url string, suitable for text-based transmission.
Alternative Methods
- Use
encryptFile(String, Path, Path)for automatic format selection (recommended) - Use
encryptFileStream(String, Path, Path)for large files (above the server's configured compact limit)
Example
// Encrypt small document for API transmission EncryptResult result = sdk.encryptFileCompact( "my-ml-kem-key", Path.of("contract.pdf"), Path.of("contract.jwe") ); System.out.println("Algorithm: " + result.getAlgorithmUsed());- Parameters:
kid- key identifier for encryption; must not benullinput- input file (up to the server's configured compact limit, default 4 MB); must not benulloutput- output file (.jwe recommended); must not benull- Returns:
- encryption result with metadata; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation fails- See Also:
-
encryptFile
public EncryptResult encryptFile(String kid, Path input, Path output) throws AnkaSecureSdkException, IOException Encrypts a file. Recommended for most use cases. Automatically selects the optimal format based on the server-discovered compact payload limit (below the limit = compact, at or above = streaming).This method automatically selects the optimal format:
- Files below the server's
maxPlaintextBytes: Compact JWE format (single-line string) - Files at or above that limit: Streaming JWE format (binary chunks)
Why Use This Method?
You don't need to worry about file sizes or server limits. The threshold is discovered from the server (not hardcoded) and cached briefly; if a compact request is still rejected as too large (HTTP 413) the SDK transparently retries via streaming, ensuring your encryption always succeeds regardless of file size.
When to Use Explicit Formats
Use
encryptFileCompact(String, Path, Path)orencryptFileStream(String, Path, Path)only when you specifically need a particular output format (e.g., compact JWE for API transmission).Example
// Encrypt any file - works for both small and large files EncryptResult result = sdk.encryptFile( "my-ml-kem-key", Path.of("data.bin"), Path.of("data.jwe") ); System.out.println("Encrypted with: " + result.getAlgorithmUsed());- Parameters:
kid- key identifier for encryption; must not benullinput- input file (any size); must not benulloutput- output file (.jwe or .jwet); must not benull- Returns:
- encryption result with metadata; never
nullBy default fails if
outputexists; callwithOverwrite()to overwrite. - Throws:
AnkaSecureSdkException- if operation failsIOException- if file cannot be accessedDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default)- See Also:
- Files below the server's
-
encryptFileStream
public EncryptResult encryptFileStream(String kid, Path input, Path output) throws AnkaSecureSdkException Encrypts a file with forced streaming format. Use for large files (100MB+), low-memory environments, or when binary output is acceptable.When to Use Streaming Format
- Large files: Files above the server's configured compact limit (required), optimal for 100MB+ (recommended)
- Memory constraints: Low-memory environments or embedded systems
- Binary output: When base64 encoding overhead is undesirable
- Progressive processing: Start processing before full upload
Output Format
Binary streaming format (.jwet file) with multipart chunks. Not suitable for text-based transmission (API/JSON).
Alternative Methods
- Use
encryptFile(String, Path, Path)for automatic format selection (recommended) - Use
encryptFileCompact(String, Path, Path)for small files (below the server's configured compact limit)
Example
// Encrypt large video file EncryptResult result = sdk.encryptFileStream( "my-ml-kem-key", Path.of("movie.mp4"), Path.of("movie.jwet") );- Parameters:
kid- key identifier for encryption; must not benullinput- input file (any size, up to 100MB recommended); must not benulloutput- output file (.jwet recommended); must not benull- Returns:
- encryption result with metadata; never
null - Throws:
AnkaSecureSdkException- if operation fails- See Also:
-
decrypt
Decrypts a compact JWE (RFC 7516) token to recover the original plaintext.The JWE token is self-contained and includes all metadata required for decryption (algorithm, encrypted key, IV, ciphertext, authentication tag). The server resolves the correct decryption key based on the
kidheader in the JWE.This method is suitable for in-memory payloads up to ~100 MB. For larger files, use
decryptFileStream(Path, Path)to avoid loading the entire payload into memory.Example
// Decrypt a previously encrypted message String jweToken = "eyJhbGciOiJNTC1LRU0tNzY4IiwiZW5jIjoiQTI1NkdDTSIsImtpZCI6Im15LWtleSJ9..."; DecryptResult result = sdk.decrypt(jweToken); byte[] plaintext = result.getDecryptedData(); String message = new String(plaintext, StandardCharsets.UTF_8); System.out.println("Decrypted using key: " + result.getMeta().getKeyRequested()); System.out.println("Algorithm: " + result.getMeta().getAlgorithmUsed());- Parameters:
ciphertextJwe- the compact JWE string to decrypt; must not benull- Returns:
- decryption result containing the plaintext bytes and operation metadata;
never
null - Throws:
AnkaSecureSdkException- if the JWE is malformed, the decryption key is not accessible to the authenticated client, decryption fails (authentication tag mismatch), or the server returns an errorNullPointerException- ifciphertextJweisnull- Since:
- 3.0.0
- See Also:
-
decryptFileCompact
public DecryptResultMetadata decryptFileCompact(Path input, Path output) throws AnkaSecureSdkException Decrypts a file with forced compact format. Use when you need to decrypt a single-line JWE string. Fails if the input exceeds the server's configured compact limit (maxPlaintextBytes, default 4 MB).When to Use Compact Format
- API transmission: Decrypting JWE from JSON responses or HTTP headers
- Storage: Decrypting from single database field (text/varchar)
- Interoperability: JWE standard format (RFC 7516)
Input Format
Expects compact JWE format (single-line base64url string). Typically created by
encryptFileCompact(String, Path, Path).Alternative Methods
- Use
decryptFile(Path, Path)for automatic format selection (recommended) - Use
decryptFileStream(Path, Path)for large files (above the server's configured compact limit)
Example
// Decrypt compact JWE file DecryptResultMetadata result = sdk.decryptFileCompact( Path.of("contract.jwe"), Path.of("contract.pdf") ); System.out.println("Decrypted using key: " + result.getKeyRequested());- Parameters:
input- compact JWE file (up to the server's configured compact limit, default 4 MB); must not benulloutput- output file for decrypted plaintext; must not benull- Returns:
- decryption result metadata; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation fails- See Also:
-
decryptFile
public DecryptResultMetadata decryptFile(Path input, Path output) throws AnkaSecureSdkException, IOException Decrypts a file. Recommended for most use cases. Automatically selects the decryption path from the input envelope's actual format, not its size.This method inspects the input file's structure and routes accordingly:
- Compact JWE (produced by
encryptFileCompact(String, Path, Path)orencryptFile(String, Path, Path)in compact mode): compact decrypt path - Streaming JWET multipart artifact (produced by
encryptFileStream(String, Path, Path)): streaming decrypt path
Why Format, Not Size?
The input here is an envelope, not plaintext. A compact JWE is roughly twice the size of the plaintext it wraps, so its size may exceed the server's compact plaintext ceiling even though it is a compact envelope that must be decrypted via the compact path. Selecting by format guarantees that any file produced by
encryptFile/encryptFileCompactis always decryptable, and that a genuinely detached/streaming artifact is always decrypted via streaming.When to Use Explicit Formats
Use
decryptFileCompact(Path, Path)ordecryptFileStream(Path, Path)only when you specifically need to force a particular input format.Example
// Decrypt any file - works for both small and large files DecryptResultMetadata result = sdk.decryptFile( Path.of("data.jwe"), Path.of("data.bin") ); System.out.println("Decrypted using key: " + result.getKeyRequested());- Parameters:
input- input JWE file (any size); must not benulloutput- output file for decrypted plaintext; must not benull- Returns:
- decryption result metadata; never
nullBy default fails if
outputexists; callwithOverwrite()to overwrite. - Throws:
AnkaSecureSdkException- if operation failsIOException- if file cannot be accessedDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default)- See Also:
- Compact JWE (produced by
-
decryptFileStream
public DecryptResultMetadata decryptFileStream(Path input, Path output) throws AnkaSecureSdkException Decrypts a file with forced streaming format. Use for large files (100MB+), low-memory environments, or when binary input is acceptable.When to Use Streaming Format
- Large files: Files above the server's configured compact limit (required), optimal for 100MB+ (recommended)
- Memory constraints: Low-memory environments or embedded systems
- Binary output: When decrypting streaming JWE format (.jwet files)
- Progressive processing: Start processing before full download
Input Format
Binary streaming format (.jwet file) with multipart chunks. Typically created by
encryptFileStream(String, Path, Path).Alternative Methods
- Use
decryptFile(Path, Path)for automatic format selection (recommended) - Use
decryptFileCompact(Path, Path)for small files (below the server's configured compact limit)
Example
// Decrypt large video file DecryptResultMetadata result = sdk.decryptFileStream( Path.of("movie.jwet"), Path.of("movie.mp4") );- Parameters:
input- streaming JWE file (any size, up to 100MB recommended); must not benulloutput- output file for decrypted plaintext; must not benull- Returns:
- decryption result metadata; never
null - Throws:
AnkaSecureSdkException- if operation fails- See Also:
-
sign
Signs raw bytes using the key identified bykid.Creates a compact JWS (RFC 7515) containing the signature and all metadata needed for verification. The signing algorithm is determined by the key type: ML-DSA, ECDSA, or RSA-PSS.
This method is suitable for in-memory payloads up to ~100 MB. For larger files, use
signFileStream(String, Path, Path)to avoid loading the entire payload into memory.Example
byte[] document = Files.readAllBytes(Path.of("/contracts/agreement.pdf")); SignResult result = sdk.sign("legal-ml-dsa-key", document); // The JWS token contains the signature and can be verified later String jwsToken = result.getJwsToken(); // Verify later VerifySignatureResult verified = sdk.verifySignature(jwsToken); if (verified.isValid()) { System.out.println("Signature verified using key: " + verified.getKeyRequested()); }- Parameters:
kid- key identifier referencing a signing key stored in ANKASecure©; must not benulldata- the raw bytes to sign; must not benull- Returns:
- signature result containing the JWS token and operation metadata;
never
null - Throws:
AnkaSecureSdkException- if the key identified bykiddoes not exist, does not support signing, the authenticated client lacks permission, or the server returns an errorNullPointerException- ifkidordataisnull- Since:
- 3.0.0
- See Also:
-
sign
public SignResult sign(String kid, byte[] data, JwsSerialization serialization) throws AnkaSecureSdkException Signs raw bytes, explicitly selecting the JWS serialization (PRD §60).Ergonomic overload of
sign(String, byte[]). PassJwsSerialization.COMPACTorJwsSerialization.JSONto request that representation; passingnullis equivalent tosign(String, byte[])(the server chooses the standards-correct representation). This axis never adds or drops a qualified timestamp.- Parameters:
kid- key identifier referencing a signing key; must not benulldata- the raw bytes to sign; must not benullserialization- requested serialization, ornullto let the server choose- Returns:
- signature result; never
null - Throws:
AnkaSecureSdkException- on error, including HTTP 400 when COMPACT is requested but the deployment mandates a qualified timestampNullPointerException- ifkidordataisnull- Since:
- 3.0.0
- See Also:
-
signFileCompact
public SignResult signFileCompact(String kid, Path input, Path output) throws AnkaSecureSdkException Signs a file with forced compact format. Use when you need a single-line string for API/JSON transmission. Fails if the input exceeds the server's configured compact limit (maxPlaintextBytes, default 4 MB).When to Use Compact Format
- API transmission: JSON responses, HTTP headers, query parameters
- Storage: Single database field (text/varchar)
- Interoperability: JWS standard format (RFC 7515)
Output Format
eyJhbGc...header...XVCJ9.eyJkYXRh...payload...9.dBjftJ...signature...
Single-line base64url string with embedded payload, suitable for text-based transmission.
Alternative Methods
- Use
signFile(String, Path, Path)for automatic format selection (recommended) - Use
signFileStream(String, Path, Path)for large files (above the server's configured compact limit)
Example
// Sign small document for API transmission SignResult result = sdk.signFileCompact( "my-ml-dsa-key", Path.of("contract.pdf"), Path.of("contract.jws") ); System.out.println("Algorithm: " + result.getAlgorithmUsed());- Parameters:
kid- key identifier for signing; must not benullinput- input file (up to the server's configured compact limit, default 4 MB); must not benulloutput- output file (.jws recommended); must not benull- Returns:
- signature result with metadata; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation fails- See Also:
-
signFileCompact
public SignResult signFileCompact(String kid, Path input, Path output, JwsSerialization serialization) throws AnkaSecureSdkException Signs a file (attached), explicitly selecting the JWS serialization (PRD §60).Ergonomic overload of
signFileCompact(String, Path, Path). Passingnulldefers to the server. When the deployment mandates a qualified timestamp, the written output is a JWS-JSON artifact carrying the JAdESsigTst(it is never collapsed to a compact string that would drop the stamp).- Parameters:
kid- key identifier for signing; must not benullinput- input file (max 5MB); must not benulloutput- output file; must not benullserialization- requested serialization, ornullto let the server choose- Returns:
- signature result; never
null - Throws:
AnkaSecureSdkException- on error, including HTTP 400 when COMPACT is requested but the deployment mandates a qualified timestamp- Since:
- 3.0.0
- See Also:
-
signFile
public SignResult signFile(String kid, Path input, Path output) throws AnkaSecureSdkException, IOException Signs a file. Recommended for most use cases. Automatically selects optimal format based on file size (<5MB = compact, ≥5MB = streaming).This method automatically selects the optimal format:
- Files below the server's
maxPlaintextBytes: Compact JWS format (single-line string) - Files at or above that limit: Streaming JWS format (detached signature)
Why Use This Method?
You don't need to worry about file sizes or server limits. The threshold is discovered from the server (not hardcoded) and cached briefly; if a compact request is still rejected as too large (HTTP 413) the SDK transparently retries via streaming. This method handles everything automatically, ensuring your signing operation always succeeds regardless of file size.
When to Use Explicit Formats
Use
signFileCompact(String, Path, Path)orsignFileStream(String, Path, Path)only when you specifically need a particular output format (e.g., compact JWS for API transmission).Example
// Sign any file - works for both small and large files SignResult result = sdk.signFile( "my-ml-dsa-key", Path.of("document.pdf"), Path.of("document.jws") ); System.out.println("Signed with: " + result.getAlgorithmUsed());- Parameters:
kid- key identifier for signing; must not benullinput- input file (any size); must not benulloutput- output file (.jws or .jwst); must not benull- Returns:
- signature result with metadata; never
nullBy default fails if
outputexists; callwithOverwrite()to overwrite. - Throws:
AnkaSecureSdkException- if operation failsIOException- if file cannot be accessedDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default)- See Also:
- Files below the server's
-
signFileStream
Signs a file with forced streaming format. Use for large files (100MB+), low-memory environments, or when binary output is acceptable.When to Use Streaming Format
- Large files: Files above the server's configured compact limit (required), optimal for 100MB+ (recommended)
- Memory constraints: Low-memory environments or embedded systems
- Binary output: When detached signature format is acceptable
- Progressive processing: Start processing before full upload
Output Format
Detached JWS signature (.jwst file) where payload is stored separately. Suitable for large files where embedding the payload in the signature would be impractical.
Alternative Methods
- Use
signFile(String, Path, Path)for automatic format selection (recommended) - Use
signFileCompact(String, Path, Path)for small files (below the server's configured compact limit)
Example
// Sign large archive file SignResult result = sdk.signFileStream( "my-ml-dsa-key", Path.of("backup.tar.gz"), Path.of("backup.tar.gz.jwst") );- Parameters:
kid- key identifier for signing; must not benullinput- input file (any size, up to 100MB recommended); must not benulloutput- output file (.jwst recommended); must not benull- Returns:
- signature result with metadata; never
null - Throws:
AnkaSecureSdkException- if operation fails- See Also:
-
verifySignature
Verifies a JWS signature from a file, accepting either the compact form or the JWS-JSON form (serialization-agnostic; PRD §60).The file may contain an RFC 7515 §7.1 compact string OR an RFC 7515 §7.2 JWS-JSON object (which MAY carry a JAdES qualified timestamp in its unprotected header). The correct representation is detected automatically. Fails if the file is ≥5MB (server limit).
Alternative Methods
Note: No auto-detection method available because streaming verification requires separate data and signature file parameters.
- Use
verifySignature(Path)for compact or JWS-JSON files (<5MB) - Use
verifySignatureStream(Path, Path)for detached signatures (any size)
Example
// Verify a compact or JWS-JSON signature file VerifySignatureResult result = sdk.verifySignature( Path.of("document.jws") ); if (result.isValid()) { System.out.println("Signature valid, signed by: " + result.getKeyRequested()); } // Informational: never affects isValid() if (result.getQualifiedTimestamp() != null) { System.out.println("Qualified timestamp trust: " + result.getQualifiedTimestamp().getTrustStatus()); }- Parameters:
jwsFile- compact or JWS-JSON signature file; must not benull- Returns:
- verification result; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation fails- Since:
- 3.0.0
- See Also:
- Use
-
verifySignature
Verifies a compact JWS (RFC 7515) signature.The JWS token is self-contained and includes all metadata required for verification (algorithm, signature, protected header). The server resolves the verification key based on the
kidheader in the JWS.Example
String jwsToken = "eyJhbGciOiJNTC1EU0EtNjUiLCJraWQiOiJteS1rZXkifQ..."; VerifySignatureResult result = sdk.verifySignature(jwsToken); if (result.isValid()) { System.out.println("Signature verified"); System.out.println("Signed by key: " + result.getKeyRequested()); } else { System.out.println("Signature verification failed"); }- Parameters:
jws- the compact JWS string to verify; must not benull- Returns:
- verification result containing validity status and metadata; never
null - Throws:
AnkaSecureSdkException- if the JWS is malformed, the verification key is not accessible, or the server returns an errorNullPointerException- ifjwsisnull- Since:
- 3.0.0
- See Also:
-
verifySignatureStream
public VerifySignatureResult verifySignatureStream(Path dataFile, Path signatureFile) throws AnkaSecureSdkException Verifies a detached JWS signature with forced streaming format. Use for large files (100MB+), low-memory environments, or when binary output is acceptable.When to Use Streaming Format
- Large files: Files above the server's configured compact limit (required), optimal for 100MB+ (recommended)
- Memory constraints: Low-memory environments or embedded systems
- Binary output: When verifying detached JWS signature format (.jwst files)
- Progressive processing: Start verification before full upload
Input Format
Detached JWS signature (.jwst file) + separate data file. Typically created by
signFileStream(String, Path, Path).Alternative Methods
Note: No auto-detection method available because streaming verification requires separate data and signature file parameters.
- Use
verifySignature(Path)for compact JWS files (<5MB) - Use
verifySignatureStream(Path, Path)for detached signatures (any size)
Example
// Verify detached signature for large file VerifySignatureResult result = sdk.verifySignatureStream( Path.of("backup.tar.gz"), // Original data Path.of("backup.tar.gz.jwst") // Detached signature ); if (result.isValid()) { System.out.println("Signature valid!"); }- Parameters:
dataFile- original data file (any size, up to 100MB recommended); must not benullsignatureFile- detached JWS signature file; must not benull- Returns:
- verification result; never
null - Throws:
AnkaSecureSdkException- if operation fails- See Also:
-
listKeys
Lists ONE PAGE of the keys accessible to the authenticated client.Filters apply server-side BEFORE pagination, so the returned totals are filtered, tenant-scoped counts. Use
listAllKeys(KeyFilters)when the complete set is needed (client-side auto-pagination).Example
KeyPage page = sdk.listKeys(new KeyFilters(null, null, "ML-KEM", "ACTIVE"), 0, 50); System.out.println("Page 1/" + page.totalPages() + " - " + page.totalElements() + " keys"); page.content().forEach(key -> System.out.println(key.getKid() + " (" + key.getAlg() + ")") );- Parameters:
filters- server-side filters;KeyFilters.none()for all keyspage- zero-based page indexsize- page size (1..200; values above 200 are rejected by the server with 400)- Returns:
- the page of key metadata with totals; never
null - Throws:
AnkaSecureSdkException- if the server returns an error- Since:
- 3.0.0
- See Also:
-
listAllKeys
Lists ALL keys matching the filters by auto-paginating through the server's paginated listing (the AWS-CLI pattern: the API pages, the client iterates).Bounded by the first page's
totalPagessnapshot with a defensive hard cap; exceeding it THROWSPaginationCeilingExceededExceptionrather than silently truncating. Offset-pagination drift between page fetches is accepted best-effort.Example
List<KeyMetadata> allKeys = sdk.listAllKeys(KeyFilters.none()); List<KeyMetadata> activeRsa = sdk.listAllKeys(new KeyFilters(null, null, "RSA", "ACTIVE"));- Parameters:
filters- server-side filters;KeyFilters.none()for all keys- Returns:
- all matching key metadata; never
null, may be empty - Throws:
AnkaSecureSdkException- if the server returns an error- Since:
- 3.0.0
- See Also:
-
getKeyMetadata
Retrieves metadata for a specific key.Example
KeyMetadata key = sdk.getKeyMetadata("my-ml-kem-768-key"); System.out.println("Key: " + key.getKid()); System.out.println("Algorithm: " + key.getAlg()); System.out.println("Status: " + key.getStatus()); System.out.println("Created: " + key.getCreatedAt());- Parameters:
kid- key identifier; must not benull- Returns:
- key metadata; never
null - Throws:
AnkaSecureSdkException- if the key does not exist, the authenticated client lacks permission, or the server returns an errorNullPointerException- ifkidisnull- Since:
- 3.0.0
- See Also:
-
reencrypt
Re-encrypts data with a different key without decrypting to plaintext.Decrypts the JWE using the original key, then immediately re-encrypts with the new key. The plaintext never leaves the server, providing better security than decrypt + encrypt in the client.
This method is suitable for in-memory JWE tokens up to ~100 MB. For larger files, use
reencryptFileStream(String, String, Path, Path).Example
// Original encryption EncryptResult encrypted = sdk.encrypt("old-aes-key", data); String jweToken = encrypted.getJweToken(); // Migrate to post-quantum encryption ReencryptResult reencrypted = sdk.reencrypt("new-ml-kem-key", jweToken); System.out.println("Migrated from: " + reencrypted.getOldKeyAlgorithmUsed()); System.out.println("Migrated to: " + reencrypted.getNewKeyAlgorithmUsed());- Parameters:
newKid- identifier of the new encryption key; must not benulljweToken- the JWE token to re-encrypt; must not benull- Returns:
- re-encryption result containing new JWE and migration metadata;
never
null - Throws:
AnkaSecureSdkException- if either key does not exist, the JWE is malformed, the authenticated client lacks permission, or the server returns an errorNullPointerException- ifnewKidorjweTokenisnull- Since:
- 3.0.0
- See Also:
-
reencryptFileCompact
public ReencryptResult reencryptFileCompact(String newKid, Path input, Path output) throws AnkaSecureSdkException Re-encrypts a file with forced compact format. Use when you need a single-line string for API/JSON transmission. Fails if the input exceeds the server's configured compact limit (maxPlaintextBytes, default 4 MB).When to Use Compact Format
- API transmission: Re-encrypting for JSON responses or HTTP headers
- Storage: Re-encrypting for single database field (text/varchar)
- Interoperability: JWE standard format (RFC 7516)
Alternative Methods
- Use
reencryptFile(String, Path, Path)for automatic format selection (recommended) - Use
reencryptFileStream(String, String, Path, Path)for large files (above the server's configured compact limit)
Example
// Re-encrypt small file with new key ReencryptResult result = sdk.reencryptFileCompact( "new-ml-kem-key", Path.of("old-data.jwe"), Path.of("new-data.jwe") ); System.out.println("Migrated from: " + result.getOldKeyAlgorithmUsed()); System.out.println("Migrated to: " + result.getNewKeyAlgorithmUsed());- Parameters:
newKid- identifier of the new encryption key; must not benullinput- compact JWE file (up to the server's configured compact limit, default 4 MB); must not benulloutput- output file (.jwe recommended); must not benull- Returns:
- re-encryption result with migration metadata; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation fails- See Also:
-
reencryptFile
public ReencryptResult reencryptFile(String newKid, Path input, Path output) throws AnkaSecureSdkException, IOException Re-encrypts a file. Recommended for most use cases. Automatically selects the re-encryption path from the input envelope's actual format, not its size.This method inspects the input file's structure and routes accordingly:
- Compact JWE (produced by
encryptFileCompact(String, Path, Path)orencryptFile(String, Path, Path)in compact mode): compact re-encrypt path - Streaming JWET multipart artifact (produced by
encryptFileStream(String, Path, Path)): streaming re-encrypt path
Why Format, Not Size?
The input here is an envelope, not plaintext. A compact JWE is roughly twice the size of the plaintext it wraps, so its size may exceed the server's compact plaintext ceiling even though it is a compact envelope that must be re-encrypted via the compact path. Selecting by format guarantees that any file produced by
encryptFile/encryptFileCompactis always re-encryptable, and that a genuinely detached/streaming artifact is always re-encrypted via streaming.When to Use Explicit Formats
Use
reencryptFileCompact(String, Path, Path)orreencryptFileStream(String, String, Path, Path)only when you specifically need to force a particular format.Example
// Re-encrypt any file - works for both small and large files ReencryptResult result = sdk.reencryptFile( "new-ml-kem-key", Path.of("old-data.jwe"), Path.of("new-data.jwe") ); System.out.println("Migrated from: " + result.getOldKeyAlgorithmUsed()); System.out.println("Migrated to: " + result.getNewKeyAlgorithmUsed());- Parameters:
newKid- identifier of the new encryption key; must not benullinput- input JWE file (any size); must not benulloutput- output file (.jwe or .jwet); must not benull- Returns:
- re-encryption result with migration metadata; never
nullBy default fails if
outputexists; callwithOverwrite()to overwrite. - Throws:
AnkaSecureSdkException- if operation failsIOException- if file cannot be accessedDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default)- See Also:
- Compact JWE (produced by
-
reencryptFileStream
public ReencryptResult reencryptFileStream(String newKid, String sourceKidOverride, Path input, Path output) throws AnkaSecureSdkException Re-encrypts a file with forced streaming format. Use for large files (100MB+), low-memory environments, or when binary output is acceptable.When to Use Streaming Format
- Large files: Files above the server's configured compact limit (required), optimal for 100MB+ (recommended)
- Memory constraints: Low-memory environments or embedded systems
- Binary output: When re-encrypting to streaming JWE format (.jwet files)
- Progressive processing: Start processing before full upload
- Key rotation: Migrating archived data to new encryption keys
Alternative Methods
- Use
reencryptFile(String, Path, Path)for automatic format selection (recommended) - Use
reencryptFileCompact(String, Path, Path)for small files (below the server's configured compact limit)
Example
// Re-encrypt large file with new key ReencryptResult result = sdk.reencryptFileStream( "new-ml-kem-key", null, // Auto-detect old key from JWE header Path.of("backup.jwet"), Path.of("backup-new.jwet") );- Parameters:
newKid- identifier of the new encryption key; must not benullsourceKidOverride- identifier of the old key;nullto auto-detect from JWEinput- streaming JWE file (any size, up to 100MB recommended); must not benulloutput- output file (.jwet recommended); must not benull- Returns:
- re-encryption result with migration metadata; never
null - Throws:
AnkaSecureSdkException- if operation fails- See Also:
-
resign
Re-signs data with a different key without verifying the original signature.Strips the old signature and creates a new JWS with the new signing key. This is useful for key rotation or migrating signatures to post-quantum algorithms.
This method is suitable for in-memory JWS tokens up to ~100 MB. For larger files, use
resignFileStream(Path, String, Path, Path).Example
// Original signature SignResult signed = sdk.sign("old-ecdsa-key", document); String jwsToken = signed.getJwsToken(); // Migrate to post-quantum signature ResignResult resigned = sdk.resign("new-ml-dsa-key", jwsToken); System.out.println("Migrated from: " + resigned.getOldKeyAlgorithmUsed()); System.out.println("Migrated to: " + resigned.getNewKeyAlgorithmUsed());- Parameters:
newKid- identifier of the new signing key; must not benulljws- the JWS token to re-sign; must not benull- Returns:
- re-sign result containing new JWS and migration metadata;
never
null - Throws:
AnkaSecureSdkException- if either key does not exist, the JWS is malformed, the authenticated client lacks permission, or the server returns an errorNullPointerException- ifnewKidorjwsisnull- Since:
- 3.0.0
- See Also:
-
resign
public ResignResult resign(String newKid, String jws, JwsSerialization serialization) throws AnkaSecureSdkException Re-signs a JWS, explicitly selecting the JWS serialization (PRD §60).Ergonomic overload of
resign(String, String). Passingnulldefers to the server. The input JWS may be compact or JWS-JSON.- Parameters:
newKid- identifier of the new signing key; must not benulljws- the JWS to re-sign (compact or JWS-JSON); must not benullserialization- requested serialization, ornullto let the server choose- Returns:
- re-sign result with migration metadata; never
null - Throws:
AnkaSecureSdkException- on error, including HTTP 400 when COMPACT is requested but the deployment mandates a qualified timestampNullPointerException- ifnewKidorjwsisnull- Since:
- 3.0.0
- See Also:
-
resignFileCompact
public ResignResult resignFileCompact(String newKid, Path input, Path output) throws AnkaSecureSdkException Re-signs a compact JWS file with forced compact format. Use when you need a single-line string for API/JSON transmission. Fails if the input exceeds the server's configured compact limit (maxPlaintextBytes, default 4 MB).When to Use Compact Format
- API transmission: Re-signing for JSON responses or HTTP headers
- Storage: Re-signing for single database field (text/varchar)
- Interoperability: JWS standard format (RFC 7515)
Alternative Methods
Note: No auto-detection method available because streaming re-signing requires separate data and signature file parameters.
- Use
resignFileCompact(String, Path, Path)for compact JWS files (below the server's configured compact limit) - Use
resignFileStream(Path, String, Path, Path)for detached signatures (any size)
Example
// Re-sign compact JWS with new key ResignResult result = sdk.resignFileCompact( "new-ml-dsa-key", Path.of("old-signature.jws"), Path.of("new-signature.jws") ); System.out.println("Migrated from: " + result.getOldKeyAlgorithmUsed()); System.out.println("Migrated to: " + result.getNewKeyAlgorithmUsed());- Parameters:
newKid- identifier of the new signing key; must not benullinput- compact JWS file (up to the server's configured compact limit, default 4 MB); must not benulloutput- output file (.jws recommended); must not benull- Returns:
- re-sign result with migration metadata; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation fails- See Also:
-
resignFileCompact
public ResignResult resignFileCompact(String newKid, Path input, Path output, JwsSerialization serialization) throws AnkaSecureSdkException Re-signs a JWS file (attached), explicitly selecting the JWS serialization (PRD §60).Ergonomic overload of
resignFileCompact(String, Path, Path). Passingnulldefers to the server. When the deployment mandates a qualified timestamp, the written output is a JWS-JSON artifact carrying the JAdESsigTst.- Parameters:
newKid- identifier of the new signing key; must not benullinput- input JWS file (compact or JWS-JSON, max 5MB); must not benulloutput- output file; must not benullserialization- requested serialization, ornullto let the server choose- Returns:
- re-sign result with migration metadata; never
null - Throws:
AnkaSecureSdkException- on error, including HTTP 400 when COMPACT is requested but the deployment mandates a qualified timestamp- Since:
- 3.0.0
- See Also:
-
resignFileStream
public ResignResult resignFileStream(Path oldJwsHeader, String newKid, Path input, Path output) throws AnkaSecureSdkException Re-signs a detached JWS signature with forced streaming format. Use for large files (100MB+), low-memory environments, or when binary output is acceptable.When to Use Streaming Format
- Large files: Files above the server's configured compact limit (required), optimal for 100MB+ (recommended)
- Memory constraints: Low-memory environments or embedded systems
- Binary output: When re-signing detached JWS signature format (.jwst files)
- Progressive processing: Start processing before full upload
- Key rotation: Migrating archived signatures to new signing keys
Input Format
Detached JWS signature (.jwst file) + separate data file. Typically created by
signFileStream(String, Path, Path).Alternative Methods
Note: No auto-detection method available because streaming re-signing requires separate data and signature file parameters.
- Use
resignFileCompact(String, Path, Path)for compact JWS files (below the server's configured compact limit) - Use
resignFileStream(Path, String, Path, Path)for detached signatures (any size)
Example
// Re-sign detached signature for large file ResignResult result = sdk.resignFileStream( Path.of("backup.tar.gz.jwst"), // Old JWS header "new-ml-dsa-key", Path.of("backup.tar.gz"), // Original data Path.of("backup-new.tar.gz.jwst") // New signature );- Parameters:
oldJwsHeader- old JWS header file (for metadata extraction); must not benullnewKid- identifier of the new signing key; must not benullinput- original data file (any size, up to 100MB recommended); must not benulloutput- output file (.jwst recommended); must not benull- Returns:
- re-sign result with migration metadata; never
null - Throws:
AnkaSecureSdkException- if operation fails- See Also:
-
signThenEncrypt
public SignEncryptResult signThenEncrypt(String signKid, String encryptKid, byte[] data) throws AnkaSecureSdkException Signs then encrypts data in a single operation (nested JWE containing JWS).Creates a JWS signature, then encrypts the entire JWS as a JWE. This provides both authenticity (signature) and confidentiality (encryption). The recipient must decrypt first, then verify the signature.
This method is suitable for in-memory payloads up to ~100 MB. For larger files, use
signThenEncryptFileCompact(String, String, Path, Path).Example
byte[] sensitiveDoc = Files.readAllBytes(Path.of("/contracts/agreement.pdf")); SignEncryptResult result = sdk.signThenEncrypt( "my-ml-dsa-key", // signing key "my-ml-kem-key", // encryption key sensitiveDoc ); // Later: decrypt then verify DecryptVerifyResult verified = sdk.decryptThenVerify(result.getJweToken()); if (verified.isSignatureValid()) { System.out.println("Signature valid, data authentic"); }- Parameters:
signKid- identifier of the signing key; must not benullencryptKid- identifier of the encryption key; must not benulldata- the raw bytes to sign and encrypt; must not benull- Returns:
- result containing nested JWE token and operation metadata;
never
null - Throws:
AnkaSecureSdkException- if either key does not exist, the authenticated client lacks permission, or the server returns an errorNullPointerException- if any parameter isnull- Since:
- 3.0.0
- See Also:
-
signThenEncrypt
public SignEncryptResult signThenEncrypt(String signKid, String encryptKid, byte[] data, JwsSerialization serialization) throws AnkaSecureSdkException Signs then encrypts, explicitly selecting the inner-JWS serialization (PRD §60).Ergonomic overload of
signThenEncrypt(String, String, byte[]). Passingnulldefers to the server. Governs only the inner JWS representation and never changes the outer JWE.- Parameters:
signKid- private key identifier for signing; must not benullencryptKid- public key identifier for encryption; must not benulldata- plaintext bytes to sign and encrypt; must not benullserialization- requested inner-JWS serialization, ornullto defer- Returns:
- combined sign-encrypt result; never
null - Throws:
AnkaSecureSdkException- on error, including HTTP 400 (before any signing or encryption) when COMPACT is requested but the deployment mandates a qualified timestampNullPointerException- if any ofsignKid,encryptKid, ordataisnull- Since:
- 3.0.0
- See Also:
-
decryptThenVerify
Decrypts a JWE then verifies the inner JWS signature.Reverses
signThenEncrypt(String, String, byte[])by decrypting the outer JWE, then verifying the inner JWS signature. Both operations must succeed for the overall operation to succeed.Example
// Received encrypted and signed document String jweToken = "eyJhbGciOiJNTC1LRU0tNzY4IiwiZW5jIjoiQTI1NkdDTSJ9..."; DecryptVerifyResult result = sdk.decryptThenVerify(jweToken); if (result.isSignatureValid()) { byte[] authenticData = result.getDecryptedData(); System.out.println("Decrypted and verified successfully"); } else { System.out.println("Signature verification failed"); }- Parameters:
jweToken- the nested JWE token to decrypt and verify; must not benull- Returns:
- result containing decrypted data and verification status;
never
null - Throws:
AnkaSecureSdkException- if the JWE is malformed, decryption fails, the JWS is malformed, or the server returns an errorNullPointerException- ifjweTokenisnull- Since:
- 3.0.0
- See Also:
-
signThenEncryptFileCompact
public SignEncryptResult signThenEncryptFileCompact(String signKid, String encryptKid, Path input, Path output) throws AnkaSecureSdkException Signs then encrypts a file with forced compact format. Use when you need a single-line string for API/JSON transmission. Fails if the input exceeds the server's configured compact limit (maxPlaintextBytes, default 4 MB).When to Use Compact Format
- API transmission: Signed and encrypted data for JSON responses or HTTP headers
- Storage: Single database field (text/varchar) with both authenticity and confidentiality
- Interoperability: Nested JWE(JWS) standard format
Output Format
JWE( JWS(payload) )
Alternative Methods
Note: No streaming variant available for combined operations. For large files, split into separate sign and encrypt operations.
Example
// Sign and encrypt sensitive document SignEncryptResult result = sdk.signThenEncryptFileCompact( "my-ml-dsa-key", // Signing key "my-ml-kem-key", // Encryption key Path.of("contract.pdf"), Path.of("contract-secure.jwe") ); System.out.println("Signed with: " + result.getSignKeyRequested()); System.out.println("Encrypted with: " + result.getEncryptKeyRequested());- Parameters:
signKid- signing key identifier; must not benullencryptKid- encryption key identifier; must not benullinput- input file (up to the server's configured compact limit, default 4 MB); must not benulloutput- output file (.jwe); must not benull- Returns:
- operation result with metadata; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation failsDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default); callwithOverwrite()to overwrite
-
signThenEncryptFileCompact
public SignEncryptResult signThenEncryptFileCompact(String signKid, String encryptKid, Path input, Path output, JwsSerialization serialization) throws AnkaSecureSdkException Signs a file then encrypts it, explicitly selecting the inner-JWS serialization (PRD §60).Ergonomic overload of
signThenEncryptFileCompact(String, String, Path, Path). Passingnulldefers to the server.- Parameters:
signKid- private key identifier for signing; must not benullencryptKid- public key identifier for encryption; must not benullinput- input file; must not benulloutput- output file; must not benullserialization- requested inner-JWS serialization, ornullto defer- Returns:
- combined sign-encrypt result; never
null - Throws:
AnkaSecureSdkException- on error, including HTTP 400 (before any signing or encryption) when COMPACT is requested but the deployment mandates a qualified timestamp- Since:
- 3.0.0
- See Also:
-
decryptThenVerifyFileCompact
public DecryptVerifyResult decryptThenVerifyFileCompact(Path input, Path output) throws AnkaSecureSdkException Decrypts and verifies a nested JWE(JWS) file with forced compact format. Use when you need to decrypt and verify a single-line string. Fails if the input exceeds the server's configured compact limit (maxPlaintextBytes, default 4 MB).When to Use Compact Format
- API transmission: Decrypting and verifying from JSON responses or HTTP headers
- Storage: Decrypting and verifying from single database field (text/varchar)
- Interoperability: Nested JWE(JWS) standard format
Alternative Methods
Note: No streaming variant available for combined operations. For large files, split into separate decrypt and verify operations.
Example
// Decrypt and verify secured document DecryptVerifyResult result = sdk.decryptThenVerifyFileCompact( Path.of("contract-secure.jwe"), Path.of("contract-recovered.pdf") ); if (result.isSignatureValid()) { System.out.println("Signature valid!"); System.out.println("Signed by: " + result.getSigningKey()); }- Parameters:
input- nested JWE file (up to the server's configured compact limit, default 4 MB); must not benulloutput- recovered plaintext file; must not benull- Returns:
- operation result with verification status; never
null - Throws:
AnkaSecureSdkException- if the input exceeds the server's configured compact limit (HTTP 413) or operation failsDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default); callwithOverwrite()to overwrite
-
signThenEncryptFileStream
public SignEncryptResult signThenEncryptFileStream(String signKid, String encryptKid, Path input, Path output) throws AnkaSecureSdkException Signs a file then encrypts it in streaming mode (nested JWE(JWS), bounded memory) — the large-file counterpart ofsignThenEncryptFileCompact(String, String, Path, Path).The payload is signed with
signKid(inner JWS) and the resulting JWS is encrypted withencryptKid(outer JWE) in a single incremental pass, so the signature is carried ENCRYPTED. The nested ciphertext artifact is written tooutputvia the SDK's sidecar write contract (quarantine to<output>.part, then atomic promotion). This is a PRODUCER operation — its result is deterministic (complete-or-abort), not verdict-framed. Because the artifact is streamed to disk,SignEncryptResult.getJweToken()isnullfor this variant; the artifact is theoutputfile.- Parameters:
signKid- private key identifier for signing (inner JWS); must not benullencryptKid- public key identifier for encryption (outer JWE); must not benullinput- input file to stream; must not benulloutput- output file for the nested JWE(JWS) artifact; must not benull- Returns:
- sign-encrypt result with the outer-JWE metadata; never
null - Throws:
AnkaSecureSdkException- if signing, encryption, or streaming failsDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default); callwithOverwrite()to overwrite- See Also:
-
decryptThenVerifyFileStream
public DecryptVerifyResult decryptThenVerifyFileStream(Path input, Path output) throws AnkaSecureSdkException Decrypts a nested JWE(JWS) file then verifies the inner signature in streaming mode — the large-file counterpart ofdecryptThenVerifyFileCompact(Path, Path), and the inverse ofsignThenEncryptFileStream(String, String, Path, Path).The server returns a TWO-verdict result carrying BOTH the outer AES-GCM tag outcome and the inner JWS signature outcome. The SDK quarantines the recovered plaintext to
<output>.partand promotes it tooutputONLY when the overall verdict is VALID (both dimensions passed). An INVALID or absent verdict is FAIL-CLOSED: the sidecar is deleted, no file is written, and a typedStreamIntegrityExceptionis thrown — success is never inferred from a closed socket.On success,
DecryptVerifyResult.isSignatureValid()istrueandDecryptVerifyResult.getQualifiedTimestamp()surfaces the §60 informational timestamp when present (it never affects validity).- Parameters:
input- nested JWE(JWS) streaming artifact (the output ofsignThenEncryptFileStream(String, String, Path, Path)); must not benulloutput- destination for the recovered plaintext; must not benull- Returns:
- decrypt-verify result with verification status and metadata; never
null - Throws:
AnkaSecureSdkException- if decryption or I/O failsStreamIntegrityException- if the integrity verdict is INVALID or absentDestinationExistsException- ifoutputalready exists and this instance usesOverwritePolicy.FAIL_IF_EXISTS(the default); callwithOverwrite()to overwrite- See Also:
-
analyzePkcs7
public co.ankatech.secure.client.model.Pkcs7AnalysisResponse analyzePkcs7(co.ankatech.secure.client.model.Pkcs7AnalysisRequest request) throws AnkaSecureSdkException Analyzes a PKCS#7 file to extract metadata and certificate information.Parses a PKCS#7/CMS file and returns information about the signing certificates, signature algorithm, and content type without verifying the signature.
Example
co.ankatech.secure.client.model.Pkcs7AnalysisRequest request = new co.ankatech.secure.client.model.Pkcs7AnalysisRequest(); co.ankatech.secure.client.model.Pkcs7AnalysisResponse analysis = sdk.analyzePkcs7(request); System.out.println("Content type: " + analysis.getContentType()); System.out.println("Certificates: " + analysis.getCertificates().size());- Parameters:
request- PKCS#7 analysis request; must not benull- Returns:
- analysis result containing PKCS#7 metadata; never
null - Throws:
AnkaSecureSdkException- if the file cannot be read, is not valid PKCS#7, or the server returns an errorNullPointerException- ifrequestisnull- Since:
- 3.0.0
-
analyzePkcs7Stream
public co.ankatech.secure.client.model.Pkcs7AnalysisResponse analyzePkcs7Stream(co.ankatech.secure.client.model.Pkcs7AnalysisStreamRequest metadata, File file) throws AnkaSecureSdkException Analyzes a PKCS#7 file using streaming to avoid loading the entire file into memory.Example
co.ankatech.secure.client.model.Pkcs7AnalysisStreamRequest metadata = new co.ankatech.secure.client.model.Pkcs7AnalysisStreamRequest(); java.io.File file = new java.io.File("/legacy/large-signed-archive.p7s"); co.ankatech.secure.client.model.Pkcs7AnalysisResponse analysis = sdk.analyzePkcs7Stream(metadata, file);- Parameters:
metadata- PKCS#7 analysis metadata; must not benullfile- PKCS#7 file to analyze; must not benull- Returns:
- analysis result containing PKCS#7 metadata; never
null - Throws:
AnkaSecureSdkException- if the file cannot be read, is not valid PKCS#7, or the server returns an errorNullPointerException- if any parameter isnull- Since:
- 3.0.0
-
convertPkcs7ToJose
public co.ankatech.secure.client.model.Pkcs7ConversionResponse convertPkcs7ToJose(co.ankatech.secure.client.model.Pkcs7ConversionRequest request) throws AnkaSecureSdkException Converts a PKCS#7 signature to JOSE (JWS) format.Extracts the signature from a PKCS#7/CMS file and converts it to compact JWS (RFC 7515) format. This enables legacy PKCS#7 signatures to be verified using modern JOSE tooling.
Example
co.ankatech.secure.client.model.Pkcs7ConversionRequest request = new co.ankatech.secure.client.model.Pkcs7ConversionRequest(); co.ankatech.secure.client.model.Pkcs7ConversionResponse conversion = sdk.convertPkcs7ToJose(request); String jws = conversion.getJws(); System.out.println("Converted to JWS: " + jws);- Parameters:
request- PKCS#7 conversion request; must not benull- Returns:
- conversion result containing JWS token; never
null - Throws:
AnkaSecureSdkException- if the file cannot be read, is not valid PKCS#7, conversion fails, or the server returns an errorNullPointerException- ifrequestisnull- Since:
- 3.0.0
-
convertPkcs7ToJoseStream
public File convertPkcs7ToJoseStream(co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest metadata, File inputFile, File outputFile) throws AnkaSecureSdkException Converts a PKCS#7 signature to JOSE using streaming.Example
co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest metadata = new co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest(); java.io.File inputFile = new java.io.File("/legacy/large-signed-archive.p7s"); java.io.File outputFile = new java.io.File("/converted/signature.jws"); java.io.File result = sdk.convertPkcs7ToJoseStream(metadata, inputFile, outputFile);- Parameters:
metadata- conversion metadata; must not benullinputFile- path to PKCS#7 file; must not benulland file must existoutputFile- path where JWS will be written; must not benull- Returns:
- the output file; never
null - Throws:
AnkaSecureSdkException- if the file cannot be read, is not valid PKCS#7, conversion fails, or the server returns an errorNullPointerException- if any parameter isnull- Since:
- 3.0.0
-
performMigrationWorkflow
public MigrationWorkflowResult performMigrationWorkflow(File pkcs7File, co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest conversionRequest, File outputFile) throws AnkaSecureSdkException Performs a complete PKCS#7-to-JOSE migration workflow with analysis and conversion.Analyzes a PKCS#7 file, converts it to JOSE format, and writes the result. This is a complete end-to-end workflow for migrating legacy PKCS#7 signatures to modern JOSE format.
Example
java.io.File pkcs7 = new java.io.File("/legacy/signed.p7s"); java.io.File output = new java.io.File("/converted/signed.jws"); co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest request = new co.ankatech.secure.client.model.Pkcs7ConversionStreamRequest(); MigrationWorkflowResult result = sdk.performMigrationWorkflow(pkcs7, request, output); System.out.println("Migration complete");- Parameters:
pkcs7File- the PKCS#7 file to convert; must not benullconversionRequest- the conversion parameters; must not benulloutputFile- where to write the JOSE output; must not benull- Returns:
- migration result with details; never
null - Throws:
AnkaSecureSdkException- if the workflow fails or the server returns an errorNullPointerException- if any parameter isnull- Since:
- 3.0.0
- See Also:
-
encryptFileUtilityStream
public EncryptResult encryptFileUtilityStream(String kty, String alg, String publicKeyB64, Path input, Path output) throws AnkaSecureSdkException Encrypts a file using a provided public key (without requiring key in ANKASecure).This utility method allows encryption using an externally-managed public key, bypassing the normal key management workflow. Useful for one-off encryptions or interoperability with external systems.
Example
String publicKeyBase64 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."; EncryptResult result = sdk.encryptFileUtilityStream( "RSA", "RSA-OAEP", publicKeyBase64, Path.of("/data/document.pdf"), Path.of("/data/document.pdf.jwe") );- Parameters:
kty- key type (e.g., "RSA", "EC", "ML-KEM"); must not benullalg- algorithm (e.g., "RSA-OAEP", "ML-KEM-768"); must not benullpublicKeyB64- base64-encoded public key; must not benullinput- path to plaintext file; must not benulloutput- path where JWE will be written; must not benull- Returns:
- encryption result containing operation metadata; never
null - Throws:
AnkaSecureSdkException- if the key is invalid, algorithm is unsupported, files cannot be read/written, or the server returns an errorNullPointerException- if any parameter isnull- Since:
- 3.0.0
-
verifySignatureUtilityStream
public VerifySignatureResult verifySignatureUtilityStream(String kty, String alg, String publicKeyB64, String signatureB64, Path dataFile) throws AnkaSecureSdkException Verifies a signature using a provided public key (without requiring key in ANKASecure).This utility method allows signature verification using an externally-managed public key, bypassing the normal key management workflow. Useful for verifying signatures from external systems.
Example
String publicKeyBase64 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."; String signatureBase64 = "..."; VerifySignatureResult result = sdk.verifySignatureUtilityStream( "RSA", "RS256", publicKeyBase64, signatureBase64, Path.of("/data/document.pdf") ); if (result.isValid()) { System.out.println("Signature verified"); }- Parameters:
kty- key type (e.g., "RSA", "EC", "ML-DSA"); must not benullalg- algorithm (e.g., "RS256", "ML-DSA-65"); must not benullpublicKeyB64- base64-encoded public key; must not benullsignatureB64- base64-encoded signature; must not benulldataFile- path to original data file; must not benull- Returns:
- verification result containing validity status; never
null - Throws:
AnkaSecureSdkException- if the key is invalid, algorithm is unsupported, files cannot be read, or the server returns an errorNullPointerException- if any parameter isnull- Since:
- 3.0.0
-
getSupportedAlgorithms
Retrieves the complete list of cryptographic algorithms supported by the server.Returns all algorithms available for key generation, encryption, signing, and other cryptographic operations. Each
AlgorithmInfoincludes detailed metadata about the algorithm's characteristics, security level, and supported operations.Example
List<AlgorithmInfo> allAlgorithms = sdk.getSupportedAlgorithms(); // Find all post-quantum algorithms allAlgorithms.stream() .filter(alg -> alg.getCategory().equals("POST_QUANTUM")) .forEach(alg -> System.out.println(alg.getKty() + " / " + alg.getAlg() + " (Level " + alg.getSecurityLevel() + ")") );- Returns:
- list of all supported algorithm information; never
null, never empty - Throws:
AnkaSecureSdkException- if the server returns an error or the request fails- Since:
- 3.0.0
- See Also:
-
getSupportedAlgorithms
public List<AlgorithmInfo> getSupportedAlgorithms(AlgorithmFilter filter) throws AnkaSecureSdkException Retrieves cryptographic algorithms matching the specified filter criteria.Filters the algorithm catalog by category (classical, post-quantum, hybrid), key operations (encrypt, sign, etc.), security level, and other characteristics. Multiple filter criteria are combined with AND logic.
Example
// Find all NIST Level 5 post-quantum signing algorithms AlgorithmFilter filter = new AlgorithmFilter() .setCategory("POST_QUANTUM") .setKeyOps(List.of("sign", "verify")) .setNistSecurityLevel(5); List<AlgorithmInfo> pqcSigning = sdk.getSupportedAlgorithms(filter); pqcSigning.forEach(alg -> System.out.println(alg.getKty() + " / " + alg.getAlg() + " (Level " + alg.getSecurityLevel() + ")") ); // Use the first result to drive a data-plane operation if (!pqcSigning.isEmpty()) { AlgorithmInfo chosen = pqcSigning.get(0); System.out.println("Selected algorithm: " + chosen.getKty() + " / " + chosen.getAlg()); }- Parameters:
filter- the algorithm filter specifying criteria such as category, key operations, and security level; must not benull- Returns:
- list of algorithm information matching all specified filter criteria;
never
null, may be empty if no algorithms match - Throws:
AnkaSecureSdkException- if the server returns an error or the request failsNullPointerException- iffilterisnull- Since:
- 3.0.0
- See Also:
-