{"id":24058238,"url":"https://github.com/ctsrc/base256","last_synced_at":"2026-04-02T02:22:00.875Z","repository":{"id":57502828,"uuid":"117576854","full_name":"ctsrc/Base256","owner":"ctsrc","description":"Encode and decode data in base 256 easily typed words","archived":false,"fork":false,"pushed_at":"2023-10-25T02:15:30.000Z","size":163,"stargazers_count":53,"open_issues_count":2,"forks_count":3,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-12T06:46:45.558Z","etag":null,"topics":["command-line-tools","decoding","encoding"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/base256","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ctsrc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-01-15T17:48:54.000Z","updated_at":"2025-02-21T14:19:21.000Z","dependencies_parsed_at":"2022-09-02T01:51:55.532Z","dependency_job_id":"b5ed825f-c33c-4747-acf3-dee3f84f8415","html_url":"https://github.com/ctsrc/Base256","commit_stats":{"total_commits":114,"total_committers":1,"mean_commits":114.0,"dds":0.0,"last_synced_commit":"a7dde830133a56452885f5b8a8a41f0e260f2b5a"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2FBase256","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2FBase256/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2FBase256/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2FBase256/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ctsrc","download_url":"https://codeload.github.com/ctsrc/Base256/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250360248,"owners_count":21417717,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line-tools","decoding","encoding"],"created_at":"2025-01-09T05:56:32.292Z","updated_at":"2026-04-02T02:22:00.806Z","avatar_url":"https://github.com/ctsrc.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `lastresort`(1) – Encode and decode data in base 256 easily typed words\n\n[![Crates.io](https://img.shields.io/crates/v/base256?style=flat-square)](https://crates.io/crates/base256)\n[![Crates.io](https://img.shields.io/crates/d/base256?style=flat-square)](https://crates.io/crates/base256)\n[![Crates.io](https://img.shields.io/docsrs/base256?style=flat-square)](https://docs.rs/crate/base256/latest)\n[![License](https://img.shields.io/badge/license-ISC-blue?style=flat-square)](LICENSE)\n[![GitHub stars](https://img.shields.io/github/stars/ctsrc/Base256?style=social)](https://github.com/ctsrc/Base256#start-of-content)\n\nYou might expect data encoded in base 256 to be more space efficient\nthan data encoded in [base 16](https://en.wikipedia.org/wiki/Hexadecimal)\nor [base 64](https://en.wikipedia.org/wiki/Base64), but with this particular\nset of symbols, that is not the case! As a natural consequence of this,\nyou have to type more, not less, when you manually input data\nusing this base 256 encoding instead of base 16 or some other\ncompact representation.\n\nSo, why this base 256 encoding?\n\nManually typing out base 64 is painful. Same goes for base 16.\nBoth of these (base 64 and base 16), and particularly base 16,\nare prone to make you lose track of where you are\nwhile reading and typing or speaking.\n\n`lastresort` aims to make manual input of binary data onto a computer\nby either keyboard or voice input less error-prone compared to\ntyping in the base 16 or base 64 encoding of said data.\n\nSample use-cases include:\n\n- typing in your SSH private key on a computer that is running a\n  live USB stick copy of its OS without persistent storage,\n  and which doesn't have a usable webcam leaving you\n  unable to enter the data using a QR-code.\n- relaying the contents of binary files to another person\n  over a voice channel.\n\nHere is a quick example:\n\nImagine a file with three bytes in it. A hexadecimal dump of this file\nmight look like:\n\n```text\n00000000: 0505 05                                  ...\n```\n\nIn other words, this file contains three bytes `0x05 0x05 0x05`.\n\nIn base64 this is:\n\n```text\nBQUF\n```\n\nThat's not so bad, and it's quick and easy to type or to read out loud\nin either base 16 or base 64 encoding.\n\nBut when the amount of data increases, it becomes more and more tricky\nto manually type in the bytes by hand or to read them out loud in base 16\nor in base 64.\n\nIn `lastresort` base 256 using the default codec PGP Word List, the bytes\nfrom the example above are represented as:\n\n```text\nadult amulet adult\n```\n\nBy now, you should see both:\n\n- Why the name of this command is `lastresort`, and\n- How in the case of greater amount of bytes, `lastresort` can be\n  of great help :)\n\n## Codecs\n\n`lastresort` supports the following codecs:\n\n- PGP Word List, the default codec\n- EFF Short Wordlist 2.0, the legacy codec\n\n### PGP Word List\n\n\u003e The PGP Word List [...] is a list of words for conveying data bytes\n\u003e in a clear unambiguous way via a voice channel. They are analogous\n\u003e in purpose to the NATO phonetic alphabet used by pilots,\n\u003e except a longer list of words is used, each word corresponding\n\u003e to one of the 256 distinct numeric byte values.\n\u003e\n\u003e [...]\n\u003e\n\u003e The list is actually composed of two lists [...]. Two lists are used\n\u003e because reading aloud long random sequences of human words\n\u003e usually risks three kinds of errors:\n\u003e 1) transposition of two consecutive words,\n\u003e 2) duplicate words, or\n\u003e 3) omitted words.\n\u003e\n\u003e To detect all three kinds of errors, the two lists are used alternately\n\u003e for the even-offset bytes and the odd-offset bytes in the byte sequence.\n\nhttps://en.wikipedia.org/wiki/PGP_word_list\n\n### EFF Short Wordlist 2.0\n\nThe EFF Short Wordlist 2.0 is a list of memorable and distinct words\nwith a few additional features making the words easy to type:\n\n\u003e * Each word has a unique three-character prefix. This means that future\n\u003e   software could auto-complete words in the passphrase after the user\n\u003e   has typed the first three characters\n\u003e * All words are at least an edit distance of 3 apart. This means that\n\u003e   future software could correct any single typo [...] (and in many cases\n\u003e   more than one typo).\n\nhttps://www.eff.org/deeplinks/2016/07/new-wordlists-random-passphrases\n\nThis wordlist is also used in the `pgen` passphrase generator.\nSee https://github.com/ctsrc/pgen for more about `pgen`.\n\nIn `lastresort`, 256 of the words from this list are used\nwhen using the legacy codec.\n\n## Example input and outputs using the different codecs\n\nIn the `sample_data/original` directory of this repository,\nwe have a file named `id_ed25519` containing the following\nOpenSSH ed25519 private key:\n\n```text\n-----BEGIN OPENSSH PRIVATE KEY-----\nb3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\nQyNTUxOQAAACCdE5ZT2FyAqO/5dfMJHZ2LsKdK95x1Jo/kJB8es4O2HQAAAJiy+V66svle\nugAAAAtzc2gtZWQyNTUxOQAAACCdE5ZT2FyAqO/5dfMJHZ2LsKdK95x1Jo/kJB8es4O2HQ\nAAAEAAr0Ou+od9Jnc+qb0VTq4zt3gF60+0ITRlL3HybqGLG50TllPYXICo7/l18wkdnYuw\np0r3nHUmj+QkHx6zg7YdAAAAEGVyaWtuQGxpYmVyYXRpb24BAgMEBQ==\n-----END OPENSSH PRIVATE KEY-----\n```\n\nFor the sake of brevity, the base 256 encoded output that results\nwhen using the legacy encoder is omitted from this README.\n\nThe base 256 encoded output that results when using the default\nencoder is shown in the subsection below.\n\n### Example output using the PGP Word List encoder\n\nIf we run `lastresort` with the above private key `id_ed25519`\nas input, and we use the PGP Word List codec:\n\n```zsh\ncargo run -- -e pgp -i sample_data/original/id_ed25519 | fold -w 78 -s\n```\n\nWe get the following base 256 encoded output:\n\n```text\nbutton commando button commando button detergent crusade disable dogsled \nenchanting bison enrollment drumbeat dinosaur drifter escapade dwelling \ndisbelief bison enterprise Dupont disruptive egghead detector eating dinosaur \nbison divisive crusade fascinate button commando button commando button \narmistice flagpole congregate crowfoot hemisphere flagpole hideaway drifter \ninsincere fallout determine chatter impartial enlist exodus Geiger inception \nflytrap hazardous crusade detector cranky detector cranky detector crowfoot \ndisable chopper inertia flagpole hesitate edict detector cranky detector \ncranky dinosaur flagpole hesitate classroom indigo enlist equation cranky \ndetector cranky detector cranky detector cranky detector cranky detergent \ncranky detector cranky detector dreadful infancy cranky detector cranky \ndetector highchair insincere flatfoot conformist framework inception enlist \nexistence allow equation inverse enchanting eating everyday indulge \nenrollment drunken detector cranky detector crucial determine flytrap \ndinosaur chopper filament eating conformist cubic informant cranky hydraulic \ndropper component chopper graduate fragile embezzle dosage disbelief enlist \nconformist drainage impetus dragnet graduate dragnet crossover chopper \ninferno chatter distortion goggles component Geiger distortion crowfoot \ncouncilman fracture impetus choking enrollment checkup disbelief drunken \ndetector cranky detector dosage handiwork inverse coherence egghead corporate \nChristmas impetus hotdog hemisphere fracture armistice hockey hamburger \ncranky detector cranky detector highchair insincere flatfoot conformist \nframework inception enlist existence drunken informant drifter Eskimo edict \ninferno dropper equation cranky detector cranky determine crucial graduate \ncrusade consulting enlist Eskimo checkup direction inverse detector gremlin \nenrollment cement consulting flytrap guitarist dreadful distortion deckhand \nfilament checkup document hamlet divisive flytrap divisive classroom \nconsulting indulge confidence dosage holiness cement headwaters dosage \ndetergent classic gravity hamlet consensus dropper conformist deckhand \nequation allow detector cranky detector crusade detector cranky impartial \nchairlift enrollment hockey coherence goggles graduate classroom distortion \nglucose gossamer briefcase hydraulic flagpole concurrent egghead Eskimo \ngremlin consensus involve inception chisel hamburger cubic corporate \nchairlift coherence chairlift disruptive eating equipment Glasgow document \nchisel disbelief inverse glossary gremlin disable drainage disable chopper \nconcurrent eating hemisphere Glasgow enterprise endow exodus dogsled \ndetermine goggles corrosion cement hemisphere chatter councilman indoors \nheadwaters flytrap hideaway endow indigo indoors armistice goldfish \nconcurrent guidance congregate glucose disbelief edict hesitate gazelle \ncoherence drunken headwaters deckhand inferno Christmas insincere framework \ncorrosion endow graduate cranky detector cranky detector crusade disable \negghead informant fallout existence highchair indigo drunken disable indulge \nhurricane endow hesitate egghead informant endow exodus Dupont hurricane \nflagpole conformist choking detergent cranky hamburger dreadful dinosaur \ncrowfoot equation commence decadence allow commando button commando button \ncommando crusade enchanting crumpled cannonball dropper enterprise crusade \nenchanting dwelling escapade deckhand cannonball drumbeat equipment dogsled \nexamine cranky Eskimo crusade cannonball dragnet dinosaur endow commando \nbutton commando button commando allow\n```\n\n## Compression\n\nThe preferable way to deal with compression, when compression is desired,\nis to separately compress the data first using for example gzip, xz, bzip2,\nbrotli or lzma, depending on your requirements and which compression tools\nyou have available on your devices.\n\nThen use lastresort to encode the compressed data. On the other device\nyou then decode with lastresort and then decompress that with the decompression\ntool corresponding to the compression tool you used.\n\nPractical example using the file `sample_data/original/id_ed25519` as the\ndata we want to compress, encode, type in on another device and\ndecode and decompress:\n\n- Compress data from example file `sample_data/original/id_ed25519` with xz\n  and then encode it.\n\n  ```zsh\n  xz \u003c sample_data/original/id_ed25519 | lastresort | fold -w 78 -s | awk '{$1=$1};1'\n  ```\n\n- On the other device, input the encoded words into a text file\n  and then decode and decompress that\n\n  ```zsh\n  mkdir -p ~/tmp/\n  vim ~/tmp/id_ed25519_compressed_words.txt\n  lastresort -d \u003c ~/tmp/id_ed25519_compressed_words.txt | unxz \u003e ~/tmp/id_ed25519\n  ```\n\n## Usage\n\n```\nlastresort [-d | --decode] [-i \u003cINPUT_FILE\u003e] [-o \u003cOUTPUT_FILE\u003e]\nlastresort -h | --help\nlastresort -V | --version\n```\n\nWith no options, `lastresort` reads raw data from stdin\nand writes encoded data as a continuous block\nof space-separated human words to stdout.\n\n### Options\n\n`-d`, `--decode` `[\u003cDECODER\u003e]` Decode data (default action is to encode data).\nDefault: `pgp`. Possible values: `pgp`, `eff`.\n\n`-e`, `--encoder` `\u003cENCODER\u003e` Encoder to use.\nPossible values: `pgp`, `eff`.\nIf encoder is not specified, the `pgp` encoder will be used.\nConflicts with option `-d`.\n\n`-i`, `--input` `\u003cINPUT_FILE\u003e` Read input from `INPUT_FILE`.\nDefault is stdin; passing `-` also represents stdin.\n\n`-o`, `--output` `\u003cOUTPUT_FILE\u003e` Write output to `OUTPUT_FILE`.\nDefault is stdout; passing `-` also represents stdout.\n\n`-h`, `--help` Print usage summary and exit.\n\n`-V`, `--version` Print version information and exit.\n\n## See also\n\n* `pgen`(1) on [crates.io](https://crates.io/crates/pgen) / [GitHub](https://github.com/ctsrc/Pgen)\n\n## Installation\n\n1. [Install Rust](https://www.rust-lang.org/en-US/install.html).\n2. Run `cargo install base256`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctsrc%2Fbase256","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fctsrc%2Fbase256","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctsrc%2Fbase256/lists"}