SharpAESCrypt: The .NET 8 Library That Encrypts Files Without Breaking the Past

A modern AESCrypt implementation for C# that balances strict security, legacy compatibility, and streaming performance.

8 min read • View on GitHub • More from duplicati

A sealed archive box split into two eras, with a worn legacy lock on one side and a precision modern lock on the other. The image explains the library’s core tension: it must preserve interoperability with old encrypted files while enforcing stricter validation in new code.
SharpAESCrypt lives in the uncomfortable middle ground between old file formats and modern security discipline.
Key Takeaways

The strange job of an encryption library is that it has to protect data and preserve history at the same time. SharpAESCrypt does that by enforcing a strict reading of the AESCrypt file format, while still offering a compatibility path for old files that were written with malformed padding.

That makes it more interesting than a straight crypto wrapper. It is a modern .NET 8 implementation that acts like a translator between clean security rules and the messy reality of legacy encrypted archives.

The AES header IV generation was slow as it queried the operating system for a MAC address on every call (and it had an error, resulting in a default value being used). Fixing the error and caching the MAC address improved the performance by up to 1.85 times.

What AESCrypt files actually look like

SharpAESCrypt does not invent a new encryption format. It implements a known one: AESCrypt, a portable file format built around AES-256, versioned headers, streamed payloads, and an integrity seal at the end. The format matters because interoperability only works when every implementation agrees on where the header ends, where the blocks begin, and how the file proves it has not been tampered with.

The library’s core idea is a stream pipeline, not a one-shot file transform. Compatibility changes one branch, but the integrity model stays intact.

A close-up machine moving 16-byte blocks along a conveyor while one arm encrypts each block and another calculates an integrity seal. A side channel carries leftover bytes into a compact buffer instead of reallocating memory. The image explains how the library streams data efficiently while preserving a verification step at the end.
SharpAESCrypt is built around a streaming pipeline, so large files move through in blocks instead of being loaded wholesale.

Why strict mode matters

The project’s most revealing switch is IgnorePaddingBytes. In strict mode, SharpAESCrypt behaves like a security gatekeeper. It refuses ambiguity, because padding mistakes can hide bugs, create malformed files, and weaken confidence in what a successful decrypt actually means.

But old files exist, and some were written by clients that did not behave cleanly. The compatibility flag is there to read those files without making the whole library permissive by default. That is a sensible trade-off: keep the safest path as the normal one, and make the exception explicit.

ModeWhat it optimizes forTrade-off
Strict validationSecurity and clear file semanticsBreaks malformed legacy files instead of guessing
Legacy compatibilityInteroperability with older archivesAccepts files that would otherwise fail validation
Default behaviorSafe operation for new dataRequires users to opt in when they need historical tolerance

That is the real pattern in the repo. The library is not saying legacy files are fine. It is saying interoperability sometimes requires carefully bounded forgiveness.

How SharpAESCrypt streams data instead of loading it all at once

This is where the implementation earns its keep. The public API wraps stream objects, so encryption and decryption fit naturally into backup workflows, file pipelines, and other long-running I/O jobs. Internally, the code processes data in fixed-size blocks, builds up the final file incrementally, and verifies integrity at the end with HMAC-SHA256.

The important detail is not just that it streams. It streams in a way that keeps the file format honest. Padding is explicit. Block boundaries matter. Verification happens after the whole transfer, not as a side effect of writing bytes to disk.

// Conceptual shape of the API
using var output = File.Create("backup.aes");
using var encrypting = SharpAESCrypt.AESCrypt.Encrypt(output, password);
source.CopyTo(encrypting);

using var input = File.OpenRead("backup.aes");
using var decrypting = SharpAESCrypt.AESCrypt.Decrypt(input, password);
decrypting.CopyTo(destination);

That pattern is why the library works for backups instead of toy examples. Backups are about pipes, not blobs. A good encryption library for that world has to behave like a stream processor first and a serializer second.

Why the .NET 8 rewrite feels modern

A WSJ-style hedcut portrait of the repository’s main contributor, rendered from a verified GitHub avatar. The portrait gives a human anchor to the library’s modernization work and signals that this is a maintained, production-oriented project.

The .NET 8 version reads like a deliberate cleanup of an older problem space. It leans on modern runtime features such as Span<T>, memory-conscious buffering, and narrow internal helpers that keep cryptographic state separate from the public surface area.

That separation matters. It makes the library easier to reason about, easier to test, and less likely to leak implementation details into every consumer’s code. In crypto, boring structure is a feature.

SharpAESCrypt vs the rest of the world

The project is best understood in contrast. It is not trying to outdo every encryption tool. It is trying to be the safest, most interoperable implementation of a specific file format inside the .NET ecosystem.

OptionWhat it gives youWhat you give up
SharpAESCryptStandard AESCrypt interoperability in modern C#You stay inside a specific file format
Original AES CryptThe canonical reference for the formatOlder runtime and implementation style
Hand-rolled .NET cryptoFull control over primitives and layoutYou must design and validate the format yourself
Restic or BorgWhole-backup encryption and orchestrationYou are choosing a different product model, not the same file-format problem

That is the right framing. The real comparison is not just against other libraries. It is against the temptation to invent one more custom encryption scheme when a portable format already exists and already has a history.

Why this library matters inside Duplicati

Inside Duplicati, SharpAESCrypt is infrastructure. It helps turn user-controlled encryption into a portable guarantee, which is central to a zero-trust backup model. If the encrypted file cannot be read later, or by another implementation, then the promise of portability starts to fray.

That is why the library’s strictness, compatibility switch, and streaming design all point in the same direction. They are not separate concerns. They are the mechanics of making encryption reliable over time, across platforms, and across imperfect history.