Turning grille cipher
ATTACKATDAWN on a 4-by-4 grille becomes ATTCXAKAXXDTXAWN: letters go through the mask's holes, the mask turns a quarter turn four times, and the full square is read row by row. Letters keep their identity, only their order changes. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Text
- ATTACKATDAWN
- Size
- 4
- Calculation mode
- Encrypt
- Text
- ATTCXAKAXXDTXAWN
- Holes count
- 4
- Length
- 16
- Pad count
- 4
The turning grille cipher, also called a Fleissner grille, is a classical transposition system that hides order rather than letter values. You lay a square cardboard mask with cut-out holes over a blank grid, write the next plaintext letters through the openings, rotate the mask ninety degrees, and repeat until the grid is full; reading the filled square row by row yields the ciphertext. This capability implements that process deterministically: supply the text, an even grid size, the base hole pattern, and mode encrypt or decrypt. The engine validates that four clockwise turns cover every cell exactly once and reports an invalid grille when holes overlap, leave gaps, sit outside the board, or have the wrong count. Spaces and punctuation travel with the letters; short plaintext is padded with a single pad character so the message fills whole squares.
How the turning grille works
A turning grille is not a substitution cipher: every character keeps its identity and only its position changes. Fix an even side length n so the board has n squared cells. A valid mask for four quarter-turns has exactly one quarter of those cells open—n squared over four holes—chosen so that rotating the openings ninety degrees clockwise four times visits every cell once and never twice.
That combinatorial condition is the heart of the system: each rotation orbit under the square’s cyclic group contributes exactly one hole in the base mask. Encryption walks the four orientations in order. At each orientation the visible holes are sorted row-major, the next plaintext characters are written through them, and the mask turns.
When all four turns finish, the grid is complete and the ciphertext is the concatenation of rows from top to bottom, left to right. Decryption fills that same grid from the ciphertext in row-major order, then reads letters back out through the identical sequence of rotated holes, restoring the original order including any padding that was appended so the last block would fill. An odd side length leaves a centre cell fixed under rotation and is rejected as an invalid grille for this four-turn model.
Overlapping orbits, duplicate base holes, out-of-range coordinates, or the wrong hole count likewise fail validation before any character is moved, so callers always know whether the mask is a legal key.
How to read the scrambled result
Send text, size, holes, and mode. Text is the plaintext or ciphertext string; nothing is stripped or case-folded, so mixed case, spaces, and punctuation participate in the transposition like any other character. Size is an even integer from two through sixteen inclusive—the side of the square.
Holes is an array of objects each with integer row and col indices starting at zero; the length of that array must equal size squared divided by four. Round-trip by encrypting with a given size and hole pattern, then decrypting with the same pair; a different mask yields a different permutation and will not restore the original. Empty text is rejected.
Classroom, CTF, product use, and cost
History and cryptography courses use the turning grille to introduce geometric keys and orbit arguments before modern ciphers: students design a legal four-hole pattern on a four-by-four board, encrypt a short slogan, pass the ciphertext and mask description to a partner, and recover the slogan only when both sides share the same openings. Capture-the-flag authors hide flags under a published or partial grille and verify solver submissions against this same deterministic routine. Documentation writers embed encrypt and decrypt pairs in tutorials without hand-maintaining permutation tables for every rotation.
Do not treat a turning grille as confidentiality for real secrets—it is a teaching and puzzle tool—but do treat the hole pattern and size as the secret parameters of the toy system.
What you can do with it
Cryptography classroom labs
Students design a valid hole mask on an even grid, encrypt a sentence through four rotations, then recover it with the same size and holes—showing that geometry is the key.
CTF and puzzle authors
Hide short challenge strings under a published or partial turning grille and verify solver submissions against the same deterministic encrypt and decrypt pair.
Docs and classical-cipher playgrounds
Generate stable ciphertext examples for Fleissner and turning-grille tutorials without hand-maintaining rotation tables for every board size.
FAQ
What is a turning grille cipher?
A classical transposition cipher that writes letters through holes in a square mask, rotates the mask 90° three more times to fill the grid, then reads the square row by row. Letter values stay the same; only order changes.
Why must size be even?
This implementation uses four 90° turns with no fixed centre cell.
What makes a grille invalid?
Wrong hole count (not size²/4), duplicate or out-of-range openings, or any cell covered more than once or left uncovered after four rotations. The error message includes the phrase invalid grille.
Does decryption need the same holes and size?
Yes. Encrypt and decrypt use the same even size and the same base hole pattern. A different mask applies a different permutation and will not restore the original text.
What does it cost?
The interactive page runs free in your browser.
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/grille-cipher \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"ATTACKATDAWN","size":4,"holes":[{"row":0,"col":0},{"row":0,"col":1},{"row":0,"col":2},{"row":1,"col":1}],"mode":"encrypt"}'const res = await fetch("https://api.kit.forhosting.com/enc/grille-cipher", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "ATTACKATDAWN",
"size": 4,
"holes": [
{
"row": 0,
"col": 0
},
{
"row": 0,
"col": 1
},
{
"row": 0,
"col": 2
},
{
"row": 1,
"col": 1
}
],
"mode": "encrypt"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/grille-cipher",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "ATTACKATDAWN",
"size": 4,
"holes": [
{
"row": 0,
"col": 0
},
{
"row": 0,
"col": 1
},
{
"row": 0,
"col": 2
},
{
"row": 1,
"col": 1
}
],
"mode": "encrypt"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/grille-cipher", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"ATTACKATDAWN","size":4,"holes":[{"row":0,"col":0},{"row":0,"col":1},{"row":0,"col":2},{"row":1,"col":1}],"mode":"encrypt"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"ATTACKATDAWN","size":4,"holes":[{"row":0,"col":0},{"row":0,"col":1},{"row":0,"col":2},{"row":1,"col":1}],"mode":"encrypt"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/grille-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
{
"text": "ATTACKATDAWN",
"size": 4,
"holes": [
{
"row": 0,
"col": 0
},
{
"row": 0,
"col": 1
},
{
"row": 0,
"col": 2
},
{
"row": 1,
"col": 1
}
],
"mode": "encrypt"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.grille_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 the tool free on this page, or call the identical pure algorithm by API at $0.002 per request for classroom demos, CTF helpers, and reproducible documentation examples.
Calling the API and reading the result
Optional pad_char is a single character used only on encrypt when the message length is not a multiple of size squared; the default is capital X. Missing required fields, a non-string text, a non-even size, out-of-range holes, an overlapping or incomplete mask, an unknown mode, or a decrypt length that is not a multiple of the cell count all fail with invalid_input and a message that names the problem—invalid grille wording appears whenever the mask itself is the fault. On success the JSON includes text (the transformed string), mode (canonical encrypt or decrypt), size, holes (normalized and sorted), holes_count, length of the result, pad_count (how many pad characters were appended on encrypt, zero on decrypt), and blocks (how many full squares were processed). Prefer this endpoint when search intent is specifically a turning grille, Fleissner grille, or rotating cardboard mask cipher rather than a columnar or rail-fence transposition.
Classroom, CTF, product use, and cost
Product teams that ship classical-cipher playgrounds can call the API for server-side checks while visitors experiment free in the browser. Because the work is pure parse-time indexing with no external service, latency stays low and the cost model is simple: try unlimited conversions free on this page, then automate identical inputs at $0.002 per successful item from prepaid KIT balance when you integrate from scripts or backend services. That parity keeps homework solutions, continuous-integration goldens, and production demos aligned. Map UI controls to size, a row editor for holes, and encrypt versus decrypt; validate even size and hole count client-side when you can, and surface invalid_input messages next to the grille editor when users submit overlapping openings or an odd side length.