⇐ Previous | Next ⇒

Caesar Cypher in Bash Oneliner

Post created 2013-12-07 16:57 by Gabe Koss.



I got this problem from karans Project repository. The challenge is as follows:

Caesar cipher - Implement a Caesar cipher, both encoding and decoding. The key is an integer from 1 to 25. This cipher rotates the letters of the alphabet (A to Z). The encoding replaces each letter with the 1st to 25th next letter in the alphabet (wrapping Z to A). So key 2 encrypts "HI" to "JK", but key 20 encrypts "HI" to "BC". This simple "monoalphabetic substitution cipher" provides almost no security, because an attacker who has the encoded message can either use frequency analysis to guess the key, or just try all 25 keys.

Mimimal Solution

Here is the tightest and most 'one-liney' I could make this:

# Sample usage: # ./bash_caesar <key (1-25)> <input file> tr 'A-Z' 'a-z' < $2 | tr 'a-z' $( echo {a..z} | sed -r 's/ //g' | sed -r "s/(.{$1})(.*)/\2\1/" )

Readable Solution

Here is some very similar logic split out into a couple lines to make it more understandable:

#!/bin/bash # example usage: # ./bash_caesar <key (1-25)> <input file> # # [email protected]:~$ echo "hi" > sample # [email protected]:~$ ./bash_caesar.sh 2 sample # jk # [email protected]:~$ ./bash_caesar.sh 20 sample # bc export A=$(echo {a..z} | sed -r 's/ //g') export C=$(echo $A | sed -r "s/^.{$1}//g")$(echo $A | sed -r "s/.{$( expr 26 - $1 )}$//g") tr '[A-Z]' $A < $2 | tr $A $C

Explanation

Inputs

This wants to be written as script and called with two arguments:

The key ( $1 ) should be a numeric value between 0-26. Realistically the keyspace is 1-25 but 0 and 26 both work as a complete rotation. if you go over problems you get into trouble with the negative numbers being passed into a regex.

) should be a numeric value between 0-26. Realistically the keyspace is 1-25 but 0 and 26 both work as a complete rotation. if you go over problems you get into trouble with the negative numbers being passed into a regex. The input file ( $2 ) should be the path to a text file

Alphabet string

I store a variable $A (for alphabet!) which is a string

export A=$(echo {a..z} | sed -r 's/ //g';);

This string looks like abcdefghijklmnopqrstuvwxyz . The trick is that echo {a..z} returns with spaces between each character like a b c ... and so these spaces are stripped out with sed .

Cypher

The cypher is created by rotating the alpahbet string a the number of characters indicated by the key. This is accomplished by passing the Alphabet variable $A through two different transforms with `sed.

Remove $1 characters

echo $A | sed -r "s/^.{$1}//g"

This deletes all characters in the space defined by the key $1 . For example if the key is 2 this will return cdefghijklmnopqrstuvwxyz .

Append 26 - $1 characters

echo $A | sed -r "s/.{$( expr 26 - $1 )}$//g"

This deletes all characters after the number defined by the key $1 . For example if the key is 2 this will return ab .

Translate file with Cypher

The actual translation is done with two chained tr commands.

Downcase the file

tr '[A-Z]' $A < $2

In the first tr command the input file $2 is translated by replacing any capital letter (in the range '[A-Z]' ) with the corresponding value in the alphabet variable $A

Translate the string

tr $A $C

Finally the downcased string is passed to tr a second time and all characters in the alphabet $A are replaced by the corresponding value in the cypher $C

Decoder

The example here only does encoding. The decoder for this can be created by swapping the $A and $C variables in the final `tr:

tr $C $A

Please enable JavaScript to view the comments powered by Disqus.

Disqus