A Swift Package (SPM) that wraps libewf by Joachim Metz as a universal static library for reading Expert Witness Format (EWF / EnCase) forensic disk images on macOS, with bundled mount and info tools.
libewf-spm provides a Swift API and prebuilt binaries for working with EWF (.e01, .ex01, .s01) forensic images on macOS. It wraps libewf behind static targets and exposes version queries, bundled tool resolution, and C headers for direct library access.
The package ships prebuilt universal fat static libraries for libewf and all libyal dependencies, plus bundled command-line tools — no separate libewf installation, Homebrew, or OpenSSL required.
- macOS 12.0+
- Xcode 15+
- macFUSE 5.x — required at runtime for
ewfmountonly
No Homebrew dependencies. OpenSSL, zlib, and bzip2 are either statically linked or provided by macOS system libraries.
Add to your Package.swift:
dependencies: [
.package(url: "https://github.com/saadtahir-dev/libewf-spm.git", from: "1.0.0")
],
targets: [
.target(
name: "YourTarget",
dependencies: [
.product(name: "LibEWF", package: "libewf-spm")
]
)
]For local development alongside other forensic packages:
dependencies: [
.package(path: "../libewf-spm")
],
targets: [
.target(
name: "YourTarget",
dependencies: [
.product(name: "LibEWF", package: "libewf-spm")
]
)
]Or add via Xcode: File → Add Package Dependencies → paste the repo URL.
import LibEWF
// Get library version
let version = EWFReader.getVersion()
print("libewf version: \(version)")
// Resolve bundled tools (for mounting via Process)
if let ewfmount = EWFToolLocator.bundledToolPath("ewfmount"),
let ewfinfo = EWFToolLocator.bundledToolPath("ewfinfo") {
print("ewfmount: \(ewfmount)")
print("ewfinfo: \(ewfinfo)")
// Launch ewfmount with Process, or use ImageMounter
}For programmatic byte-level reads, use the CLibEWF module and libewf C APIs (libewf_handle_t) via the shipped headers in Sources/CLibEWF/include.
| Target | Description |
|---|---|
CLibEWF |
Static libewf + all libyal deps, no FUSE. Use for reading EWF images in-process. |
CLibEWFFuse |
Static libewf + all libyal deps, FUSE-enabled. Use when you need to launch ewfmount. |
CLibEWFResources |
Bundled ewf* command-line tools as SPM resources. |
LibEWF |
Swift wrapper. Depends on CLibEWF + CLibEWFResources. |
| Method | Description |
|---|---|
static func getVersion() -> String |
Returns the linked libewf version string (e.g. "20251220"). |
Resolves paths to bundled executables in the CLibEWFResources resource bundle (bin/). Results are cached after the first successful lookup.
| Method | Description |
|---|---|
static func bundledToolPath(_ tool: String) -> String? |
Returns the filesystem path to a bundled tool by name, or nil if not found or not executable. |
Common tool names: "ewfmount", "ewfinfo", "ewfexport", "ewfacquire", "ewfverify".
C modules exposing libewf.h and related headers. Linked via -Xlinker on the prebuilt static archives. Use for direct libewf_handle_* access when you need read/write beyond the Swift convenience layer.
| Format | Extension | Support |
|---|---|---|
| EnCase / EWF (EWF-E01) | .e01 |
Supported |
| EnCase / EWF (EWFX) | .ex01 |
Supported |
| SMART / s01 | .s01 |
Supported |
| Split segments | .e01, .e02, … |
Supported (open first segment; libewf globs the set) |
All libraries ship as universal fat binaries (arm64 + x86_64) in Sources/CLibEWF/ and Sources/CLibEWFFuse/:
| Library | Purpose |
|---|---|
libewf.a |
EWF read/write implementation |
libbfio.a |
Basic file I/O abstraction |
libcaes.a |
AES encryption support |
libcdata.a |
Data structures |
libcdatetime.a |
Date/time handling |
libcerror.a |
Error handling |
libcfile.a |
File abstraction |
libclocale.a |
Locale support |
libcnotify.a |
Notification support |
libcpath.a |
Path handling |
libcsplit.a |
String splitting |
libcthreads.a |
Thread support |
libfcache.a |
File cache |
libfdata.a |
File data |
libfdatetime.a |
File date/time |
libfguid.a |
GUID support |
libfvalue.a |
File value |
libhmac.a |
HMAC hashing |
libodraw.a |
Optical disk raw access |
libsmdev.a |
Storage media device |
libsmraw.a |
Storage media raw access |
libuna.a |
Unicode/ASCII conversion |
The following system libraries are linked at build time — no bundling required:
| Library | Source |
|---|---|
libz |
macOS system (/usr/lib/libz.1.dylib) |
libbz2 |
macOS system (/usr/lib/libbz2.1.0.dylib) |
OpenSSL is statically linked into the libraries — no Homebrew or system OpenSSL required.
Prebuilt command-line tools ship in Sources/CLibEWFResources/bin/ and are resolved at runtime via EWFToolLocator:
| Tool | Purpose | macFUSE required |
|---|---|---|
ewfmount |
Mount an EWF image as a raw block device via FUSE | Yes |
ewfinfo |
Print image metadata and integrity information | No |
ewfexport |
Export EWF image to another format | No |
ewfacquire |
Acquire a disk image into EWF format | No |
ewfacquirestream |
Acquire a disk image into EWF format from a stream (e.g. piped input) | No |
ewfverify |
Verify EWF image integrity | No |
ewfrecover |
Recover a corrupted or incomplete EWF image | No |
ewfdebug |
Low-level debug/diagnostic output for EWF images | No |
| Property | Value |
|---|---|
| Architectures | Universal (arm64 + x86_64) |
| FUSE linkage | System /usr/local/lib/libfuse3.4.dylib (macFUSE 5.x), absolute path |
| OpenSSL linkage | Statically linked — no runtime dependency |
| Resolution | CLibEWFResources SPM resource bundle |
ewfmount requires macFUSE to be installed and loaded on the target machine, and links against the system-installed /usr/local/lib/libfuse3.4.dylib by absolute path — it does not bundle its own copy.
An earlier build of this package tried vendoring a private copy of libfuse3.4.dylib into the resource bundle and re-signing it under this package's own Developer ID, to work around hardened-runtime library-validation rejecting macFUSE's Team ID. That approach doesn't work: libfuse3.4.dylib isn't standalone — it's one piece of a multi-component macFUSE installation, and it itself loads MFMount.framework (/Library/Filesystems/macfuse.fs/Contents/Frameworks/MFMount.framework/...), a separate component signed under macFUSE's own Team ID and tied to the user's installed macFUSE version and kernel/system extension. Resigning our copy of libfuse3.4.dylib didn't change that inner dependency's signature — so the same Team ID mismatch just reappeared one level deeper in the load chain.
The actual fix: ewfmount links the system libfuse3.4.dylib directly (matching whatever macFUSE version the user has installed, avoiding any version skew), and the consuming app must sign ewfmount with the com.apple.security.cs.disable-library-validation entitlement. This package does not sign its own binaries with this entitlement — bundling an SPM resource doesn't preserve a signature or entitlements through Xcode's normal build/archive process, so the entitlement has to be applied by whichever app embeds and (re-)signs ewfmount as part of its own build (see ReconLab's Sign Imaging Binaries build phase for a reference implementation). Scope the entitlement to ewfmount specifically, not the whole app — the other bundled tools (ewfinfo, ewfacquire, etc.) don't touch macFUSE and don't need it.
The currently vendored libewf release already ships a correct fuse_darwin_attr boundary layer in ewftools/mount_fuse.c for macFUSE 5.x — no source patch is applied by this package. An earlier build of this package did require a manual patch against an older libewf release; upstream has since merged the equivalent fix, so a fresh clone no longer needs it. Always verify against ewftools/mount_fuse.h/.c before assuming the playbook's patch script applies.
For build steps and troubleshooting, see the swift-forensic-playbook.
See the swift-forensic-playbook for the complete step-by-step guide covering:
- Building libewf and all 21 libyal dependencies as static-only universal archives (
--enable-static --disable-shared), arm64 + x86_64,lipo'd together - Building with static OpenSSL, zlib, and bzip2 support
- Checking whether the target libewf release needs the macFUSE 5.x
fuse_darwin_attrboundary-layer patch toewftools/mount_fuse.c(not needed as of the version currently vendored here — verify against upstream before assuming otherwise) - Linking
ewfmountagainst the system/usr/local/lib/libfuse3.4.dylib(absolute path — do not vendor and re-sign a private copy; see macFUSE Compatibility above for why) - Bundling
ewfmountand the other seven ewf* tools into the SPM resource target - Creating the SPM package structure
- A note for consuming apps: sign
ewfmountwithcom.apple.security.cs.disable-library-validationat archive/export time, scoped to that binary only
MIT — see LICENSE
- swift-forensic-playbook — Build guides for forensic image libraries as Swift Packages
- libyal/libewf — Upstream libewf library
- ImageMounter — macOS forensic image mounting service (uses
EWFToolLocatorfor EWF mounting)