14

I found an obfuscated e-mail address that can be decrypted using this command:

echo "cbyrzba@cbyrzba.bet" | tr '[a-z]' '[n-za-m]'

How does that output a valid e-mail address? What is that command doing?

Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
LanceBaynes
  • 40,135
  • 97
  • 255
  • 351

2 Answers2

24

tr's man page explains it pretty well; it's a filter that converts characters from one set to another. The first set specified is [a-z], which is a shorthand way of typing [abcdefghijklmnopqrstuvwxyz]. The second is [n-za-m], which turns into [nopqrstuvwxyzabcdefghijklm]. tr reads each character from stdin, and if it appears in the first set, it replaces it with the character in the same position in the second set (this means [ and ] are getting replaced with themselves, so including them was pointless, but a lot of people do it by mistake because regular expressions use them to represent character classes so they think tr requires them).

So a simpler example:

$ echo abc | tr ab xy
xyc

a turned into x, b turned into y, and c was left unchanged because it wasn't in the first set. All the user did in this case is run their e-mail address through the same filter (since it's symmetric -- a maps to n and n back to a, etc.) to get the rotated version; you running it through again swaps all the characters back to their originals


Sidenote: This particular swap, where each letter is replaced by the one 13 characters away from it in the alphabet, is called ROT13 (rotate 13); it was popular on newsgroups as a way to hide things people might not want to see

Michael Mrozek
  • 93,103
  • 40
  • 240
  • 233
  • 1
    Including [ and ] is useful: They are sometimes mandatory (some solaris default tr need them, for example). Hence it's probably a good habit (once one knows to not mix those with a regexp '[...]' ) – Olivier Dulac Jan 19 '18 at 15:25
7

tr transliterates characters: for some character x in the input, it outputs a character y.

tr takes two command line arguments, the "from" characters and the "to" characters.

In your example above, the "from characters" are given as '[a-z]'. The "to characters" are given as '[n-za-m]' . The single-quotes keep the shell that interprets the command line from doing anything to the two arguments. tr treats square-bracketed arguments as ranges. So '[a-z]' means "all lower case characters from 'a' to 'z', inclusive". The second argument is a bit more complicated,'[n-za-m]'` means "lower case characters from 'n' to 'z' inclusive, and lower-case characters from 'a' to 'm', inclusive'.

tr transliterates all input 'a' characters to 'n', 'b' to 'm', 'c' to 'o', etc, up to 'n' characters output as 'z'. 'o' characters in input get output as 'a', 'p' to 'b', 'q' to 'c' and so forth. 'z' characters in input get output as 'l'.

Essentially, your command does a Caesar Cipher on its input, one lower case character at a time. Someone had to encipher "polemon@polemon.org" to get the string you have echo outputing.

  • 1
    several caveats: So '[a-z]' means "all lower case characters from 'a' to 'z', inclusive" : no, it means : '[' and all the letters 'a' to 'z' (in your locale!), and ']' . Thankfully the 2nd argument replaces "[" with "[" and "]" with "]". The other caveat: in some locales, a-z can be : all the ascii lowercase letters, or all letters (lower AND uppercase) except "A" (or except "Z" in other locales), or sometimes even "all letters a to z, including accented letters". To ensure the usual : force the locale while invoking tr: LC_ALL='C' tr 'a-z' 'A-Z' (or LC_ALL='C' tr '[a-z]' '[A-Z]') – Olivier Dulac Jan 19 '18 at 15:29