How to Use IronZIP with Claude Code

Curtis Chau
Curtis Chau
Updated: October 19, 2026

A case archive that has been through an update can open with the right password, list every file and extract cleanly, and still hold its evidence under the old ZIP cipher instead of AES-256. Nothing in the file list shows the change. Claude Code is Anthropic's coding agent, available from the command line, inside VS Code and JetBrains IDEs, as a desktop app and in a browser. Wherever it runs, it reads the repository, edits files and runs shell commands, which lets it stage an updated archive, extract it, read its raw directory and compare every file before the original is replaced.

IronZIP opens, edits and saves password-protected ZIP files from .NET, with AES-128, AES-256 or the older Traditional cipher, also known as ZipCrypto. Each edit is one call. Which call opens the archive, how a corrected file replaces its old entry, and whether the encryption is set again before the save decide the result, and a wrong choice in any of them raises no exception. The rest of this page prepares Claude Code for a monthly evidence intake, with four tested prompts and the IronZIP behavior behind each one.

Two model settings cover the session. Sonnet handles the listing and the project rules, and the opusplan alias plans the updater with Opus and writes it with Sonnet.

Quickstart
NuGetInstall with NuGet

PM > Install-Package IronZip

Install IronZIP by running the command above in the NuGet Package Manager Console, or search for the package in the NuGet Package Manager.

Launch claude from the repository folder and run /model sonnet before this request.

Add the IronZip NuGet package, version 2026.10.2, to CaseArchive.csproj.

Then make Program.cs list every ZIP file under archives/:

- Apply the license key from IRONZIP_LICENSE_KEY before any other IronZIP call.
- Open each file as an IronZipArchive with the password from CASE_ARCHIVE_PASSWORD.
- Print a block per archive with its entry count, then each entry's name, size and IsCrypted value.
- If an archive won't open, print its exception message and move on to the next one.

Don't change any archive.
Don't print or echo the value of either variable. Tell me whether each one is set.
Text

Expect CASE-1043 to fail even with the correct password. The section on opening an existing ZIP explains why.



What does Claude Code do in a .NET archive project?

Claude Code writes the updater, builds each staged archive, unpacks it, reads its directory and lists the checks that did not pass. After a failed check it edits the code and runs the whole intake again. Your part is to define what every case archive must hold and to read the report at the end.

Name IronZIP as the only archive library in the first prompt. Attackers publish malicious packages under names that AI coding tools hallucinate, and an agent that picks its own package can install one. The attack is called slopsquatting.

How do you set up Claude Code?

Anthropic's quickstart covers installing Claude Code and signing in. A working installation prints a version number for claude --version.

How do you set up a project Claude Code can work in?

The test repository, CaseArchive, is a .NET 9 console project holding three AES-256 case archives in an archives folder, new files for two of them in an incoming folder, and a Markdown page in a docs folder that sets the intake rules. A new file name is added, a matching name replaces its entry, names listed in remove.txt come out, and a case with no incoming folder stays as it is. The archive password comes from CASE_ARCHIVE_PASSWORD.

Rules written in CLAUDE.md load at the start of every session. With the package in place after the Quickstart, the next request writes that file and a reviewer.

Create CLAUDE.md in the repo root with a "Case archives" heading.
Put these rules under it for future sessions:

- Archives are read and written with IronZIP and nothing else.
- The IronZip package stays at the version CaseArchive.csproj references now.
- The intake rules live in docs/case-archives.md.
- Look up an IronZIP member in docs/IronZip.xml before you use it.
- The XML has no entry for IronZip.Entry. Its Name, Size and IsCrypted exist anyway.
- A file replaces an archive under archives/ after it has passed every check, never before.
- CASE_ARCHIVE_PASSWORD and IRONZIP_LICENSE_KEY values never appear in output, logs or files.

Copy docs/IronZip.xml now from the local NuGet cache folder for that IronZip version.
If the cache has no such file, stop and tell me.

Then create .claude/agents/archive-auditor.md.
Give it frontmatter with the name archive-auditor, a one-line description and a tools field.
The tools field lists Read, Grep and Glob, so the auditor can't edit.
In its instructions, tell it to:

- collect the IronZIP types and members used under Services/
- flag any member that docs/IronZip.xml lacks, and list Entry members separately
- point out each save of an opened archive that doesn't set the encryption again first
Text

A running Claude Code session does not detect a newly created .claude/agents folder, so commit that folder, with a placeholder file in it, before you start.

