tird


Nametird JSON
Version 0.22.0 PyPI version JSON
download
home_pageNone
SummaryA file encryption tool focused on minimizing metadata and hiding encrypted data
upload_time2025-08-26 18:28:39
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9.2
licenseNone
keywords encryption file-encryption hiding data-hiding plausible-deniability deniable-encryption purb time-lock undetectable stealth steganography
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            
<p align="left">
  <img src="https://raw.githubusercontent.com/hakavlad/tird/main/images/logo2.png" width="800" alt="Logo">
</p>

> Cryptography without steganography is like vodka without beer.

*β€” Russian saying*

<table>

<tr>
<td>&nbsp;πŸ“œ&nbsp;</td>
<td><b>&nbsp;<a href="https://github.com/hakavlad/tird/blob/main/docs/MANPAGE.md">man page</a></b></td>
</tr>

<tr>
<td>&nbsp;πŸ“‘&nbsp;</td>
<td><b>&nbsp;<a href="https://github.com/hakavlad/tird/blob/main/docs/SPECIFICATION.md">Specification</a></b></td>
</tr>

<tr>
<td>&nbsp;πŸ“„&nbsp;</td>
<td><b>&nbsp;<a href="https://github.com/hakavlad/tird/blob/main/docs/INPUT_OPTIONS.md">Input&nbsp;Options</a>&nbsp;&nbsp;&nbsp;</b></td>
</tr>

<tr>
<td>&nbsp;πŸ“–&nbsp;</td>
<td><b>&nbsp;<a href="https://github.com/hakavlad/tird/blob/main/docs/tutorial/README.md">Tutorial</a></b></td>
</tr>

<tr>
<td>&nbsp;❓&nbsp;</td>
<td><b>&nbsp;<a href="https://github.com/hakavlad/tird/blob/main/docs/FAQ.md">FAQ</a></b></td>
</tr>

<tr>
<td>&nbsp;πŸ“₯&nbsp;</td>
<td><b>&nbsp;<a href="https://github.com/hakavlad/tird/blob/main/docs/INSTALLATION.md">Installation</a></b></td>
</tr>

</table><br>

<details>
  <summary>&nbsp;<b>Table of Contents</b></summary>

