file icon logo

The algebraicfile specification v1

This document describes version 1 of the “algebraicfile” file format [1].

Versions

The versions of the specification are:

Version Link
1 https://algebraic.cc/algebraicfile/v1 (this page)
2 https://algebraic.cc/algebraicfile/v2

File structure

  Section Size Encrypted
1 Magic & version 6 bytes no
2 Primary header 51 bytes no
3 Secondary header variable length yes, XChaCha20
4 File data variable length (may be zero) yes, XChaCha20
5 Filler data variable length (may be zero) yes, XChaCha20
6 Checksum 32 bytes no

1. Magic & version

This structure of this section should remain the same for all versions of the algebraicfile specification. Reader implementations can read this section and then switch their parsing behavior based on the Version value.

The Go struct representation is below. The struct value is binary-encoded in big-endian order.

struct {
    Magic   [5]byte // value: [5]byte{'e', 'v', 'r', 'c', 'u'}
    Version uint8   // value: 0x01
}

Here is a hex dump of this section:

00000000: 6576 7263 7501

which decomposes into:

Magic                6576 7263 75
Version              01

2. Primary header

The Go struct representation is below. The struct value is binary-encoded in big-endian order.

struct {
    // Argon2id params.
    Salt    [16]byte
    Time    uint32 // number of passes over memory
    Mem     uint32 // KiB
    Threads uint8

    // XChaCha20 nonce.
    Nonce [24]byte

    // SecondaryHeaderLen is the length of the variable-length
    // secondary header that follows this section.
    SecondaryHeaderLen uint16
}

For example, here is a hex dump of a primary header:

00000000: 1b2d 47d2 370b ca4e bed7 8378 3b64 878b
00000010: 0000 0002 0018 0000 048a 82d0 4960 0137
00000020: 8da1 2ed5 5e9e 946a 977d f0e6 d3cb 8fd5
00000030: bc01 f0

which decomposes into:

Salt                 1b2d 47d2 370b ca4e bed7 8378 3b64 878b
Time                 0000 0002
Mem                  0018 0000
Threads              04
Nonce                8a82 d049 6001 378d a12e d55e 9e94 6a97 7df0 e6d3 cb8f d5bc
SecondaryHeaderLen   01f0

3. Secondary header

The DataLen field records the length of the variable length file data that follows. The Copyfile field contains ACL and xattr data in AppleDouble format generated by copyfile(3). Note that the filler data length isn’t recorded. Reader implementations should consider all bytes after the file data but for the checksum to be filler data.

The Go struct representation is below. The struct value is JSON-encoded, then encrypted with XChaCha20.

struct {
    Copyfile    []byte `json:"cp,omitempty"` // packed copyfile(3) data
    DataLen     int64  `json:"dl,omitempty"` // uncompressed file data size; only for regular files
    Mode        uint32 `json:"m,omitempty"`  // fs.FileMode value
    Name        []byte `json:"n,omitempty"`
    Linkname    []byte `json:"l,omitempty"` // for symbolic links
    Uid         int64  `json:"u,omitempty"`
    Gid         int64  `json:"g,omitempty"`
    ModTime     int64  `json:"mt,omitempty"`
    AccessTime  int64  `json:"at,omitempty"`
    ChangeTime  int64  `json:"ct,omitempty"`
    BirthTime   int64  `json:"bt,omitempty"`
    Compression uint8  `json:"z,omitempty"` // compression used for data; currently only value is 0 (off)
}

4. File data

File data encrypted using XChaCha20. Variable length.

5. Filler data

Filler data. Variable length. The filler data is typically psuedo-randomly generated. Variable length.

This section is used to (optionally) obfuscate the file size of an encrypted file.

6. Checksum

SHA-256 sum of all preceding bytes.


  1. The exported type identifier on Apple systems is “org.littleroot.algebraic.algebraicfile”.