Set up the license before the first open. With no key, opening and extracting both throw LicensingException, and the message says "Production License Required". The IRONZIP_LICENSE_KEY variable alone does not license IronZIP. In the calibration probe the variable was set and License.IsLicensed stayed false, so the program assigns IronZip.License.LicenseKey from it. The IronZIP License Keys page explains how to obtain a key and where it can be set.

Which IronZIP update rules belong in CLAUDE.md?

The calibration probe measured each line on IronZIP 2026.10.2 against the fixture archives and a matching probe archive. Paste the block under the Case archives heading, then restart with claude --continue so the session reads it.

Measured on IronZIP 2026.10.2, these rules apply to every archive update:

- Open with new IronZipArchive(path, password) or IronZipArchive.FromArchive(path, password).
- IronZipArchive.FromFile(path) builds a new archive that stores the ZIP file itself as one entry.
- A protected archive with exactly one entry does not open.
- The constructor and FromArchive throw "Invalid Password!" with the right password.
- ExtractArchiveToDirectory reads it, so rebuild it from an extracted copy in a new IronZipArchive.
- Saving an opened archive writes every entry with the Traditional cipher.
- Call Encrypt(password, EncryptionMethods.AES256) before the save to keep AES-256.
- Entries() reports IsCrypted true either way.
- Opening does not check the password. The save does.
- Entries() lists an archive opened with a wrong password, and SaveAs then throws ZipException.
- Add stores the file name without its folder.
- Adding a name the archive already holds keeps both entries, and extraction writes the later one.
- ReplaceEntry(name, path) stores the new entry under the path it is given, folders included.
- Replace an entry with Delete(name) and then Add(path).
- Delete and ReplaceEntry throw for a name the archive does not hold. Test Contains(name) first.
- Add throws UnauthorizedAccessException for a folder. Add files one at a time.
- Save() writes back over the file the archive was opened from.
Markdown

Why does an updated archive lose its AES-256 encryption?

The save falls back to the Traditional cipher when nothing sets the method again. In our calibration probe, opening CASE-1044 with its password and saving it with no change at all wrote all three entries with the Traditional cipher. Python's standard zipfile module, which cannot read AES entries, then decrypted every one of them with the password. Calling Encrypt with EncryptionMethods.AES256 before the save kept all five entries of an updated CASE-1042 at AES-256, the three new entries included. A ZipSaveOptions that names AES-256, passed to the save call, did the same for an archive with one entry deleted.

Extraction with the password succeeds either way, so only the raw directory shows the downgrade. Each AES entry carries the extra field 0x9901, whose strength byte is 3 for a 256-bit key, and the Traditional entries in the probe had no such field.

How do you open an existing ZIP with IronZIP?

Pass the path and the password to the constructor. The add files to ZIP example opens its archive with FromFile instead, and in the probe that produced an archive holding CASE-1042.zip as one unencrypted entry next to the added photo. IronZIP's skill.md warns that FromFile always builds a new archive and names the constructor and FromArchive as the calls that open one.

An archive with a single protected entry needs a different method. In the probes, an AES-256 archive of this kind threw "Invalid Password!" from the constructor, FromArchive and the byte array constructor, while extraction with the same password worked. The constructor threw the same error for a Traditional archive with one entry. The rebuild extracts the archive to a temporary folder, copies the incoming files in, and saves a new archive with Encrypt called first. The rebuilt CASE-1043 held three AES-256 entries and opened normally afterward.

How do you prompt for IronZIP code that compiles?

Run /model opusplan, then cycle Shift+Tab until plan mode appears in the status bar, and send the request.

Build the monthly intake in Services/IntakeUpdater.cs and Services/ArchiveCheck.cs.
Program.cs runs both after the listing.

IntakeUpdater applies @docs/case-archives.md to each case folder under incoming/:

- It writes out/staged/<case id>.zip with AES-256 and the same password.
- It leaves archives/ untouched.
- A case without an incoming folder keeps its archive byte for byte.

ArchiveCheck judges a staged archive without trusting IronZIP's listing:

1. Extract both archives with IronZIP and the password into new temp folders.
2. Compare each staged entry's SHA-256 with its source.
3. Parse the staged file's central directory bytes itself, without decrypting.

A case fails on any of these:

- a repeated entry name
- an entry without AES extra field 0x9901 at key strength 3
- staged names that differ from the expected set

An added or replaced entry's source is the incoming file.
A kept entry's source is its extracted original.
The expected set is the original names minus those in remove.txt, plus incoming names.
Leave out remove.txt itself.

Move a passing case's staged file over the original.
Use a plain file move, not a second IronZIP save.
A second intake on the same incoming files must pass and leave the same entries.

