ROT18 cipher
Hello, World! 123 becomes Uryyb, Jbeyq! 678 in one pass: letters move 13 places and digits move five, while spaces and punctuation stay put. Run it again and the original returns, so a single step both hides and reveals. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Text
- Hello, World! 123
- Result
- Uryyb, Jbeyq! 678
- Length
- 17
- Letters rotated
- 10
- Digits rotated
- 3
ROT18 is the combined rotation cipher that applies ROT13 to every Latin letter and ROT5 to every decimal digit in one pass. Letters A through Z and a through z move thirteen places around the alphabet so Hello becomes Uryyb, while digits zero through nine move five places so 123 becomes 678. Spaces, punctuation, and other characters stay where they are, which keeps readable structure for puzzle strings and light labels. Because thirteen is half of twenty-six and five is half of ten, applying ROT18 a second time undoes the first: the same operation both encodes and decodes. Paste any non-empty string and receive the transformed result instantly.
How ROT18 combines ROT13 letters and ROT5 digits
ROT18 is not a separate alphabet; it is the product of two classical half-ring rotations run character by character. For each Latin letter the algorithm maps the character to an index from zero through twenty-five within its case, adds thirteen, takes the remainder modulo twenty-six, and maps back to a letter of the same case. That is classic ROT13: A becomes N, N becomes A, Hello becomes Uryyb, and Uryyb becomes Hello again.
For each ASCII digit the algorithm maps zero through nine to an index, adds five, takes the remainder modulo ten, and maps back: zero becomes five, five becomes zero, one two three becomes six seven eight. Characters outside those two sets—spaces, commas, emoji, accented letters outside the basic Latin block—are copied unchanged so phrases keep their shape.
The combined transform is an involution: because thirteen plus thirteen is twenty-six and five plus five is ten, every letter and every digit returns to itself after two applications, so encode and decode are the same call. There is no key to choose, no mode flag, and no floating-point step. Every step is integer modular arithmetic with a fixed rule, fully deterministic, with no network call, no random seed, and no wall-clock timestamp in the path.
This page implements that fixed ROT18 profile only—not a variable Caesar shift, not Vigenère, not AES, and not a brute-force cracker. Those are separate tools and search intents.
Where ROT18 tools show up in real work
Introductory cryptography and programming courses often introduce ROT13 first and then ask students to extend the idea to digits; a single trusted ROT18 oracle speeds homework demos and auto-graders that need both letter and digit rotation. Capture-the-flag warm-ups and puzzle hunts still hide ROT-style messages that mix words and numbers in plain sight, and solvers want a fast, predictable transform rather than a general cryptanalysis suite.
Support and content teams sometimes lightly obfuscate spoilers, quiz answers, serial-looking labels, or internal ticket codes that mix letters and digits and need the reverse path without installing a language-specific library. If you need a variable integer Caesar shift, strong authenticated encryption, Base32 or Base64 encoding, or automatic frequency-analysis key recovery, treat those as separate search intents and landings rather than overloading this fixed ROT18 page.
What you can do with it
Classroom ROT13-plus-digits demos
Show students how half-alphabet and half-digit rotations combine, with one ground-truth transform for letters and numbers together.
Puzzle and CTF mixed alphanumeric strings
Encode or reverse challenge strings that mix words and digits without writing a one-off script for every problem set.
FAQ
What is ROT18?
A combined rotation cipher: ROT13 on Latin letters A–Z/a–z and ROT5 on digits 0–9. Non-alphanumeric characters are left unchanged. Applying it twice recovers the original text.
How do I decode ROT18?
Apply the same transform again. ROT18 is self-inverse because 13+13=26 and 5+5=10, so encode and decode are identical.
What happens with empty input?
You must provide a non-empty text string; blank input is rejected and not charged.
Are spaces and punctuation transformed?
No. Only A–Z, a–z, and digits 0–9 are rotated. Spaces, punctuation, and other characters pass through unchanged.
What does it cost?
The browser tool is free and runs locally.
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/rot18 \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"text":"Hello, World! 123"}'const res = await fetch("https://api.kit.forhosting.com/enc/rot18", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"text": "Hello, World! 123"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/enc/rot18",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"text": "Hello, World! 123"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/enc/rot18", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"text":"Hello, World! 123"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"text":"Hello, World! 123"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/enc/rot18", 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": "Hello, World! 123"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "enc.rot18",
"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
Empty input is rejected with a clear invalid_input error so scripts never silently treat a blank field as a no-op.
What you send and what you get back
Send a required string field named text containing the message you want to transform. Classic checks include transforming Hello, World! 123 into Uryyb, Jbeyq! 678, applying the same transform again to recover the original, and confirming that an empty text field is rejected rather than returned unchanged. Aliases such as input, value, data, message, plaintext, and ciphertext are accepted for the same field so scripts can reuse existing payload shapes. On success the response echoes the original text, returns result as the ROT18 string, length of that result, letters_rotated and digits_rotated as counts of how many alphabetic and numeric characters were rotated, plus alphabet, cipher, and self_inverse labels so clients can assert they hit the ROT18 profile. Missing text, non-string objects for text, empty strings, and strings longer than the documented maximum fail with invalid_input and a clear English message. Validation failures do not consume prepaid balance. Pricing for successful API calls is the published base of $0.002 per item.
Where ROT18 tools show up in real work
Because this capability is a pure parse engine, API pricing is the published base of $0.002 per successful item and failed validation does not consume balance.
Integration use cases
Lightweight spoiler and label obfuscation
Rotate quiz answers or ticket-style labels that contain letters and digits, then recover them with the same call in browser or API.