stegtext 0.2.0

Text steganography command-line tool and library.
Documentation
# stegtext

Text [steganography][] command-line tool and library.

Links:

- [stegtext Git Repository (codeberg.org)][codeberg-stegtext]
- [stegtext Package Page (crates.io)][crates-io-stegtext]
- [stegtext API Documentation (docs.rs)][docs-rs-stegtext]

## How It Works

[Unicode][] has many [homoglyphs][]; that is, different characters with
the same appearance.

This tool hides a secret value in plain text by selectively replacing
characters with [homoglyphs][].

The encoded result is visually indistinguishable from the plain text.

The amount of secret data that you can hide depends on the embedding
capacity (the number of characters with [homoglyphs][]) of the plain
text.

See the [Technical Details section of the API
documentation][tech-details] for additional details.

## Example

Hide a secret message in plain text:

```text
# show "input.txt"
$ cat input.txt
The Hitchhiker's Guide to the Galaxy is a 1979 science fiction comedy
novel by English author Douglas Adams, adapted from the first four parts
of his radio comedy series of the same name.

# hide secret, write to "hidden.txt"
$ stegtext encode 'hi there' < input.txt > hidden.txt

# show "hidden.txt"
$ cat hidden.txt
Тhe Нitchhiker'ѕ Guide to the Galaxy is a 1979 ѕcіеncе fictіon соmedy
novel by Englіsh author Douglаs Аdаmѕ, adapted frоm the fіrѕt four рartѕ
of hiѕ rаdio сomedу ѕеriеs оf the sаmе name.

# read secret from "hidden.txt"
$ stegtext decode < hidden.txt
hi there
```

## Install

[stegtext][] can be installed several ways:

- as a binary from the [stegtext package on crates.io][crates-io-stegtext]
- as a binary from the [stegtext Git repository][codeberg-stegtext]
- as a [container][]

### Install from Package

Install the [stegtext package][crates-io-stegtext] with `cargo
install`:

```sh
cargo install stegtext
```

### Install from Git Repository

Install directly from the `main` branch of the [Git
repository][codeberg-stegtext]:

```sh
cargo install --git https://codeberg.org/pablotron/stegtext
```

### Install as Container

Install as a [container][] with [Podman][]:

```sh
# pull container image
podman pull codeberg.org/pablotron/stegtext:latest
```

Run [container][]:

```sh
# container image url
IMAGE_URL=codeberg.org/pablotron/stegtext

# run ephemeral stegtext container, read text from "input.txt", hide
# secret "hi there", and write result to "hidden.txt"
podman run --rm -i $IMAGE_URL encode 'hi there' < input.txt > hidden.txt
```

[Container][] image notes:

- less than 750k in size
- contains stripped, statically-linked binary and nothing else
- can run rootless and with no capabilities (e.g. `--cap-drop ALL`)
- signed by [OpenPGP][] key ID `021136521548EB198F64FF738E182534CDD1F2B8`

## Build

Build release binary using `cargo build`:

```sh
# clone git repo
git clone https://codeberg.org/pablotron/stegtext
cd stegtext

# build release binary
cargo build --release
```

Build [stegtext][] container image using [Podman][]:

```sh
# clone git repo
git clone https://codeberg.org/pablotron/stegtext
cd stegtext

# build image
podman build -t stegtext:latest .
```

Run previously-built [stegtext][] container:

```sh
# run ephemeral stegtext container, read text from "input.txt", hide
# secret "hi there", and write result to "hidden.txt"
podman run --rm -i stegtext:latest encode 'hi there' < input.txt > hidden.txt
```

## Usage

Available subcommands:

- `capacity`: Print embedding capacity of input, in bytes.
- `encode`: Embed secret in text and then print result.
- `decode`: Extract secret from text and print it.
- `help`: Print usage.

## Rust Library

[stegtext][] can also be used as a [Rust][] library.  Here are a couple
of examples.

Hide secret in text:

```rust
// secret
const SECRET: [u8; 5] = *b"hello";

// input text
const TEXT: &str = "\
Тhe Нitсhhikеr's Guіdе to thе Galaxy is a 1979 ѕcіеncе fiсtion соmedy
novеl bу Englіѕh author Douglаѕ Adаmѕ, adарtеd frоm the fіrѕt four parts
of hiѕ radiо соmedу ѕеriеѕ оf thе sаmе name.";

// expected output
const EXP: &str = "\
Тhe Нitсhhikеr's Guide to the Galaxy is a 1979 ѕcіеncе fiсtion соmedy
noνеl by Еnglіsh author Dоuglаs Аdаms, аdарtеd from thе fіrst four parts
of hiѕ radiо соmedу ѕеriеѕ оf thе sаmе name.";

// encode secret, check result
assert_eq!(stegtext::encode(&SECRET, TEXT)?, EXP);
```

Get secret from text:

```rust
// text with embedded secret
const TEXT: &str = "\
Тhe Нitсhhikеr's Guide to the Galaxy is a 1979 ѕcіеncе fiсtion соmedy
noνеl by Еnglіsh author Dоuglаs Аdаms, аdарtеd from thе fіrst four parts
of hiѕ radiо соmedу ѕеriеѕ оf thе sаmе name.";

// decode secret, check result
assert_eq!(stegtext::decode(TEXT)?, "hello");
```

