Tag engine¶
The zeroecho.core.tag package provides a streaming authentication-tag layer
that can be plugged into any byte-stream pipeline. A TagEngine wraps an
InputStream and either appends a trailer tag on write (produce mode) or verifies
a supplied tag at EOF on read (verify mode), without buffering the full payload.
The TagEngineBuilder factory wires a ZeroEchoSession context to a fresh
engine on each call, so that session policy and auditing apply consistently to
every tag operation.
Modes¶
| Mode | Description |
|---|---|
| Produce | TagEngine.wrap(upstream) returns a passthrough stream. Bytes flow unchanged; when the upstream reaches EOF, the computed tag bytes are appended as a trailer. |
| Verify | The caller supplies the expected tag via setExpectedTag(byte[]) and strips the trailer from the upstream before passing it to wrap. At EOF the engine compares the computed tag to the expected one. |
Verification outcome handling is delegated to a VerificationBiPredicate. The
default predicate returns a boolean; getThrowOnMismatch() converts it to one that
throws VerificationException on mismatch, which is the typical choice for
pipeline use.
TagEngineBuilder¶
TagEngineBuilder<T> is a Supplier<TagEngine<T>> that creates fresh engine
instances. Calling get() on the same builder multiple times is safe; each call
produces an independent engine.
| Factory method | Tag algorithm | T type |
|---|---|---|
TagEngineBuilder.digest(session, spec) |
Unkeyed digest (SHA-256 by default) | byte[] |
TagEngineBuilder.hmac(session, key, spec) |
Keyed HMAC (HMAC-SHA-256 by default) | byte[] |
TagEngineBuilder.signature(session, algId, key, spec) |
JCA signature (auto-detects SIGN/VERIFY from key type) | Signature |
TagEngineBuilder.ed25519Sign(session, privateKey) |
Ed25519 signing | Signature |
TagEngineBuilder.ed25519Verify(session, publicKey) |
Ed25519 verification | Signature |
TagEngineBuilder.rsaSign(session, privateKey, spec) |
RSA-PSS or PKCS#1 v1.5 signing | Signature |
TagEngineBuilder.rsaVerify(session, publicKey, spec) |
RSA-PSS or PKCS#1 v1.5 verification | Signature |
TagEngineBuilder.ecdsaSign(session, privateKey, spec) |
ECDSA signing | Signature |
TagEngineBuilder.ecdsaVerify(session, publicKey, spec) |
ECDSA verification | Signature |
Pass null for spec to use the algorithm-specific default.
TagEngine<T> — interface¶
| Method | Description |
|---|---|
wrap(InputStream upstream) |
Return a filtered stream that applies tag computation or verification. |
tagLength() |
Fixed tag length in bytes (used to strip or append trailers). |
setExpectedTag(byte[]) |
Set the expected tag for verify mode. |
setVerificationApproach(VerificationBiPredicate) |
Override the outcome handler. |
getVerificationCore() |
Return the default predicate (for wrapping with getThrowOnMismatch()). |
Produce example¶
import zeroecho.core.tag.TagEngine;
import zeroecho.core.tag.TagEngineBuilder;
import zeroecho.core.alg.digest.DigestSpec;
import java.io.InputStream;
ZeroEchoSession session = new ZeroEchoSession(); // or .withPolicy(…) / .withAuditMode(…)
TagEngineBuilder<byte[]> digestBuilder = TagEngineBuilder.digest(session, DigestSpec.sha256());
TagEngine<byte[]> engine = digestBuilder.get();
try (InputStream tagged = engine.wrap(plaintextStream)) {
byte[] output = tagged.readAllBytes();
// Separate body from trailer: last tagLength() bytes are the SHA-256 digest.
int tLen = engine.tagLength();
byte[] body = java.util.Arrays.copyOfRange(output, 0, output.length - tLen);
byte[] tag = java.util.Arrays.copyOfRange(output, output.length - tLen, output.length);
}
Verify example¶
import zeroecho.core.tag.TagEngine;
import zeroecho.core.tag.TagEngineBuilder;
import java.security.PublicKey;
PublicKey verificationKey = /* load from certificate */;
TagEngineBuilder<java.security.Signature> verifyBuilder =
TagEngineBuilder.ed25519Verify(session, verificationKey);
TagEngine<java.security.Signature> engine = verifyBuilder.get();
engine.setVerificationApproach(engine.getVerificationCore().getThrowOnMismatch());
engine.setExpectedTag(expectedTag); // stripped from the stream externally
try (InputStream verified = engine.wrap(bodyWithoutTrailer)) {
byte[] body = verified.readAllBytes();
// If the tag is invalid, readAllBytes() throws VerificationException at EOF.
}
CLI integration¶
The zeroecho CLI accepts a -T <algorithm> flag on streaming operations to
attach or verify a tag trailer. The flag selects the algorithm registered with
the session. See Command-line application for flag syntax.
Thread safety¶
TagEngineBuilder is immutable and thread-safe. Each TagEngine instance is
stateful and not thread-safe; use one instance per pipeline run.