Tier 3 Zero-Knowledge Decryption — SDK Reference
Overview
Tier 3 ships two decryption SDKs — both open-source under Apache 2.0, both share the same envelope wire format. Pick based on where you decrypt:
| SDK | Where it runs | Use case |
|---|---|---|
| Browser SDK (TypeScript) | EchelonGraph dashboard at app.echelongraph.io | Dashboard rendering, ad-hoc analyst queries |
sdk/zkdecrypt (Go) | Anywhere Go runs | SOC pipelines, SIEM forwarders, server-side decryption proxies, analytics notebooks |
Both authenticate against your KMS (AWS / GCP / Vault) using your own credentials — EchelonGraph never sees the plaintext.
> Distribution note. The browser SDK lives at > frontend/src/lib/zkdecrypt/ and is bundled with the EchelonGraph > dashboard — there's nothing for you to npm install. If you want > to host your own decryption UI, copy the source (Apache 2.0) into > your project; the code samples below show the public surface.
Browser SDK (TypeScript)
Quick start with React
import { useZkConfig, useZkDecrypt } from "@echelongraph/zkdecrypt";
function FindingViewer({ finding, jwt, vaultToken }) {
const { config } = useZkConfig(jwt);
const { decrypt, busy, error } = useZkDecrypt(config, { vaultToken });
const [plaintext, setPlaintext] = useState<string | null>(null);
async function reveal() {
const out = await decrypt({
envelope: finding.encryptedPayload,
tenantId: finding.tenantId,
agentId: finding.agentId,
});
setPlaintext(new TextDecoder().decode(out.plaintext));
}
if (error) return <div>Decrypt failed: {error.code}</div>;
if (busy) return <div>Decrypting…</div>;
return plaintext ? <pre>{plaintext}</pre> : <button onClick={reveal}>Reveal</button>;
}Auth flow per provider
| Provider | Customer identity | Token sent to KMS |
|---|---|---|
| Vault Transit (T3.11 — shipped) | OIDC sign-in via your IdP → Vault returns a token | X-Vault-Token |
| AWS KMS (T3.12 — shipped) | Your IdP → Cognito Identity Pool / AssumeRoleWithWebIdentity → STS temp creds | SigV4-signed KMS Decrypt |
| GCP Cloud KMS (T3.13 — shipped) | Google Identity Services / Workload Identity Federation → OAuth access token | Authorization: Bearer |
The SDK never holds long-lived credentials. Tokens are passed via the React hook's options argument; rotation is the customer's auth context's responsibility.
AWS quick start (T3.12)
The SDK signs KMS Decrypt requests with hand-rolled SigV4 — no aws-sdk-js dependency. The dashboard's auth layer is responsible for fetching STS credentials (Cognito Identity Pool federation, AssumeRoleWithWebIdentity, IAM Roles Anywhere — your choice). Pass them to the hook as a static object or an async getter:
import { useZkDecrypt } from "@echelongraph/zkdecrypt";
// Async getter — SDK refetches when within 60s of expiresAt.
async function getAwsCreds() {
const stsResp = await myCognitoRefresh(); // your IdP / federation
return {
accessKeyId: stsResp.AccessKeyId,
secretAccessKey: stsResp.SecretAccessKey,
sessionToken: stsResp.SessionToken,
expiresAt: stsResp.Expiration, // ISO-8601
};
}
const { decrypt } = useZkDecrypt(config, { awsCredentials: getAwsCreds });The provider auto-refreshes credentials within 60s of expiresAt and surfaces kms_auth_failed when STS / Cognito returns 401/403 so you can re-prompt the user for sign-in. Custom KMS endpoints (FIPS, VPC endpoints) are supported via config.aws.endpoint.
GCP quick start (T3.13)
The SDK calls Cloud KMS Decrypt over REST with a customer-fetched OAuth access token — no @google-cloud/kms (gRPC + protobuf) dependency, ~3 KB gzipped. The dashboard's auth layer fetches the token via Google Identity Services (google.accounts.oauth2), Workload Identity Federation, or any token broker. Required scope: https://www.googleapis.com/auth/cloudkms.
import { useZkDecrypt } from "@echelongraph/zkdecrypt";
// Async getter — SDK refetches when within 60s of expiresAt.
async function getGcpCreds() {
const tokenResponse = await myGisRefresh(); // your GIS / federation
return {
accessToken: tokenResponse.access_token,
expiresAt: tokenResponse.expiry, // ISO-8601
};
}
const { decrypt } = useZkDecrypt(config, { gcpCredentials: getGcpCreds });The customer's IAM grant must include cloudkms.cryptoKeyVersions.useToDecrypt on the configured key for the federated identity. Cloud KMS returns 401/403 → kms_auth_failed (re-prompt for sign-in); 429 RESOURCE_EXHAUSTED + 5xx are retried with backoff. Regional endpoints (e.g., https://us-east1-cloudkms.googleapis.com) and VPC SC perimeter endpoints are supported via config.gcp.endpoint.
Error codes
ZkSdkError.code is stable — pattern-match on it instead of parsing messages: envelope_too_small, envelope_version_unsupported, envelope_malformed, wrapped_dek_invalid, provider_not_implemented, kms_unwrap_failed, kms_auth_failed, aes_gcm_decrypt_failed, config_disabled, config_missing, no_subtle_crypto.
Bundle size
Tree-shakable: provider implementations load lazily via dynamic import(). A Vault-only customer ships ~5 KB gzipped. An AWS-only customer ships ~7 KB gzipped (provider + hand-rolled SigV4 signer). A GCP-only customer ships ~3 KB gzipped (REST + bearer token; no gRPC or protobuf). Unselected providers are not pulled into the bundle.
Go SDK
Quick start
import "github.com/AkshayDubey29/EchelonGraph/tier3-continuous-agent/sdk/zkdecrypt"
plaintext, err := zkdecrypt.Open(zkdecrypt.OpenInput{
EnvelopePayload: rowFromAPI,
BYOK: customerKey32Bytes, // fetch from your KMS first
TenantID: "acme",
AgentID: "tentacle-node-1",
})Fetching the KEK
# AWS
aws kms decrypt --ciphertext-blob fileb://wrapped-kek.bin \
--query Plaintext --output text | base64 -d > kek.bin
# GCP
gcloud kms decrypt --location=us-east1 --keyring=echelongraph --key=runtime \
--ciphertext-file=wrapped-kek.bin --plaintext-file=kek.bin
# Vault
vault write -field=plaintext transit/decrypt/echelongraph \
ciphertext=vault:v1:... | base64 -d > kek.binWire format
byte 0: version (uint8, currently 1)
bytes 1..5: wrappedLen (uint32 LE)
bytes 5..5+wrappedLen: wrapped DEK
next 12 bytes: AES-GCM nonce
remainder: ciphertext + 16-byte AEAD tagAAD: ${tenantID}|${agentID} UTF-8 bytes; both empty → no AAD.
Threat model
Protects against: EchelonGraph staff curiosity, EchelonGraph DB compromise, network interception, cross-tenant leak.
Does NOT protect against (by design): customer's KMS compromise, customer's browser session compromise (XSS / malicious extension), EchelonGraph backend code injection that could MITM the customer's KMS calls. Mitigations: HTTPS-only, CSP locked to our origin, SRI on the SDK chunk, customer rotates KEK on suspected compromise.
License gate
zk_browser_decrypt license claim required for the browser SDK (T3.11+). The Go SDK is unrestricted (open-source — no license check).
Source
- Go SDK:
tier3-continuous-agent/sdk/zkdecrypt/(Apache 2.0) - Browser SDK:
frontend/src/lib/zkdecrypt/(Apache 2.0) - Tests: 111 unit tests covering envelope edge cases, AES-GCM round-trip,
KMS Decrypt happy paths, auth flows, credential refresh, retry policies, error mapping per HTTP status, edge cases (oversized / empty / wrong-length / malformed responses), HTTPS-only endpoint enforcement, AbortSignal propagation, dispose() lifecycle, single- flight credential refresh under concurrent burst.