Skip to content

Security ​

ZIGX security features and best practices.

Integrity Verification ​

SHA-256 Hashes ​

Every file in the archive has a SHA-256 checksum:

zig
var info = try zigx.getArchiveInfo("archive.zigx", allocator);
defer info.deinit();

for (info.checksums.items) |item| {
    std.debug.print("{s}: {x}\n", .{item.path, item.hash});
}

Payload Hash ​

The entire compressed payload is hashed:

zig
std.debug.print("Payload Hash: {s}\n", .{info.payload_hash[0..64]});

Archive Hash ​

The complete archive file hash:

zig
std.debug.print("Archive Hash: {s}\n", .{info.archive_hash[0..64]});

CRC32 Verification ​

Each compressed block has a CRC32 checksum for quick integrity checks during decompression.

Signing ​

Archive signing is supported via CLI or API. The signature is appended to the archive and the header is updated to reflect its presence.

Sign with CLI ​

bash
# Sign an archive
zigx sign archive.zigx "my-signature-data"

Sign with API ​

zig
const zigx = @import("zigx");

try zigx.manager.setSignature("archive.zigx", "my-secure-signature-bytes", allocator);

Sign with API ​

zig
try zigx.manager.setSignature("archive.zigx", "signature-bytes", allocator);

Check signature status:

zig
var info = try zigx.getArchiveInfo("archive.zigx", allocator);
if (info.is_signed) {
    std.debug.print("Archive is signed\n", .{});
}

Encryption (Future) ​

Encryption support is planned:

zig
// Future API
_ = try zigx.bundle(.{
    .allocator = allocator,
    .include = &.{"src"},
    .output_path = "encrypted.zigx",
    .encrypt_with = key,
});

// Decrypt
try zigx.unbundle(.{
    .archive_path = "encrypted.zigx",
    .output_dir = "decrypted",
    .allocator = allocator,
    .decrypt_with = key,
});

Check encryption status:

zig
if (info.is_encrypted) {
    std.debug.print("Archive is encrypted\n", .{});
}

Security Best Practices ​

1. Validate Before Extraction ​

zig
// Quick check using isValid() alias
if (!zigx.isValid(path)) {
    return error.InvalidArchive;
}

// Full validation using verify() alias
const valid = try zigx.verify(.{
    .allocator = allocator,
    .archive_path = path,
});
if (!valid) {
    return error.ValidationFailed;
}

2. Verify Checksums ​

zig
var info = try zigx.getArchiveInfo(path, allocator);
defer info.deinit();

// Compare against known hash
if (!std.mem.eql(u8, &info.archive_hash, expected_hash)) {
    return error.HashMismatch;
}

3. Check Version Compatibility ​

zig
if (info.format_version > zigx.FORMAT_VERSION) {
    std.debug.print("Warning: Newer format version\n", .{});
}

4. Use Safe Extraction Paths ​

zig
// Using unbundle() alias with safe options
try zigx.unbundle(.{
    .archive_path = path,
    .output_dir = "/safe/path",  // Use absolute paths
    .allocator = allocator,
    .overwrite = false,  // Don't overwrite by default
});

5. Limit Resource Usage ​

zig
// Check archive size before extraction
if (info.original_size > MAX_ALLOWED_SIZE) {
    return error.ArchiveTooLarge;
}

Path Traversal Protection ​

ZIGX automatically prevents path traversal attacks:

  • Strips ../ sequences
  • Validates path components
  • Rejects absolute paths in archives

Memory Safety ​

ZIGX is written in Zig with:

  • No hidden memory allocations
  • Explicit error handling
  • Bounds checking
  • No undefined behavior

See Also ​

Released under the Apache License 2.0.