> - [About](#about)
> - [Goals](#goals)

> - [Usage](#usage)
> - [Input Options](#input-options)
> - [Debug Mode](#debug-mode)

> - [Payload](#payload)
> - [Input Keying Material](#input-keying-material)

> - [Cryptographic Primitives](#cryptographic-primitives)
> - [Encrypted Data Format](#encrypted-data-format)

> - [Low Observability and Minimizing Metadata](#low-observability-and-minimizing-metadata)

> - [Hidden File System and Container Format](#hidden-file-system-and-container-format)
> - [Storing and Carrying Concealed Encrypted Data](#storing-and-carrying-concealed-encrypted-data)

> - [Time-Lock Encryption](#time-lock-encryption)

> - [Tradeoffs and Limitations](#tradeoffs-and-limitations)
> - [Warnings](#warnings)

> - [LLM reports](#llm-reports)

> - [Requirements](#requirements)

> - [TODO](#todo)
> - [Feedback](#feedback)

</details>

## About

`tird` /tΙͺrd/ *(an acronym for "this is random data")* is a file encryption tool focused on

- <ins>minimizing metadata</ins> and
- <ins>hiding encrypted data</ins>.

With `tird`, you can:

1. Create files filled with random data to use as containers or keyfiles.
2. Overwrite the contents of block devices and regular files with random data. This can be used to prepare containers and to destroy residual data.
3. Encrypt file contents and comments. The encrypted data format (called cryptoblob) is a [padded uniform random blob (PURB)](https://en.wikipedia.org/wiki/PURB_(cryptography)): it looks like random data and has a randomized size. This reduces metadata leakage from file format and length, and also allows cryptoblobs to be hidden among random data. You can use keyfiles and passphrases at your choice.
4. Create [steganographic](https://en.wikipedia.org/wiki/Steganography) (hidden, undetectable) user-driven file systems inside container files and block devices. Unlike [VeraCrypt](https://veracrypt.fr) and [Shufflecake](https://shufflecake.net/) containers, `tird` containers do not contain headers at all; the user specifies the location of the data in the container and is responsible for ensuring that this location is separated from the container.
5. Prevent or resist [coercive](https://en.wikipedia.org/wiki/Coercion) attacks (keywords: [key disclosure law](https://en.wikipedia.org/wiki/Key_disclosure_law), [rubber-hose cryptanalysis](https://en.wikipedia.org/wiki/Deniable_encryption), [xkcd 538](https://xkcd.com/538/)). `tird` provides some forms of [plausible deniability](https://en.wikipedia.org/wiki/Plausible_deniability) out of the box, even if you encrypt files without hiding them in containers.

> \[!WARNING]
> Users of `tird` **must** carefully read and understand the "[Warnings](#warnings)" section in the `README.md`. The tool's security relies heavily on the user's understanding of its limitations and operating it in a secure environment, especially regarding key management, debug mode usage, and interpreting MAC verification results.

<i>β€” <a href="https://gemini.google.com/share/627c17c844b9">Gemini</a></i>

## Goals

- **File Protection:** Ensuring protection for individual files, including:
  - Symmetric encryption and authentication.
  - Minimizing metadata leakage.
  - Preventing access to data in cases of user coercion.
  - Plausible deniability of payload existence.
  - Hiding encrypted data.
- **Stable Format:** Ensuring a stable encryption format with no [cryptographic agility](https://en.wikipedia.org/wiki/Cryptographic_agility) for long-term data storage.
- **Simplicity:** Ensuring simplicity and avoiding [feature creep](https://en.wikipedia.org/wiki/Feature_creep): refusal to implement features that are not directly related to primary security goals.

## Usage

You don't need to memorize command-line options to use `tird`. This tool features a prompt-based CLI: simply start it, select a menu option, and answer the questions that will follow.

```
$ tird

                       MENU
    β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
    0. Exit              1. Info & Warnings
    2. Encrypt           3. Decrypt
    4. Embed             5. Extract
    6. Encrypt & Embed   7. Extract & Decrypt
    8. Create w/ Random  9. Overwrite w/ Random
    β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”
A0. Select an option [0-9]:
```

## Input Options

There are 5 groups of input options: A (Action), C (Custom), D (Data), K (Keys), P (Proceed). They are numbered for ease of description.

```
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| A0. Select an option     | A. Select an action    |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| C0. Use custom settings? |                        |
| C1. Time cost            | C. Set custom settings |
| C2. Max padding size     |                        |
| C3. Set fake MAC tag?    |                        |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| D1. Input file path      |                        |
| D2. Comments             | D. Enter data,         |
| D3. Output file path     |    data location,      |
| D4. Output file size     |    data size           |
| D5. Start position       |                        |
| D6. End position         |                        |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| K1. Keyfile path         | K. Specify input       |
| K2. Passphrase           |    keying material     |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| P0. Proceed?             | P. Confirm to continue |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
```

A detailed description of these options with examples can be found [here](https://github.com/hakavlad/tird/blob/main/docs/INPUT_OPTIONS.md).

## Debug Mode

> \[!WARNING]
> Debug mode is not intended for use in production!

Start `tird` with the `--debug` option to look under the hood while the program is running.

Enabling debug mode additionally shows:

- File operations:
  - Opening and closing of file descriptors.
  - Real paths to opened files.
  - Movement of file pointers.
- Byte strings related to cryptographic operations: salts, passphrases, digests, keys, nonces, and tags.
- Some other information, including various sizes.

## Payload

The payload that will be encrypted during cryptoblob creation consists of:

- **Contents of one file:** This may be a regular file or a block device (an entire disk or partition). Maximum size: 16 exbibytes minus 832 bytes.
- **Comments (optional):** An arbitrary string of up to 512 bytes. Decrypted comments will be displayed during decryption.

Specifying the payload in the UI looks as follows:

```
D1. File to encrypt: list.txt
    I: path: 'list.txt'; size: 6,493 B (6.3 KiB)
D2. Comments (optional, up to 512 B): Epstein client list, txt
    I: comments will be shown as ['Epstein client list, txt']
```

## Input Keying Material

`tird` provides the option to use passphrases and the contents of keyfiles to derive one-time keys.

- **Keyfiles:** Specify none, one, or multiple keyfile paths. A keyfile path may be:
  - A <ins>regular file</ins>. The contents of the keyfile will be hashed, and its digest will be used for further key stretching and key derivation.
  - A <ins>block device</ins>. Handled the same as a regular keyfile: contents will be hashed.
  - A <ins>directory</ins>. All files within the directory will be hashed and used as keyfiles.
- **Passphrases:** Specify none, one, or multiple passphrases of up to 2048 bytes.

The order of input does not matter.

Specifying IKM in the UI looks as follows:

```
K1. Keyfile path (optional): foo
    I: path: 'foo'; size: 1 B
    I: reading and hashing contents of 'foo'
    I: keyfile accepted
K1. Keyfile path (optional):
K2. Passphrase (optional):
K2. Confirm passphrase:
    I: passphrase accepted
```

## Cryptographic Primitives

The following cryptographic primitives are utilized by `tird`:

- `ChaCha20` cipher ([RFC 8439](https://www.rfc-editor.org/rfc/rfc8439.html)) for data encryption.
- `BLAKE2` ([RFC 7693](https://www.rfc-editor.org/rfc/rfc7693.html)) for hashing and authentication.
- `Argon2` memory-hard function ([RFC 9106](https://www.rfc-editor.org/rfc/rfc9106.html)) for key stretching.
- `HKDF` ([RFC 5869](https://www.rfc-editor.org/rfc/rfc5869.html)) for key derivation.

For more details, refer to the [specification](https://github.com/hakavlad/tird/blob/main/docs/SPECIFICATION.md).

## Encrypted Data Format

<img src="https://i.imgur.com/wAJyAJc.png" width="280" alt="256 shades of grey">

The format of the encrypted data is quite simple and consists of ciphertext with a MAC tag, located *somewhere* among the surrounding random data:

```
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| Random data | Ciphertext | MAC tag | Random data |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
|               Random-looking data                |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
```

**The only data available is:**

- This is random-looking data.
- Its size.

The ciphertext size and its location within the cryptoblob are hidden.

<details>
  <summary>&nbsp;<b>Show more detailed scheme</b></summary>

```
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| CSPRNG output:                                     |
|     Salt for key stretching used with Argon2, 16 B |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| CSPRNG output:                                     |
|     Randomized padding (header padding): 0-20% of  |
|     the (unpadded size + 255 B) by default         |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| ChaCha20 output:                                   |
|     Ciphertext, 512+ B, consists of:               |
|     - Encrypted constant-padded comments, 512 B    |
|     - Encrypted payload file contents, 0+ B        |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| BLAKE2 or CSPRNG output:                           |
|     MAC tag or Fake MAC tag, 32 B                  |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| CSPRNG output:                                     |
|     Randomized padding (footer padding): 0-20% of  |
|     the (unpadded size + 255 B) by default         |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
| CSPRNG output:                                     |
|     Salt for prehashing IKM used with BLAKE2, 16 B |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
```

</details>

Data encrypted with `tird` cannot be distinguished from random data without knowledge of the keys. It also does not contain identifiable headers. `tird` produces cryptoblobs that contain bilateral [randomized padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Randomized_padding) with uniform random data (PURBs). This minimizes metadata leaks from the file format and makes it possible to hide cryptoblobs among other random data. Bilateral padding also conceals the exact location of the ciphertext and MAC tag within the cryptoblob.

## Low Observability and Minimizing Metadata

> While the content of an encrypted message is protected, its size, its provenance, its destination… are not. Data is hidden, metadata is shown.

<i>β€” <a href="https://loup-vaillant.fr/articles/rolling-your-own-crypto">Loup Vaillant</a></i>

|![](https://i.imgur.com/ArRAis1.jpeg)<br>Vs.<br>![](https://i.imgur.com/Oa3y3qg.jpeg)|
|-|

- PURB format:
  - Encrypted files look like random data.
  - Encrypted files have a randomized size: do not reveal the payload size.
- Do not prove that the entered keys are incorrect.
- Prompt-based CLI: no leakage of used options through shell history.
- The output file path is user-defined and is not related to the input file path by default.
- Optional: hiding encrypted data in containers.

## Hidden File System and Container Format

`tird` employs a technique that is [described](https://en.wikipedia.org/wiki/List_of_steganography_techniques#Digital) as follows:

> Concealing data within encrypted data or within random data. The message to conceal is encrypted, then used to overwrite part of a much larger block of encrypted data or a block of random data (an unbreakable cipher like the one-time pad generates ciphertexts that look perfectly random without the private key).

You can encrypt files and embed cryptoblobs into containers starting at arbitrary positions. After writing the cryptoblob, you will need to remember its location in the container (the starting and ending positions), which will be used later to extract the cryptoblobs. In this way, you can create a **hidden, headerless, user-driven file system** inside a container:

- It is **hidden** because it is impossible to distinguish between random container data and cryptoblob data, as well as to determine the location of written cryptoblobs without knowing the positions and keys.
- It is **headerless** because containers do not contain any headers; all data about cryptoblob locations must be stored separately by the user.
- The starting position of the cryptoblob in the container is **user-defined**, and the **user must** store both the starting and ending positions separately from the container. This is why it is called a **user-driven file system**.

Any file, disk, or partition larger than the minimum cryptoblob size (831 B) can be a valid container. Cryptoblobs can be embedded into any area.

**Examples of Valid Containers Include:**

1. Specially generated files with random data.
2. `tird` cryptoblobs, as they contain pockets β€” unauthenticated padding of random data β€” by default, which can be used to embed smaller cryptoblobs.
3. Disk areas containing random data. For example, you can overwrite a disk with random data, format it in FAT32 or exFAT, and use a large portion of the disk, leaving a few dozen MB from the beginning. The disk will appear empty unless you add some files to it.
4. [LUKS](https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup) encrypted volumes.
5. VeraCrypt containers, even those that already contain hidden volumes.

**Example of Container Structure:**

```
+β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+ <β€” Position 0 of the container
|         |             |
|         | Random data |
|         |             |
|         +β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+ <β€” Cryptoblob1 start position
| Header- |             |
| less    | Cryptoblob1 |
|         |             |
| Layer   +β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+ <β€” Cryptoblob1 end position
|         | Random data |
| Cake    +β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+ <β€” Cryptoblob2 start position
|         |             |
|         | Cryptoblob2 |
|         |             |
|         +β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+ <β€” Cryptoblob2 end position
|         | Random data |
+β€”β€”β€”β€”β€”β€”β€”β€”β€”+β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”+
```

#### Visualization of Embedding

The next image visualizes how hard it is to distinguish one random data entry from another and the process of embedding cryptoblobs in a container.

<details>
  <summary>&nbsp;<b>Show Images</b></summary>

<br>

*Empty container with random data:*
<img src="https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/container.png" width="800" alt="Container">

*One cryptoblob embedded in the container:*
<img src="https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embed1.png" width="800" alt="Embedded1">

*Two cryptoblobs embedded in the container:*
<img src="https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embed2.png" width="800" alt="Embedded2">

*Three cryptoblobs embedded in the container:*
<img src="https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embed3.png" width="800" alt="Embedded3">

*Animation: visualization of embedding:*
<img src="https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embedding.gif" width="800" alt="GIF: visualization of embedding">

</details>

## Storing and Carrying Concealed Encrypted Data

Please look at the following screenshot.

<img src="https://i.imgur.com/2tpEhTw.png" width="839" alt="Screenshot">

It looks like this 16 GB volume contains only one 8.7 MiB file. Is it really true? Maybe yes, maybe no.

The file system tells us that there is only one file here. But is there really only one file on the volume? We cannot determine this using the file system. In fact, data may be located outside the file system and be undetectable by file system tools. The 15.2 GiB of space marked as free may be occupied by a hidden file system. This "free" space may be taken up by hidden encrypted data.

Can we disprove the existence of this data? Yes, for example, by examining the entropy level of this free space using `binwalk`. Low entropy indicates a likely absence of hidden data. High entropy *does not*, *by itself*, prove the presence of encrypted hidden data. Areas with high entropy can be either just residual data or hidden encrypted data.

If you are interested in hiding data outside the visible file system, then `tird` is at your service to provide an Invisibility Cloak for your files.

## Time-Lock Encryption

<img src="https://i.imgur.com/65xm1mK.jpeg" width="280" alt="TLE image">

Time-lock encryption (TLE) can be used to prevent an adversary from quickly accessing plaintexts in the event of an IKM compromise (in case of user coercion, for example). In our implementation, it is actually a PoW-based time-lock key derivation. The "Time cost" input option specifies the number of Argon2 passes. If you specify a sufficiently high number of passes, it will take a significant amount of time to perform them. However, an attacker will require the same amount of time when using similar hardware. The execution of Argon2 cannot be accelerated through parallelization, so it is expected that the time spent by an attacker will be approximately the same as that spent by the defender.

This TLE implementation works offline, unlike [tlock](https://github.com/drand/tlock).

Use custom options and set the desired "Time cost" value:

```
C0. Use custom settings? (Y/N, default=N): y
    I: use custom settings: True
    W: decryption will require the same [C1] and [C2] values!
C1. Time cost (default=4): 1000000
    I: time cost: 1,000,000
```

**Plausible TLE:** The adversary does not know the actual value of the time cost, so you can plausibly misrepresent the number of passes. The adversary cannot refute your claim until they attempt to decrypt the cryptoblob using the specified time cost value.

## Tradeoffs and Limitations

- `tird` does not support:
  - [Public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography).
  - File compression.
  - ASCII armored output.
  - [Reed–Solomon error correction](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction).
  - Splitting the output into chunks.
  - Use of [standard streams](https://en.wikipedia.org/wiki/Standard_streams) for processing files (not intended for automated scripts).
  - Low-level block device reading and writing on MS Windows. As a result, these devices cannot be used as keyfiles, cannot be overwritten, and cannot be encrypted or embedded.
- `tird` does not provide:
  - A graphical user interface.
  - A password generator.
- `tird` cannot handle (encrypt/embed) more than one file in one pass. Encryption of directories and multiple files is not supported.
- `tird` does not fake file access, modification, and creation timestamps (atime, mtime, ctime).
- `tird`'s encryption speed is not very high (up to 420 MiB/s in my tests).

## Warnings

> Crypto can help, but it won’t save you from misuse, vulnerabilities, social engineering, or physical threats.

<i>β€” <a href="https://loup-vaillant.fr/articles/rolling-your-own-crypto">Loup Vaillant</a></i>

<img src="https://i.imgur.com/g84qgw8.jpeg" width="600" alt="DANGER MINES">

- ⚠️ The author does not have a background in cryptography.
- ⚠️ The code has no automated test coverage.
- ⚠️ `tird` has not been independently security audited by humans.
- ⚠️ `tird` is ineffective in a compromised environment; executing it in such cases may cause disastrous data leaks.
- ⚠️ `tird` is unlikely to be effective when used with short and predictable keys.
- ⚠️ `tird` does not erase its sensitive data from memory after use.
- ⚠️ Sensitive data may leak into swap space.
- ⚠️ `tird` always releases unverified plaintext, violating [the Cryptographic Doom Principle](https://moxie.org/2011/12/13/the-cryptographic-doom-principle.html); decrypted output is untrusted until the MAC tag is verified.
- ⚠️ Padding contents are never authenticated; authentication only applies to the ciphertext, salts, and certain sizes.
- ⚠️ Padding sizes depend on secret values.
- ⚠️ `tird` does not sort digests of keyfiles and passphrases in constant-time.
- ⚠️ Overwriting file contents does not guarantee secure destruction of data on the media.
- ⚠️ You cannot prove to an adversary that your random data does not contain encrypted information.
- ⚠️ `tird` protects data, not the user; it cannot prevent torture if you are under suspicion.
- ⚠️ Key derivation consumes 1 GiB RAM, which may lead to performance issues or crashes on low-memory systems.
- ⚠️ Development is not complete, and there may be backward compatibility issues.

## LLM reports

<img src="https://i.imgur.com/Ab8rSlc.jpeg" width="200" alt="">

- [Tird Code Security Audit Report (v0.19.0)](https://gemini.google.com/share/6390743bb873); Target: [d016bd5](https://github.com/hakavlad/tird/tree/d016bd51571cd24ea0b21b8959dc01c4e7a69bee); Date: April 13, 2025; Auditor: Gemini 2.5 Pro (experimental)
- [Security Audit Report: tird.py (v0.19.0)](https://gemini.google.com/share/82c80109c0c9); Target: [105f2dd](https://github.com/hakavlad/tird/tree/105f2ddbcace2802e2372f25c7aaae028ae4b357); Date: April 24, 2025; Auditor: Gemini 2.5 Pro (experimental)
- [Tird Security Review (v0.20.0)](https://gemini.google.com/share/754c591bab98); Target: [ba504f9](https://github.com/hakavlad/tird/tree/ba504f92f5f40a8557ab4e1e5c6cc7fbc689a0cd); Date: May 4, 2025; Auditor: Gemini 2.5 Pro (experimental)

## Requirements

- Python >= 3.9.2
- [cryptography](https://pypi.org/project/cryptography/) >= 2.1 (provides `HKDF` and a fast `ChaCha20` implementation)
- [PyNaCl](https://pypi.org/project/PyNaCl/) >= 1.2.0 (provides fast implementations of `Argon2` and `BLAKE2`)
- [colorama](https://pypi.org/project/colorama/) >= 0.4.6 (Windows-specific)

## TODO

Write or improve the documentation:

- Features
- User Guide
- Specification
- Design Rationale

## Feedback

Please feel free to ask questions, leave feedback, or provide critiques in the [Discussions](https://github.com/hakavlad/tird/discussions) section.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "tird",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9.2",
    "maintainer_email": "Alexey Avramov <hakavlad@gmail.com>",
    "keywords": "encryption, file-encryption, hiding, data-hiding, plausible-deniability, deniable-encryption, purb, time-lock, undetectable, stealth, steganography",
    "author": null,
    "author_email": null,
    "download_url": "https://files.pythonhosted.org/packages/32/a4/88d055f3c6d2f86b9213d4993ce6d14fae3bfbade7d724abdf4633115c94/tird-0.22.0.tar.gz",
    "platform": null,
    "description": "\n<p align=\"left\">\n  <img src=\"https://raw.githubusercontent.com/hakavlad/tird/main/images/logo2.png\" width=\"800\" alt=\"Logo\">\n</p>\n\n> Cryptography without steganography is like vodka without beer.\n\n*\u2014 Russian saying*\n\n<table>\n\n<tr>\n<td>&nbsp;\ud83d\udcdc&nbsp;</td>\n<td><b>&nbsp;<a href=\"https://github.com/hakavlad/tird/blob/main/docs/MANPAGE.md\">man page</a></b></td>\n</tr>\n\n<tr>\n<td>&nbsp;\ud83d\udcd1&nbsp;</td>\n<td><b>&nbsp;<a href=\"https://github.com/hakavlad/tird/blob/main/docs/SPECIFICATION.md\">Specification</a></b></td>\n</tr>\n\n<tr>\n<td>&nbsp;\ud83d\udcc4&nbsp;</td>\n<td><b>&nbsp;<a href=\"https://github.com/hakavlad/tird/blob/main/docs/INPUT_OPTIONS.md\">Input&nbsp;Options</a>&nbsp;&nbsp;&nbsp;</b></td>\n</tr>\n\n<tr>\n<td>&nbsp;\ud83d\udcd6&nbsp;</td>\n<td><b>&nbsp;<a href=\"https://github.com/hakavlad/tird/blob/main/docs/tutorial/README.md\">Tutorial</a></b></td>\n</tr>\n\n<tr>\n<td>&nbsp;\u2753&nbsp;</td>\n<td><b>&nbsp;<a href=\"https://github.com/hakavlad/tird/blob/main/docs/FAQ.md\">FAQ</a></b></td>\n</tr>\n\n<tr>\n<td>&nbsp;\ud83d\udce5&nbsp;</td>\n<td><b>&nbsp;<a href=\"https://github.com/hakavlad/tird/blob/main/docs/INSTALLATION.md\">Installation</a></b></td>\n</tr>\n\n</table><br>\n\n<details>\n  <summary>&nbsp;<b>Table of Contents</b></summary>\n\n> - [About](#about)\n> - [Goals](#goals)\n\n> - [Usage](#usage)\n> - [Input Options](#input-options)\n> - [Debug Mode](#debug-mode)\n\n> - [Payload](#payload)\n> - [Input Keying Material](#input-keying-material)\n\n> - [Cryptographic Primitives](#cryptographic-primitives)\n> - [Encrypted Data Format](#encrypted-data-format)\n\n> - [Low Observability and Minimizing Metadata](#low-observability-and-minimizing-metadata)\n\n> - [Hidden File System and Container Format](#hidden-file-system-and-container-format)\n> - [Storing and Carrying Concealed Encrypted Data](#storing-and-carrying-concealed-encrypted-data)\n\n> - [Time-Lock Encryption](#time-lock-encryption)\n\n> - [Tradeoffs and Limitations](#tradeoffs-and-limitations)\n> - [Warnings](#warnings)\n\n> - [LLM reports](#llm-reports)\n\n> - [Requirements](#requirements)\n\n> - [TODO](#todo)\n> - [Feedback](#feedback)\n\n</details>\n\n## About\n\n`tird` /t\u026ard/ *(an acronym for \"this is random data\")* is a file encryption tool focused on\n\n- <ins>minimizing metadata</ins> and\n- <ins>hiding encrypted data</ins>.\n\nWith `tird`, you can:\n\n1. Create files filled with random data to use as containers or keyfiles.\n2. Overwrite the contents of block devices and regular files with random data. This can be used to prepare containers and to destroy residual data.\n3. Encrypt file contents and comments. The encrypted data format (called cryptoblob) is a [padded uniform random blob (PURB)](https://en.wikipedia.org/wiki/PURB_(cryptography)): it looks like random data and has a randomized size. This reduces metadata leakage from file format and length, and also allows cryptoblobs to be hidden among random data. You can use keyfiles and passphrases at your choice.\n4. Create [steganographic](https://en.wikipedia.org/wiki/Steganography) (hidden, undetectable) user-driven file systems inside container files and block devices. Unlike [VeraCrypt](https://veracrypt.fr) and [Shufflecake](https://shufflecake.net/) containers, `tird` containers do not contain headers at all; the user specifies the location of the data in the container and is responsible for ensuring that this location is separated from the container.\n5. Prevent or resist [coercive](https://en.wikipedia.org/wiki/Coercion) attacks (keywords: [key disclosure law](https://en.wikipedia.org/wiki/Key_disclosure_law), [rubber-hose cryptanalysis](https://en.wikipedia.org/wiki/Deniable_encryption), [xkcd 538](https://xkcd.com/538/)). `tird` provides some forms of [plausible deniability](https://en.wikipedia.org/wiki/Plausible_deniability) out of the box, even if you encrypt files without hiding them in containers.\n\n> \\[!WARNING]\n> Users of `tird` **must** carefully read and understand the \"[Warnings](#warnings)\" section in the `README.md`. The tool's security relies heavily on the user's understanding of its limitations and operating it in a secure environment, especially regarding key management, debug mode usage, and interpreting MAC verification results.\n\n<i>\u2014 <a href=\"https://gemini.google.com/share/627c17c844b9\">Gemini</a></i>\n\n## Goals\n\n- **File Protection:** Ensuring protection for individual files, including:\n  - Symmetric encryption and authentication.\n  - Minimizing metadata leakage.\n  - Preventing access to data in cases of user coercion.\n  - Plausible deniability of payload existence.\n  - Hiding encrypted data.\n- **Stable Format:** Ensuring a stable encryption format with no [cryptographic agility](https://en.wikipedia.org/wiki/Cryptographic_agility) for long-term data storage.\n- **Simplicity:** Ensuring simplicity and avoiding [feature creep](https://en.wikipedia.org/wiki/Feature_creep): refusal to implement features that are not directly related to primary security goals.\n\n## Usage\n\nYou don't need to memorize command-line options to use `tird`. This tool features a prompt-based CLI: simply start it, select a menu option, and answer the questions that will follow.\n\n```\n$ tird\n\n                       MENU\n    \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\n    0. Exit              1. Info & Warnings\n    2. Encrypt           3. Decrypt\n    4. Embed             5. Extract\n    6. Encrypt & Embed   7. Extract & Decrypt\n    8. Create w/ Random  9. Overwrite w/ Random\n    \u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\nA0. Select an option [0-9]:\n```\n\n## Input Options\n\nThere are 5 groups of input options: A (Action), C (Custom), D (Data), K (Keys), P (Proceed). They are numbered for ease of description.\n\n```\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| A0. Select an option     | A. Select an action    |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| C0. Use custom settings? |                        |\n| C1. Time cost            | C. Set custom settings |\n| C2. Max padding size     |                        |\n| C3. Set fake MAC tag?    |                        |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| D1. Input file path      |                        |\n| D2. Comments             | D. Enter data,         |\n| D3. Output file path     |    data location,      |\n| D4. Output file size     |    data size           |\n| D5. Start position       |                        |\n| D6. End position         |                        |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| K1. Keyfile path         | K. Specify input       |\n| K2. Passphrase           |    keying material     |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| P0. Proceed?             | P. Confirm to continue |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n```\n\nA detailed description of these options with examples can be found [here](https://github.com/hakavlad/tird/blob/main/docs/INPUT_OPTIONS.md).\n\n## Debug Mode\n\n> \\[!WARNING]\n> Debug mode is not intended for use in production!\n\nStart `tird` with the `--debug` option to look under the hood while the program is running.\n\nEnabling debug mode additionally shows:\n\n- File operations:\n  - Opening and closing of file descriptors.\n  - Real paths to opened files.\n  - Movement of file pointers.\n- Byte strings related to cryptographic operations: salts, passphrases, digests, keys, nonces, and tags.\n- Some other information, including various sizes.\n\n## Payload\n\nThe payload that will be encrypted during cryptoblob creation consists of:\n\n- **Contents of one file:** This may be a regular file or a block device (an entire disk or partition). Maximum size: 16 exbibytes minus 832 bytes.\n- **Comments (optional):** An arbitrary string of up to 512 bytes. Decrypted comments will be displayed during decryption.\n\nSpecifying the payload in the UI looks as follows:\n\n```\nD1. File to encrypt: list.txt\n    I: path: 'list.txt'; size: 6,493 B (6.3 KiB)\nD2. Comments (optional, up to 512 B): Epstein client list, txt\n    I: comments will be shown as ['Epstein client list, txt']\n```\n\n## Input Keying Material\n\n`tird` provides the option to use passphrases and the contents of keyfiles to derive one-time keys.\n\n- **Keyfiles:** Specify none, one, or multiple keyfile paths. A keyfile path may be:\n  - A <ins>regular file</ins>. The contents of the keyfile will be hashed, and its digest will be used for further key stretching and key derivation.\n  - A <ins>block device</ins>. Handled the same as a regular keyfile: contents will be hashed.\n  - A <ins>directory</ins>. All files within the directory will be hashed and used as keyfiles.\n- **Passphrases:** Specify none, one, or multiple passphrases of up to 2048 bytes.\n\nThe order of input does not matter.\n\nSpecifying IKM in the UI looks as follows:\n\n```\nK1. Keyfile path (optional): foo\n    I: path: 'foo'; size: 1 B\n    I: reading and hashing contents of 'foo'\n    I: keyfile accepted\nK1. Keyfile path (optional):\nK2. Passphrase (optional):\nK2. Confirm passphrase:\n    I: passphrase accepted\n```\n\n## Cryptographic Primitives\n\nThe following cryptographic primitives are utilized by `tird`:\n\n- `ChaCha20` cipher ([RFC 8439](https://www.rfc-editor.org/rfc/rfc8439.html)) for data encryption.\n- `BLAKE2` ([RFC 7693](https://www.rfc-editor.org/rfc/rfc7693.html)) for hashing and authentication.\n- `Argon2` memory-hard function ([RFC 9106](https://www.rfc-editor.org/rfc/rfc9106.html)) for key stretching.\n- `HKDF` ([RFC 5869](https://www.rfc-editor.org/rfc/rfc5869.html)) for key derivation.\n\nFor more details, refer to the [specification](https://github.com/hakavlad/tird/blob/main/docs/SPECIFICATION.md).\n\n## Encrypted Data Format\n\n<img src=\"https://i.imgur.com/wAJyAJc.png\" width=\"280\" alt=\"256 shades of grey\">\n\nThe format of the encrypted data is quite simple and consists of ciphertext with a MAC tag, located *somewhere* among the surrounding random data:\n\n```\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| Random data | Ciphertext | MAC tag | Random data |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n|               Random-looking data                |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n```\n\n**The only data available is:**\n\n- This is random-looking data.\n- Its size.\n\nThe ciphertext size and its location within the cryptoblob are hidden.\n\n<details>\n  <summary>&nbsp;<b>Show more detailed scheme</b></summary>\n\n```\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| CSPRNG output:                                     |\n|     Salt for key stretching used with Argon2, 16 B |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| CSPRNG output:                                     |\n|     Randomized padding (header padding): 0-20% of  |\n|     the (unpadded size + 255 B) by default         |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| ChaCha20 output:                                   |\n|     Ciphertext, 512+ B, consists of:               |\n|     - Encrypted constant-padded comments, 512 B    |\n|     - Encrypted payload file contents, 0+ B        |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| BLAKE2 or CSPRNG output:                           |\n|     MAC tag or Fake MAC tag, 32 B                  |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| CSPRNG output:                                     |\n|     Randomized padding (footer padding): 0-20% of  |\n|     the (unpadded size + 255 B) by default         |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n| CSPRNG output:                                     |\n|     Salt for prehashing IKM used with BLAKE2, 16 B |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n```\n\n</details>\n\nData encrypted with `tird` cannot be distinguished from random data without knowledge of the keys. It also does not contain identifiable headers. `tird` produces cryptoblobs that contain bilateral [randomized padding](https://en.wikipedia.org/wiki/Padding_(cryptography)#Randomized_padding) with uniform random data (PURBs). This minimizes metadata leaks from the file format and makes it possible to hide cryptoblobs among other random data. Bilateral padding also conceals the exact location of the ciphertext and MAC tag within the cryptoblob.\n\n## Low Observability and Minimizing Metadata\n\n> While the content of an encrypted message is protected, its size, its provenance, its destination\u2026 are not. Data is hidden, metadata is shown.\n\n<i>\u2014 <a href=\"https://loup-vaillant.fr/articles/rolling-your-own-crypto\">Loup Vaillant</a></i>\n\n|![](https://i.imgur.com/ArRAis1.jpeg)<br>Vs.<br>![](https://i.imgur.com/Oa3y3qg.jpeg)|\n|-|\n\n- PURB format:\n  - Encrypted files look like random data.\n  - Encrypted files have a randomized size: do not reveal the payload size.\n- Do not prove that the entered keys are incorrect.\n- Prompt-based CLI: no leakage of used options through shell history.\n- The output file path is user-defined and is not related to the input file path by default.\n- Optional: hiding encrypted data in containers.\n\n## Hidden File System and Container Format\n\n`tird` employs a technique that is [described](https://en.wikipedia.org/wiki/List_of_steganography_techniques#Digital) as follows:\n\n> Concealing data within encrypted data or within random data. The message to conceal is encrypted, then used to overwrite part of a much larger block of encrypted data or a block of random data (an unbreakable cipher like the one-time pad generates ciphertexts that look perfectly random without the private key).\n\nYou can encrypt files and embed cryptoblobs into containers starting at arbitrary positions. After writing the cryptoblob, you will need to remember its location in the container (the starting and ending positions), which will be used later to extract the cryptoblobs. In this way, you can create a **hidden, headerless, user-driven file system** inside a container:\n\n- It is **hidden** because it is impossible to distinguish between random container data and cryptoblob data, as well as to determine the location of written cryptoblobs without knowing the positions and keys.\n- It is **headerless** because containers do not contain any headers; all data about cryptoblob locations must be stored separately by the user.\n- The starting position of the cryptoblob in the container is **user-defined**, and the **user must** store both the starting and ending positions separately from the container. This is why it is called a **user-driven file system**.\n\nAny file, disk, or partition larger than the minimum cryptoblob size (831 B) can be a valid container. Cryptoblobs can be embedded into any area.\n\n**Examples of Valid Containers Include:**\n\n1. Specially generated files with random data.\n2. `tird` cryptoblobs, as they contain pockets \u2014 unauthenticated padding of random data \u2014 by default, which can be used to embed smaller cryptoblobs.\n3. Disk areas containing random data. For example, you can overwrite a disk with random data, format it in FAT32 or exFAT, and use a large portion of the disk, leaving a few dozen MB from the beginning. The disk will appear empty unless you add some files to it.\n4. [LUKS](https://en.wikipedia.org/wiki/Linux_Unified_Key_Setup) encrypted volumes.\n5. VeraCrypt containers, even those that already contain hidden volumes.\n\n**Example of Container Structure:**\n\n```\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+ <\u2014 Position 0 of the container\n|         |             |\n|         | Random data |\n|         |             |\n|         +\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+ <\u2014 Cryptoblob1 start position\n| Header- |             |\n| less    | Cryptoblob1 |\n|         |             |\n| Layer   +\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+ <\u2014 Cryptoblob1 end position\n|         | Random data |\n| Cake    +\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+ <\u2014 Cryptoblob2 start position\n|         |             |\n|         | Cryptoblob2 |\n|         |             |\n|         +\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+ <\u2014 Cryptoblob2 end position\n|         | Random data |\n+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014\u2014+\n```\n\n#### Visualization of Embedding\n\nThe next image visualizes how hard it is to distinguish one random data entry from another and the process of embedding cryptoblobs in a container.\n\n<details>\n  <summary>&nbsp;<b>Show Images</b></summary>\n\n<br>\n\n*Empty container with random data:*\n<img src=\"https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/container.png\" width=\"800\" alt=\"Container\">\n\n*One cryptoblob embedded in the container:*\n<img src=\"https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embed1.png\" width=\"800\" alt=\"Embedded1\">\n\n*Two cryptoblobs embedded in the container:*\n<img src=\"https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embed2.png\" width=\"800\" alt=\"Embedded2\">\n\n*Three cryptoblobs embedded in the container:*\n<img src=\"https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embed3.png\" width=\"800\" alt=\"Embedded3\">\n\n*Animation: visualization of embedding:*\n<img src=\"https://raw.githubusercontent.com/hakavlad/tird/refs/heads/main/images/embedding/embedding.gif\" width=\"800\" alt=\"GIF: visualization of embedding\">\n\n</details>\n\n## Storing and Carrying Concealed Encrypted Data\n\nPlease look at the following screenshot.\n\n<img src=\"https://i.imgur.com/2tpEhTw.png\" width=\"839\" alt=\"Screenshot\">\n\nIt looks like this 16 GB volume contains only one 8.7 MiB file. Is it really true? Maybe yes, maybe no.\n\nThe file system tells us that there is only one file here. But is there really only one file on the volume? We cannot determine this using the file system. In fact, data may be located outside the file system and be undetectable by file system tools. The 15.2 GiB of space marked as free may be occupied by a hidden file system. This \"free\" space may be taken up by hidden encrypted data.\n\nCan we disprove the existence of this data? Yes, for example, by examining the entropy level of this free space using `binwalk`. Low entropy indicates a likely absence of hidden data. High entropy *does not*, *by itself*, prove the presence of encrypted hidden data. Areas with high entropy can be either just residual data or hidden encrypted data.\n\nIf you are interested in hiding data outside the visible file system, then `tird` is at your service to provide an Invisibility Cloak for your files.\n\n## Time-Lock Encryption\n\n<img src=\"https://i.imgur.com/65xm1mK.jpeg\" width=\"280\" alt=\"TLE image\">\n\nTime-lock encryption (TLE) can be used to prevent an adversary from quickly accessing plaintexts in the event of an IKM compromise (in case of user coercion, for example). In our implementation, it is actually a PoW-based time-lock key derivation. The \"Time cost\" input option specifies the number of Argon2 passes. If you specify a sufficiently high number of passes, it will take a significant amount of time to perform them. However, an attacker will require the same amount of time when using similar hardware. The execution of Argon2 cannot be accelerated through parallelization, so it is expected that the time spent by an attacker will be approximately the same as that spent by the defender.\n\nThis TLE implementation works offline, unlike [tlock](https://github.com/drand/tlock).\n\nUse custom options and set the desired \"Time cost\" value:\n\n```\nC0. Use custom settings? (Y/N, default=N): y\n    I: use custom settings: True\n    W: decryption will require the same [C1] and [C2] values!\nC1. Time cost (default=4): 1000000\n    I: time cost: 1,000,000\n```\n\n**Plausible TLE:** The adversary does not know the actual value of the time cost, so you can plausibly misrepresent the number of passes. The adversary cannot refute your claim until they attempt to decrypt the cryptoblob using the specified time cost value.\n\n## Tradeoffs and Limitations\n\n- `tird` does not support:\n  - [Public-key cryptography](https://en.wikipedia.org/wiki/Public-key_cryptography).\n  - File compression.\n  - ASCII armored output.\n  - [Reed\u2013Solomon error correction](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction).\n  - Splitting the output into chunks.\n  - Use of [standard streams](https://en.wikipedia.org/wiki/Standard_streams) for processing files (not intended for automated scripts).\n  - Low-level block device reading and writing on MS Windows. As a result, these devices cannot be used as keyfiles, cannot be overwritten, and cannot be encrypted or embedded.\n- `tird` does not provide:\n  - A graphical user interface.\n  - A password generator.\n- `tird` cannot handle (encrypt/embed) more than one file in one pass. Encryption of directories and multiple files is not supported.\n- `tird` does not fake file access, modification, and creation timestamps (atime, mtime, ctime).\n- `tird`'s encryption speed is not very high (up to 420 MiB/s in my tests).\n\n## Warnings\n\n> Crypto can help, but it won\u2019t save you from misuse, vulnerabilities, social engineering, or physical threats.\n\n<i>\u2014 <a href=\"https://loup-vaillant.fr/articles/rolling-your-own-crypto\">Loup Vaillant</a></i>\n\n<img src=\"https://i.imgur.com/g84qgw8.jpeg\" width=\"600\" alt=\"DANGER MINES\">\n\n- \u26a0\ufe0f The author does not have a background in cryptography.\n- \u26a0\ufe0f The code has no automated test coverage.\n- \u26a0\ufe0f `tird` has not been independently security audited by humans.\n- \u26a0\ufe0f `tird` is ineffective in a compromised environment; executing it in such cases may cause disastrous data leaks.\n- \u26a0\ufe0f `tird` is unlikely to be effective when used with short and predictable keys.\n- \u26a0\ufe0f `tird` does not erase its sensitive data from memory after use.\n- \u26a0\ufe0f Sensitive data may leak into swap space.\n- \u26a0\ufe0f `tird` always releases unverified plaintext, violating [the Cryptographic Doom Principle](https://moxie.org/2011/12/13/the-cryptographic-doom-principle.html); decrypted output is untrusted until the MAC tag is verified.\n- \u26a0\ufe0f Padding contents are never authenticated; authentication only applies to the ciphertext, salts, and certain sizes.\n- \u26a0\ufe0f Padding sizes depend on secret values.\n- \u26a0\ufe0f `tird` does not sort digests of keyfiles and passphrases in constant-time.\n- \u26a0\ufe0f Overwriting file contents does not guarantee secure destruction of data on the media.\n- \u26a0\ufe0f You cannot prove to an adversary that your random data does not contain encrypted information.\n- \u26a0\ufe0f `tird` protects data, not the user; it cannot prevent torture if you are under suspicion.\n- \u26a0\ufe0f Key derivation consumes 1 GiB RAM, which may lead to performance issues or crashes on low-memory systems.\n- \u26a0\ufe0f Development is not complete, and there may be backward compatibility issues.\n\n## LLM reports\n\n<img src=\"https://i.imgur.com/Ab8rSlc.jpeg\" width=\"200\" alt=\"\">\n\n- [Tird Code Security Audit Report (v0.19.0)](https://gemini.google.com/share/6390743bb873); Target: [d016bd5](https://github.com/hakavlad/tird/tree/d016bd51571cd24ea0b21b8959dc01c4e7a69bee); Date: April 13, 2025; Auditor: Gemini 2.5 Pro (experimental)\n- [Security Audit Report: tird.py (v0.19.0)](https://gemini.google.com/share/82c80109c0c9); Target: [105f2dd](https://github.com/hakavlad/tird/tree/105f2ddbcace2802e2372f25c7aaae028ae4b357); Date: April 24, 2025; Auditor: Gemini 2.5 Pro (experimental)\n- [Tird Security Review (v0.20.0)](https://gemini.google.com/share/754c591bab98); Target: [ba504f9](https://github.com/hakavlad/tird/tree/ba504f92f5f40a8557ab4e1e5c6cc7fbc689a0cd); Date: May 4, 2025; Auditor: Gemini 2.5 Pro (experimental)\n\n## Requirements\n\n- Python >= 3.9.2\n- [cryptography](https://pypi.org/project/cryptography/) >= 2.1 (provides `HKDF` and a fast `ChaCha20` implementation)\n- [PyNaCl](https://pypi.org/project/PyNaCl/) >= 1.2.0 (provides fast implementations of `Argon2` and `BLAKE2`)\n- [colorama](https://pypi.org/project/colorama/) >= 0.4.6 (Windows-specific)\n\n## TODO\n\nWrite or improve the documentation:\n\n- Features\n- User Guide\n- Specification\n- Design Rationale\n\n## Feedback\n\nPlease feel free to ask questions, leave feedback, or provide critiques in the [Discussions](https://github.com/hakavlad/tird/discussions) section.\n",
    "bugtrack_url": null,
    "license": null,
    "summary": "A file encryption tool focused on minimizing metadata and hiding encrypted data",
    "version": "0.22.0",
    "project_urls": {
        "Bug Tracker": "https://github.com/hakavlad/tird/issues",
        "Discussions": "https://github.com/hakavlad/tird/discussions",
        "Documentation": "https://github.com/hakavlad/tird/blob/main/README.md",
        "Homepage": "https://github.com/hakavlad/tird",
        "Repository": "https://github.com/hakavlad/tird"
    },
    "split_keywords": [
        "encryption",
        " file-encryption",
        " hiding",
        " data-hiding",
        " plausible-deniability",
        " deniable-encryption",
        " purb",
        " time-lock",
        " undetectable",
        " stealth",
        " steganography"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "eae6873fd518bbf5539a787ea912e4ee4257e9c6aeaa03e3f067d9bcd6af5bd7",
                "md5": "db3b56f09d7df64203f83281e131e3c3",
                "sha256": "ca01f1d9f6543eda2f38e87395f3736ec5fcd21365bbbed99cca09424e9e2d37"
            },
            "downloads": -1,
            "filename": "tird-0.22.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "db3b56f09d7df64203f83281e131e3c3",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9.2",
            "size": 47980,
            "upload_time": "2025-08-26T18:28:37",
            "upload_time_iso_8601": "2025-08-26T18:28:37.917323Z",
            "url": "https://files.pythonhosted.org/packages/ea/e6/873fd518bbf5539a787ea912e4ee4257e9c6aeaa03e3f067d9bcd6af5bd7/tird-0.22.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "32a488d055f3c6d2f86b9213d4993ce6d14fae3bfbade7d724abdf4633115c94",
                "md5": "638f46da69ac312fb27ff72c59776ae9",
                "sha256": "b61dc2a3a0b374e137c9547718c7821c8ab5f31badf6f81a517ce8dee20967c3"
            },
            "downloads": -1,
            "filename": "tird-0.22.0.tar.gz",
            "has_sig": false,
            "md5_digest": "638f46da69ac312fb27ff72c59776ae9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9.2",
            "size": 56206,
            "upload_time": "2025-08-26T18:28:39",
            "upload_time_iso_8601": "2025-08-26T18:28:39.700213Z",
            "url": "https://files.pythonhosted.org/packages/32/a4/88d055f3c6d2f86b9213d4993ce6d14fae3bfbade7d724abdf4633115c94/tird-0.22.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-26 18:28:39",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "hakavlad",
    "github_project": "tird",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "tird"
}
        
Elapsed time: 3.33839s