Book cipher
Hide a message inside a passage you share with someone: with a 13-word key, “quick fox river” becomes 2 4 12, and those numbers decrypt back to the same words. Made for puzzles, escape rooms and history lessons. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Action
- Encrypt
- Result
- 2 4 12
- Key word count
- 13
- Positions
- 2, 4, 12
- Words
- quick, fox, river
A book cipher hides a short message by pointing at words that already exist in a shared passage instead of inventing a substitution alphabet. Paste any key text you and your counterpart both hold—a paragraph, a poem, or a printed page—then encrypt a phrase into a list of 1-based word positions, or decrypt those numbers back into the original words. Matching is case-insensitive, leading and trailing punctuation is stripped during tokenization, and any message words that do not appear in the key are listed so you can extend the passage or rephrase the plaintext. The engine is pure and deterministic: the same key and message always yield the same positions, with no network calls, random seeds, or clocks.
How the book cipher uses word positions
Classical book ciphers treat a shared text as a codebook. Instead of replacing letters with other letters, each unit of the secret message is written as a pointer into that text—most often a word index counted from the start of the passage. This tool implements a clear, teachable form of that idea: the key text is split on whitespace, each token has leading and trailing punctuation removed, and the resulting sequence is numbered from one.
When you encrypt, every word of the message is looked up case-insensitively against the first occurrence of the same word in the key list, and the cipher is the space-separated list of those 1-based positions. When you decrypt, the message field is read as integers separated by spaces, commas, or semicolons; each number is resolved to the word at that index in the key. Because only the first match is used, encrypt and decrypt stay unambiguous even when a word repeats later in the passage.
Non-letter characters outside word tokens never become positions on their own, so you always reason about whole words. This construction is intentionally weaker than modern cryptography and is meant for teaching, recreational puzzles, CTF warm-ups, and light reversible obfuscation—not for protecting real secrets in transit or at rest. Frequency and context still leak when the key is a known public book; treat the shared passage as a shared secret only in the same spirit as a classical party trick, not as an authenticated channel.
What you can do with it
Classroom crypto history
Show students how a shared passage becomes a codebook and how word indices encrypt and decrypt without a letter substitution alphabet.
Puzzle and escape-room design
Encode short clues as position lists that only open when players hold the same printed paragraph or poem.
CTF and hobby ciphers
Generate reversible book-cipher challenges and report missing key words so authors can tune the passage before publishing.
FAQ
What inputs does the book cipher need?
Optional action is encrypt (default) or decrypt. Encrypt expects plaintext words; decrypt expects 1-based position numbers.
What happens if a message word is not in the key?
Extend the key passage or rephrase the message to cover it.
What does a successful response include?
Result is space-separated positions on encrypt and space-separated words on decrypt.
What happens when a word appears more than once in the key passage?
The tool always uses its first occurrence, so every word has exactly one position. That keeps encryption and decryption unambiguous even when the same word turns up again later in the passage.
Is a book cipher safe for real secrets?
No. It is a classical cipher meant for teaching, puzzles and light, reversible hiding of a message. If the key is a well-known public book, word frequency and context can still give the message away.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/enc/book-cipher \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"key_text":"The quick brown fox jumps over the lazy dog near the river bank","message":"quick fox river"}'const res = await fetch("https://api.kit.forhosting.com/enc/book-cipher", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"key_text": "The quick brown fox jumps over the lazy dog near the river bank",
"message": "quick fox river"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/book-cipher",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"key_text": "The quick brown fox jumps over the lazy dog near the river bank",
"message": "quick fox river"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/book-cipher", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"key_text":"The quick brown fox jumps over the lazy dog near the river bank","message":"quick fox river"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"key_text":"The quick brown fox jumps over the lazy dog near the river bank","message":"quick fox river"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/book-cipher", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"key_text": "The quick brown fox jumps over the lazy dog near the river bank",
"message": "quick fox river"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.book_cipher",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Use it free in the browser for classroom demos and puzzle design, or call the identical logic through the API at $0.002 per successful request.
Encrypt, decrypt, and missing words
On encrypt the message is tokenized into words the same way as the key; each word is mapped to its first key position when present. Missing words do not abort a successful encrypt call: they are reported so authors can grow the key passage or drop rare vocabulary without guessing which token failed. Round-tripping encrypt then decrypt with the same key restores the key’s surface forms for every word that was present, which may differ in capitalization from the original plaintext while preserving the same dictionary entries. Send a required key_text string and a required message string, and optionally set action to encrypt or decrypt (encrypt is the default). The response includes the normalized action, how many words the key contains, the original message, a result string of space-separated positions for every word that was found, the parallel arrays of positions and surface-form words taken from the key, a missing_words list for tokens that never appear in the key, and counters words_found and words_total. On decrypt the message must contain only positive integer positions; a non-numeric fragment or a position larger than the key word count fails immediately with invalid_input naming the problem. Decrypt never invents missing vocabulary: every number either maps to a key word or rejects the request. Empty key text after tokenization, empty message after tokenization on encrypt, missing fields, and illegal action values also fail with invalid_input and are not charged.
API usage, pricing, and practical tips
Use action decrypt when the message is already a position list produced for this same key. Never reuse a public novel page as if it were a modern key: anyone who can guess the book can attempt the same lookups. Status is beta while the public surface stabilizes, but the position-mapping rules follow this fixed classical construction and will not change for identical inputs. Call the capability with key_text and message as required fields. Pricing for the hosted API is a flat $0.002 per successful request; validation failures such as a missing key_text, an empty passage, a non-integer decrypt token, or an out-of-range position do not consume balance. Prefer a passage long enough to cover your vocabulary so missing_words stays empty, and prefer distinctive wording so first-occurrence indices are easy to verify by hand. For pipelines, submit each message as its own task and collect results through your usual webhook or signed-link flow. Keep field names explicit rather than packing free-form prose into one blob: the contract stays aligned with OpenAPI, SDK types, and form controls, and it avoids ambiguous parsing of key versus ciphertext.
Technical questions
How much does the book cipher API cost?
Each successful API call costs $0.002. The same engine runs free in your browser with no account required. Invalid input is not charged.
Is the book cipher deterministic and secure?
It is fully deterministic for the same key_text, message, and action. It is a classical position cipher for teaching and puzzles, not modern cryptographic security.