Get text embedding capacity:

```rust
// input text
const TEXT: &str = "\
Тhe Нitсhhikеr's Guіdе to thе Galaxy is a 1979 ѕcіеncе fiсtion соmedy
novеl bу Englіѕh author Douglаѕ Adаmѕ, adарtеd frоm the fіrѕt four parts
of hiѕ radiо соmedу ѕеriеѕ оf thе sаmе name. Іt centrеѕ оn the
misаdvеntureѕ оf Arthur Dent, the оnly man tо ѕurvive the destruction of
Earth, as he roams the cosmos and learns the truth behind his very
existence. The novel's namesake is an in-universe electronic travel
guide written in the form of an encyclopaedia, through which the story
is framed.";

// calculate capacity, check result
assert_eq!(stegtext::capacity(TEXT), 24);
```

Additional documentation is available here: [stegtext API
documentation][docs-rs-stegtext].

## Testing

Tests are run automatically as part of the [CI/CD][] pipeline (see
`.forgejo/workflows/ci.yml`) and release process (see `release.py` and
`Containerfile.release`).

However, you can manually run the audit, code coverage, linting, and
testing commands with the commands in the following sections.

### Audit Dependencies

Install [cargo-audit][] and then use `cargo audit` to check dependencies
for security vulnerabilities:

```text
cargo audit
    Fetching advisory database from `https://github.com/RustSec/advisory-db.git`
      Loaded 1271 security advisories (from /data/home/pabs/.cargo/advisory-db)
    Updating crates.io index
    Scanning Cargo.lock for vulnerabilities (22 crate dependencies)
```

### Check Code Coverage

Install [cargo-tarpaulin][] and use `cargo tarpaulin` to check [code
coverage][code coverage]:

```text
cargo tarpaulin --engine llvm --fail-under 95
...
|| Uncovered Lines:
|| src/bin/stegtext.rs: 80-84
|| src/lib.rs: 393, 434, 565
|| Tested/Total Lines:
|| src/bin/stegtext.rs: 5/10 +0.00%
|| src/lib.rs: 150/153 +0.03%
||
95.09% coverage, 155/163 lines covered, +0.06% change in coverage
```

### Lint Code

Use `cargo clippy` to run the code [linter][]:

```text
cargo clippy
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.04s
```

### Lint Markdown

Use [markdownlint-cli][] via [Podman][] to lint the [Markdown][] in
`README.md`:

```sh
# container image URL
IMAGE_URL=ghcr.io/igorshubovych/markdownlint-cli

# run markdownlint-cli in ephemeral container, lint README.md
podman run --rm -it -v .:/src -w /src $IMAGE_URL ./README.md
```

### Run Tests

Use `cargo test` to run the test suite and check the examples in the
[API][] documentation:

```text
cargo test
...
test result: ok. 12 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
```

[steganography]: https://en.wikipedia.org/wiki/Steganography
  "Steganography (Wikipedia)"
[homoglyphs]: https://en.wikipedia.org/wiki/Homoglyph
  "Homoglyph (Wikipedia)"
[stegtext]: https://codeberg.org/pablotron/stegtext
  "stegtext"
[codeberg-stegtext]: https://codeberg.org/pablotron/stegtext
  "stegtext Git Repository (codeberg.org)"
[crates-io-stegtext]: https://crates.io/crates/stegtext
  "stegtext Package Page (crates.io)"
[docs-rs-stegtext]: https://docs.rs/stegtext
  "stegtext API Documentation (docs.rs)"
[rust]: https://rust-lang.org/
  "Rust programming language"
[unicode]: https://en.wikipedia.org/wiki/Unicode
  "Unicode (Wikipedia)"
[podman]: https://podman.io/
  "Podman: open source container management engine"
[tech-details]: https://docs.rs/stegtext/latest/stegtext/#technical-details
  "Technical Details section of the stegtext API Documentation (docs.rs)"
[container]: https://en.wikipedia.org/wiki/Containerization_(computing)
  "Containerization (Wikipedia)"
[ci/cd]: https://en.wikipedia.org/wiki/CI/CD
  "Continuous Integration / Continuous Delivery (Wikipedia)"
[cargo-tarpaulin]: https://crates.io/crates/cargo-tarpaulin
  "Tarpaulin code coverage reporting tool."
[code coverage]: https://en.wikipedia.org/wiki/Code_coverage
  "Code coverage (Wikipedia)"
[linter]: https://en.wikipedia.org/wiki/Lint_(software)
  "Static code analysis tool to catch common mistakes"
[markdownlint-cli]: https://github.com/igorshubovych/markdownlint-cli
  "Markdown linter"
[markdown]: https://en.wikipedia.org/wiki/Markdown
  "Markdown lightweight markup language (Wikipedia)"
[cargo-audit]: https://docs.rs/cargo-audit/latest/cargo_audit/
  "Check Rust dependencies for vulnerabilities"
[api]: https://en.wikipedia.org/wiki/API
  "Application Programming Interface (Wikipedia)"
[openpgp]: https://en.wikipedia.org/wiki/OpenPGP
  "OpenPGP (Wikipedia)"