Write out/intake-report.csv with one row per case:

- entries before and after
- names added, replaced and removed
- pass or fail, with the reason

Print how many cases pass.
Only the directory parse may read an archive without IronZIP.
Don't add another package.
When all cases pass, have @agent-archive-auditor review Services/.
Text

Every check in the prompt blocks a different false pass.

  1. Hashes against the sources: a replaced entry is compared with its incoming file, so a statement that kept its old text fails.
  2. The directory parse: a duplicate name and a missing entry also pass extraction unnoticed.
  3. Staging first: an update that fails a check leaves the original archive as it was.
Tips: Accept the plan if it calls Encrypt before every save, rebuilds CASE-1043 from an extracted copy, and cannot store a replaced name twice, either because it deletes the old entry first or because it builds each staged archive from scratch. A plan that misses any of those writes archives that still list correctly.

Can a wrong password damage a case archive?

IronZIP lists a protected archive opened with any password, so the first error comes late. In the calibration probe the save threw ZipException ("Invalid password for AES") and wrote no file, and extraction threw ArgumentException ("Invalid password!!"). The last prompt makes the agent prove that this path leaves the originals unchanged.

Prove a wrong archive password can't damage anything, in these steps:

1. Hash every file under archives/ with SHA-256.
2. Launch the built program a second time, in a child process.
3. Hash the files again once the child exits.
4. Print both hash lists side by side.
5. Print the child's exit code and the failure reasons it wrote to out/intake-report.csv.

The child inherits IRONZIP_LICENSE_KEY and gets a wrong CASE_ARCHIVE_PASSWORD.
It also gets a --child flag, under which it starts no process.

Three things have to hold:

- Every hash matches.
- The report has a failed row for CASE-1042 and one for CASE-1043, each with IronZIP's error text.
- The exit code is non-zero.

Change the program only where one of those fails, then run the check again.
Text

What did the prompts produce in a real run?

Claude Code received the four prompts in order within a single session, and the rules block was appended to CLAUDE.md before the third. After the run, the committed code was rebuilt from a clean clone and run against the original archives. The Python library pyzipper, which shares no code with IronZIP, read every result.

  • The Quickstart listing, which Claude Code ran itself, showed 4 encrypted entries for CASE-1042, 3 for CASE-1044 and "Invalid Password!" for CASE-1043.
  • After the intake, CASE-1042 held 5 entries instead of 4.
  • The CASE-1042 update added two photos, replaced the witness statement and removed invoice-7781.pdf.
  • CASE-1043 went from 1 entry to 3.
  • CASE-1044 kept every byte.
  • All 11 entries in the three archives carried AES-256.
  • Each entry matched the SHA-256 of its source file.
  • The plan built every staged archive from an extracted copy, the single-entry CASE-1043 included, and never opened an archive to edit it.
  • Encrypt ran before the updater's only save.
  • The directory parser read each entry's name and AES strength byte and no sizes.
  • At the end of the third prompt, the archive-auditor subagent ran once and reported no undocumented IronZIP member.
  • The clean rebuild passed both cases that had incoming files in 2.1 seconds and reported CASE-1044 as skipped.
  • Entries from the rebuild matched those from the run.
  • With a wrong password, all three cases failed at extraction with "Invalid password!!".
  • In that wrong-password run, the archive hashes did not change and the process exited with code 1.
  • Before the fourth prompt, a wrong password stopped the program at the first extraction with an unhandled exception and no report, and the hashes still matched.
  • Some steps ran differently from the page. Every prompt was sent unattended, as a resumed headless session, so the /model choices were passed as command-line options and each new prompt reloaded CLAUDE.md without a manual restart. The plan dialog was not available in that mode, so the plan was approved by a typed reply. The fourth prompt's proof ran as shell commands, so the program gained no child-process code and never reads the child flag. During the fourth prompt, Claude Code also ran the intake once with the right password, which rewrote CASE-1042 and CASE-1043 with the same entries.

The Cursor guide also plans before any file changes, and in its run Plan Mode saved the IronZIP port as an editable Markdown plan. In the ChatGPT Codex guide, the intake rules are written to AGENTS.md, a file Codex loads before any work begins, where this guide uses CLAUDE.md. The AI coding assistants guide sets one complete IronZIP task with a fixed pass list, and the shared run record names the Claude Code version, the models, the prompt timings and the test machine behind these results.


Troubleshooting


Questions?

If you have any questions, reach out to support@ironsoftware.com

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

Read More

Ready to Get Started?

Nuget Downloads 24,698Version:2026.10just released