{"id":18092,"date":"2026-05-04T21:47:40","date_gmt":"2026-05-05T01:47:40","guid":{"rendered":"https:\/\/scruss.com\/blog\/?p=18092"},"modified":"2026-05-04T21:47:40","modified_gmt":"2026-05-05T01:47:40","slug":"rot13-and-other-cypher-silliness","status":"publish","type":"post","link":"https:\/\/scruss.com\/blog\/2026\/05\/04\/rot13-and-other-cypher-silliness\/","title":{"rendered":"ROT13 and other cypher silliness"},"content":{"rendered":"\n<p>I wanted to encode a spoiler in a <a href=\"https:\/\/stardot.org.uk\/forums\/viewtopic.php?p=483567#p483567\">forum post<\/a> last night, so used the ancient <a href=\"https:\/\/en.wikipedia.org\/wiki\/ROT13\">ROT13<\/a> reciprocal cypher in the time-honoured way. That way, casual readers can immediately read the solutions, but you can get them by running the text through the ROT13 cypher again.<\/p>\n\n\n\n<p>It&#8217;s a very simple cypher: the letters a\u2013m are mapped to n\u2013z, and n\u2013z are mapped to a\u2013m in turn. Each letter is rotated 13 places in the alphabet, hence the name. So the phrase \u201c<em>fly at once all is discovered<\/em>\u201d becomes \u201c<em>syl ng bapr nyy vf qvfpbirerq<\/em>\u201d. A simple command line invocation might use the <strong>tr<\/strong> command like this:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p><code>echo fly at once all is discovered | tr a-mn-z n-za-m syl ng bapr nyy vf qvfpbirerq<\/code><\/p>\n<\/div>\n\n\n\n<p><strong>NB<\/strong>:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Because I&#8217;m a low-effort hipster, I&#8217;m only going to work with lower case letters. Real implementations do more.<\/li>\n\n\n\n<li>Nothing in this article moves the state of cryptography forward in any way. People were doing this kind of thing 2000 years ago.<\/li>\n\n\n\n<li>I&#8217;m going to keep using <strong>tr<\/strong>, but you probably have a <strong>rot13<\/strong> command.<\/li>\n<\/ol>\n\n\n\n<p>I noticed that once of the encyphered words in the spoiler spelled <em>onyx<\/em>, an English word in its own right.. Before discovering that this was <a href=\"https:\/\/en.wikipedia.org\/wiki\/ROT13#Word_pairs\">all documented on Wikipedia already<\/a>, I wrote some scripts to find what words were also words when run through ROT13:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p><code>tr a-mn-z n-za-m &lt; \/usr\/share\/dict\/words | sort |\\     comm -12 &lt;(sort \/usr\/share\/dict\/words) - |\\     grep -P '^[a-z]{4,}$'<\/code><\/p>\n<\/div>\n\n\n\n<p>This process has three phases:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>ROT13 the word list (\/usr\/share\/dict\/words) and sort it;<\/li>\n\n\n\n<li>Output the words common to the sorted word list and the ROT13 output using <strong>comm<\/strong>;<\/li>\n\n\n\n<li>finally, output only those words that are all lowercase letters and at least four characters long.<\/li>\n<\/ol>\n\n\n\n<p>With a smallish word list, you&#8217;ll get results like:<\/p>\n\n\n\n<p><em>balk barf crag ebbs envy errs flap frag gnat ones onyx pent rail reef roof sent sync tang<\/em><\/p>\n\n\n\n<p><em>gnat\/tang<\/em> is the longest pair that are ROT13 and the reverse of each other. If you&#8217;re into very obscure words, <em>nana\/anan<\/em> work too. (<em>Anan<\/em>: obsolete interjection meaning &#8216;in a moment&#8217; or &#8216;at your service&#8217;; 17th century)<\/p>\n\n\n\n<p>There are more words that reverse if you ROT13 them, but aren&#8217;t necessarily real words when reversed: &#8216;<em>robe<\/em>&#8216;, &#8216;<em>serf<\/em>&#8216; and &#8216;<em>thug<\/em>&#8216; are fairly common examples. (Yes, I know about &#8216;<em>Ebor<\/em>&#8216;, archaic name for York)<\/p>\n\n\n\n<p>The longest ROT13 self-reversing word I can find is &#8216;<em>tavering<\/em>&#8216; (Scots: to wander aimlessly). Next shorter are &#8216;<em>rebore<\/em>&#8216;, &#8216;<em>ravine<\/em>&#8216; and &#8216;<a href=\"https:\/\/en.wikipedia.org\/wiki\/Grivet\">grivet<\/a>&#8216;. Obscure examples are &#8216;<em>averin<\/em>&#8216;, &#8216;<em>cherup<\/em>&#8216; and &#8216;<em>granet<\/em>&#8216;: all in OED, just.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Other reciprocal cyphers<\/h2>\n\n\n\n<p>Another historical cypher is <a href=\"https:\/\/en.wikipedia.org\/wiki\/Atbash\">Atbash<\/a>: here, the range a\u2013z is mapped to z\u2013a. The cypher&#8217;s name derives from the first, last, second, and second to last Hebrew letters: &#8220;\u05d0\u05ea\u05d1\u05e9&#8221; (which reads right-to-left). A name derived from the Latin alphabet might be something like \u201c<strong>azby<\/strong>\u201d<\/p>\n\n\n\n<p>Again, <strong>tr<\/strong> can do the needful:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p><code>echo fly at once all is discovered | tr a-z zyxwvutsrqponmlkjihgfedcba uob zg lmxv zoo rh wrhxlevivw<\/code><\/p>\n<\/div>\n\n\n\n<p>Seeing that <em>all<\/em> becomes <em>zoo<\/em>, there have to be some good Atbash words that are English words. Using similar code as above:<\/p>\n\n\n\n<p><em>girl girt glow grog hold holy horn kiln prom slim slob slow tilt told trig trio<\/em><\/p>\n\n\n\n<p>Again, we can see a word pair that&#8217;s reversed when encoded: <em>girt\/trig<\/em>. The longest reversed-by-Atbash words I can find are <em>wizard<\/em> and <em>hovels<\/em>. <\/p>\n\n\n\n<p>There are, in fact, a huge number of reciprocal cyphers you can create this way. As long as, for each letter pair <em>(a, b)<\/em>, you map <em>a\u2192b<\/em> and <em>b\u2192a<\/em>, you&#8217;ll get a cypher that&#8217;s self-decrypting. Here&#8217;s an embarrassment of a shell one-liner that will generate a perfectly reciprocal mapping for <em>a\u2013z<\/em>:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p><code>for i in {a..z}; do echo &quot;$i&quot;; done | shuf | awk '{a[NR]=$0;} END{for (i=1;i&lt;26;i+=2) {b[a[i]]=a[i+1]; b[a[i+1]]=a[i];}; for (m in b) {print m &quot; &quot; b[m];}}' | sort | awk '{print $2}' | fmt -w999 | tr -d ' '<\/code><\/p>\n<\/div>\n\n\n\n<p>Here are 21 examples that can be put after &#8216;<em>tr a-z<\/em>&#8216; to make a reciprocal cypher:<\/p>\n\n\n\n<div class=\"wp-block-jetpack-markdown\"><p><code>bauonpqmtrzxhedfgjwicyslvk cyalpqnmzxrdhgwefktsvuojbi dcbajlzsxeoftqkrnphmwyuivg dknafehgovbmlciwyuxzrjpsqt eyfpacoihxutzsgdvwnlkqrjbm johmtyrcvawzdubsxgpenikqfl khjiznvbdcaouflwxsrymgpqte kwtlqosrnxaduifvehgcmpbjzy ohsjkvpbrdezqyagmicwxftunl petjbzyrmdlkivuaxhwconsqgf pyqjmztsvdoxerkacnhgwiulbf qldchvyekxibwtszauonrfmjgp ufzedbtosqmrkphnjligawvyxc uktiljzpdfbexsvhrqncaoymwg usdcnprwjitmlexfzgbkayhovq vintfeorbzpywcgkuhxdqamslj xjgzrmcwubonflksvepyiqhatd xoledhwfkpicutbjzyvnmsgarq ylfjgcepodrbnmihwktsvuqzax yregcwdnmotvihjsxbpkzlfqau badcfehgjilknmporqtsvuxwzy<\/code><\/p>\n<\/div>\n\n\n\n<p>That last one is what you get if you don&#8217;t shuffle the letters before you pair them. My brain keeps wanting to put it in alphabetical order, and it can&#8217;t.<\/p>\n\n\n\n<p>There are <em>lots<\/em> of these keys: I estimate something like 49,229,914,688,306,352,000,000 (= 26! \u00f7 8192) of them. But they&#8217;re all trivially easy to crack. They don&#8217;t change the underlying letter frequencies in the text, so if you have a long enough encrypted message, you can use standard frequency tables to break them.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I wanted to encode a spoiler in a forum post last night, so used the ancient ROT13 reciprocal cypher in the time-honoured way. That way, casual readers can immediately read the solutions, but you can get them by running the text through the ROT13 cypher again. It&#8217;s a very simple cypher: the letters a\u2013m are [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2}},"categories":[7],"tags":[3371,3370,2426,270,2546],"class_list":["post-18092","post","type-post","status-publish","format-standard","hentry","category-computers-suck","tag-atbash","tag-cipher","tag-cypher","tag-linux","tag-rot13"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/pQNZZ-4HO","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/18092","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/comments?post=18092"}],"version-history":[{"count":4,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/18092\/revisions"}],"predecessor-version":[{"id":18096,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/posts\/18092\/revisions\/18096"}],"wp:attachment":[{"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/media?parent=18092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/categories?post=18092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/scruss.com\/blog\/wp-json\/wp\/v2\/tags?post=18092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}