Iron security for agents: IronCrypto, IronPrivacyGuard, and IronSocketLayer
A human engineer who reaches for a cryptographic library brings something the library does not ship: the knowledge of which algorithm fits the job, which rule must never be broken, and what a particular failure actually means. That knowledge lives in documentation, specifications, and experience.
An autonomous agent has none of it. It has an API surface and a guess. Every guess is a chance to reuse a nonce, accept an unverified certificate, or treat a revoked identity as valid.
Three of our Rust projects attack that problem at three different layers, and they now compose into a stack: IronCrypto for primitives, IronPrivacyGuard for files and identities, and IronSocketLayer for the wire. Today we are announcing IronSocketLayer 0.3.1, the newest of the three, alongside IronPrivacyGuard 0.2.0.
One idea, three layers
Each project puts the rules in the same place as the code, as data an agent can query before it acts. Ask IronCrypto what to use and it answers with the call, the constraints that make it safe, and the alternatives it rejected and why:
ic recommend encrypt-message --fipsThe answer names AES-256-GCM and the exact call to make, marks nonce reuse as a critical constraint with its consequence spelled out, and records that ChaCha20-Poly1305 was rejected as unapproved in the FIPS mode of operation rather than silently substituted. The same shape of answer comes from IronPrivacyGuard for a file workflow and from IronSocketLayer for a connection profile.
All three also expose their catalogs as JSON, JSON-LD, and OWL, and all three ship an MCP server, so an agent discovers capabilities through the same mechanism it uses to call them.
IronCrypto 0.2.15 — the floor
IronCrypto is agentic-first cryptography in pure Rust with a machine-readable ontology. Zero dependencies, no C, no build scripts: every crate that implements an algorithm depends on nothing outside the workspace, and that boundary is checked per crate on each build. The one deliberate exception is the rustls provider adapter, which lets IronCrypto carry TLS for existing stacks.
It is no_std from the ground up and cross-compiled for ARM Cortex-M, RISC-V, and WebAssembly. Implemented primitives are checked against published vectors or independent reconstructions, with test provenance documented rather than asserted.
The ontology is the part that matters for agents. Constraints carry a severity, a requirement, and the consequence of violating it:
ic ontology show aes-256-gcm --jsonIronPrivacyGuard 0.2.0 — files, identities, and trust
IronPrivacyGuard (ipg) covers the GPG-shaped workflows: generate identities, export public keys, encrypt and decrypt files, sign and verify exact bytes. Since its announcement it has grown from 54 operations to 82, reachable through direct commands, structured JSON calls, NDJSON streams, and MCP over stdio.
Trust is explicit rather than ambient. Encryption and verification take an expected fingerprint, so the caller states which identity it intends to trust. Native trust policy is an immutable snapshot identified by a digest; governed operations report the digest they enforced, and a mismatched snapshot fails the operation instead of falling back. Existing output paths are never replaced, and there is no force-overwrite flag.
Keys can live where the workflow requires: passphrase-protected software identities, or non-exportable keys on PKCS#11 tokens and HSMs, TPM 2.0, and AWS KMS — the last over IPG's own TLS 1.3 client. Hybrid post-quantum identities combine ML-KEM-768 with X25519 for encryption and ML-DSA-65 with Ed25519 for composite signatures.
IronCrypto is the only dependency. Every build, including the OpenPGP, PKCS#11, TPM, attestation, and AWS KMS integrations, resolves to IronCrypto and first-party IPG crates.
IronSocketLayer 0.3.1 — the wire
IronSocketLayer (isl) is TLS 1.3 and QUIC-TLS in pure Rust, implemented over IronCrypto. Post-quantum by default, sans-I/O, no_std, no unsafe code in the library, and no third-party dependencies. Every cryptographic operation is IronCrypto's; IronSocketLayer implements the protocol and nothing else.
It answers the three questions an agent cannot answer for itself. Which configuration? Named profiles and intents, with the rationale and the rejected alternatives returned as data — and an honest unavailable instead of a weaker substitute when nothing meets the requirements:
isl recommend intent:agent-to-agent-mtls --post-quantum --jsonWhat did I get? Every connection yields a SessionReport: version, suite, group, signature schemes, the names the peer's certificate was actually issued for, the safe defaults the configuration gave up, and the security properties that hold, each as a named property: post-quantum key exchange, mutual authentication, FIPS-approved algorithms. "The handshake succeeded" is not a security claim; this is.
What do I do about this failure? Every error is a closed kind with a stable id, the alert it maps to, flags for retryable and caller-correctable and peer-fault, and a recovery action a planner can branch on.
The protocol surface is wide: full TLS 1.3 client and server with mutual authentication, HelloRetryRequest, KeyUpdate, post-handshake client authentication for privilege step-up, opt-in 0-RTT with a server-side replay guard, external PSKs for agent pairs with no PKI, and resumption that keeps both forward secrecy and the post-quantum key exchange. QUIC v1 and v2 packet protection per RFC 9001 and RFC 9369. X25519 with ML-KEM-768 for key exchange, and ML-DSA signatures. CRLs and OCSP stapling checked in both directions, with a revoked certificate always fatal. Encrypted Client Hello with GREASE by default, so the connections that do use ECH do not stand out.
One foot-gun is simply absent: there is no option to disable certificate verification. An agent talking to a peer without a PKI pins that peer's public key instead, which is stricter and easier to provision than a flag someone will eventually set in production.
isl probe cloudflare.com --alpn h2,http/1.1
isl explain error:unknown-ca
isl mcpEvidence, not assertions
Two copies of the same misreading of an RFC interoperate perfectly, so in-memory tests prove little on their own. IronSocketLayer's handshakes are tested against independent implementations: public servers at Cloudflare, Google, and GitHub across suites and groups, including a hybrid X25519 with ML-KEM-768 handshake, a real HelloRetryRequest, resumption that preserves the hybrid group, and Encrypted Client Hello with Cloudflare — including the rejection path, where a key Cloudflare does not hold is refused and the authenticated retry configurations are used.
Against OpenSSL 3.5 it runs both directions: 8 key types across 10 groups, ML-DSA-65 and ML-DSA-87 certificate chains that OpenSSL accepts in strict X.509 mode, mutual TLS, resumption, OCSP stapling, CRLs, post-handshake authentication, external PSKs, and 0-RTT. A separate suite exercises CNSA 2.0 against an OpenSSL restricted to ML-KEM-1024, AES-256-GCM, and ML-DSA-87.
Conformance is also checked by tlsfuzzer, an independent suite. Its TLS 1.3 scripts found eight defects. All eight are fixed, every remaining failure is classified in a published report, and a script reproduces the run. Whole-suite branch coverage is 97.70%, with each remaining gap reviewed.
What we are not claiming
None of the three has had an independent cryptographic audit. IronSocketLayer's 0.1.0 security audit was our own with AI-assisted review; its 21 findings and 12 documented weaknesses are fixed in 0.2.0 and 0.2.1, each with a test that fails without the fix. Two advisories cover 0.1.0 — a name-constraint bypass with parsing denial of service, and an MCP probe tool that could reach internal networks — so upgrade if you took that release.
None of them is a FIPS-validated cryptographic module. IronSocketLayer has a fips-140-3 profile and FIPS service indicators; it does not have a certificate. wolfSSL is mature, broadly deployed, FIPS-certified, and sells DO-178C DAL-A packages; we hold none of that, and the repository documents the comparison with its gaps rather than hiding it.
IronPrivacyGuard is not a drop-in GPG replacement: native IPG keys, envelopes, and signatures are not OpenPGP, and interoperability with GnuPG runs through a separate, documented boundary. All three are pre-1.0 and need independent review before high-value production use. For IronSocketLayer, that review is the single most useful contribution the project could receive, and there is a guide for where to start.
Try the stack
With Rust 1.88 or later and Cargo installed:
cargo install ipg --version 0.2.0 --locked
cargo install isl-cli --version 0.3.1 --locked
ipg discover
isl capabilitiesBoth expose MCP entry points — ipg mcp and isl mcp — and both document the host controls worth setting before an agent gets access: which tools are available, where keys live, and which trust policy is pinned.
IronCrypto, IronPrivacyGuard, and IronSocketLayer are available under AGPL-3.0-or-later with a commercial licensing option. See each repository's license files for terms.
The common thread is a refusal to make the agent guess. Which algorithm, which identity, which profile, what actually happened, and what to do when it fails — all of it addressable as data, from the primitive up through the socket.
Explore IronCrypto, IronPrivacyGuard, and IronSocketLayer on GitHub.
Per aspera ad astra.
Subscribe for new dispatches
Research updates, technical deep-dives, and announcements from the frontier of embodied AI — delivered to your inbox.
Check your inbox to confirm your subscription.
