Skip to content

scode/saltybox

Repository files navigation

Introduction

Saltybox is a tool for encrypting files with a passphrase.

Its primary intended use-case is for encrypting small amounts of personal data for safe keeping on untrusted media (physical or otherwise).

Installation

Homebrew

brew install scode/dist-tap/saltybox

From source

Requires Rust.

$ cargo install --path .

Assuming ~/.cargo/bin is in your $PATH, saltybox is now ready to use.

Alternatively, you can build and run directly from the repository:

$ cargo build --release
$ ./target/release/saltybox --help

If you decide to use saltybox for anything important, please review guidance for use.

Usage

Here's how to encrypt a file (you will be interactively prompted for a passphrase):

saltybox encrypt -i allmysecrets.txt -o allmysecrets.txt.saltybox

And here is how to decrypt it afterwards (again, you will be interactively prompted for a passphrase):

saltybox decrypt -i allmysecrets.txt.saltybox -o allmysecrets.txt

And here is how to update a previously encrypted file in a manner that ensures the passphrase is not accidentally changed:

saltybox update -i allmysecrets-updated.txt -o allmysecrets.txt.saltybox

update requires -i and -o to reference different files. Using the same file (or a path alias that resolves to the same file) is rejected.

Features and limitations

  • Files must fit comfortably in memory and there is no support for encrypting a stream in an incremental fashion.
  • There is no attempt to lock the passphrase or derived key into memory. The passphrase may be paged to disk by the operating system. You are responsible for the security of the device on which you run this program.
  • File writes use atomic same-directory temporary files named .saltybox-*.tmp. On Unix, these temporary files are written with mode 0600 and then atomically renamed into place. In the event of a crash, stale .saltybox-*.tmp files may remain and should still be private (0600).
  • The format is based upon well known algorithms with exceedingly simple layering on top. scrypt is used for key stretching, nacl is used for encryption, and a base64 variant is used for encoding.
  • The amount of code is relatively small and light on dependencies.

Guidance for use

Use update whenever possible

Always use update when updating an existing encrypted file. This avoids the possibility of accidentally changing the passphrase by providing a different passphrase than what was used to encrypt the existing file. If you manually decrypt and re-encrypt, you lose this protection.

Keep a copy of saltybox

It is important to consider the possibility that saltybox disappears from github, or stops building because a dependency has changed or becomes unavailable. In order to ensure that you are able to decrypt your data if such a thing were to happen, the following steps are recommended:

  • Store a copy of the binary for your platform(s) in a safe place.
  • In a copy of the source code, run cargo vendor to download all necessary dependencies into the vendor directory. Ensure saltybox builds with cargo build --frozen --offline. Then store a copy of the complete source tree (including vendor and Cargo.lock) in a safe place.

In an emergency need to decrypt data, this should maximize your chances of being able to do so without relying on external projects/people aside from the Rust language tools themselves remaining available.

Format/API contract

  • Future versions if any will remain able to decrypt data encrypted by older versions.
  • The command line interface may change at any time. It is currently not intended for automated scripting (for this reason and others).
  • The code in this project is not meant to be consumed as a library and may be refactored or changed at will. It's possible this changes in the future, but if so it will be explicitly made clear.

Important crypto disclaimer

I am not a cryptographer and the code has not been reviewed by any cryptographers. Are you one? Please send me feedback ([email protected]).

Although I certainly did not attempt to invent any new cryptographic primitives and rather use well established trusted primitives, there is generally a risk that cryptographic primitives are used incorrectly when composed into a larger program.

Unfortunately, I have not been able to find a tool like this that satisfies my personal criteria for what I want to depend on for emergency life recovery media.

Details: Encrypted File Format (saltybox format version 1)

Saltybox encrypts files using a passphrase-based encryption scheme. The output is a text file containing an armored (ASCII text) string that represents the encrypted data. This section documents the format.

Armored (Text) Format

  • The contents of the file starts with the string saltybox1: which identifies the format.
  • This is followed by a base64url encoded (RFC 4648 Section 5, no padding) payload whose format is described below ("binary format").
    • Uses URL-safe base64 alphabet: - and _ instead of + and /
  • Example: saltybox1:RF0qX8mpCMXVBq6zxHfamdiT64s6Pwvb99Qj9gV61sMAAAAAAAAAFE6RVTWMhBCMJGL0MmgdDUBHoJaW
    • The 1 in the prefix indicates the format version. Future versions would use a different version number (e.g., saltybox2:).

Binary Format

The binary format contains the following, in order:

  1. Salt (8 bytes): Random salt used for key derivation.
  2. Nonce (24 bytes): Random nonce for the NaCl secretbox encryption.
  3. Length (8 bytes): Big-endian encoded signed 64-bit integer (int64) indicating the number of bytes in the sealed box that follows. This value must be non-negative and must not exceed the remaining length of the input data after the salt, nonce, and length fields. During decryption, invalid lengths (negative, too large, or causing truncation) are rejected as format errors.
  4. Sealed Box (variable length, as specified by the length field): The encrypted payload, sealed using NaCl's secretbox (XSalsa20 stream cipher with Poly1305 MAC). The sealed box contains the user's plaintext exactly - without any padding or additional metadata.

The encryption key is derived from the user-provided passphrase and the salt using scrypt with parameters:

  • N = 32768
  • r = 8
  • p = 1
  • Key length = 32 bytes

Golden Test Vectors

The repository includes comprehensive test vectors in testdata/golden-vectors.json for purpose of correctness/compatibility testing.

Usage

Run golden vector tests:

cargo test --test golden_vectors -- --ignored

(The arguments are required because by default not all golden vectors are tested in order to avoid adding multiple seconds to test time.)

Golden Vectors Format

The testdata/golden-vectors.json file contains a JSON array of test vectors. Each vector is an object with these fields:

  • plaintext: Base64-encoded plaintext data to encrypt
  • ciphertext: Armored (text format) expected ciphertext (e.g., saltybox1:...)
  • nonce: Base64-encoded nonce used for encryption
  • salt: Base64-encoded salt used for encryption
  • passphrase: Base64-encoded passphrase used for encryption
  • comment: Human-readable description of what the test case exercises

All binary data (including passphrases that may contain arbitrary bytes) is base64-encoded for safe JSON storage. The ciphertext is in the final armored text format that would be written to a file.

About

Passphrase based encryption

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages