Created
February 4, 2011 18:59
-
-
Save gaurav/811562 to your computer and use it in GitHub Desktop.
A program to crack the cipher at http://keiththomsonbooks.com/cipher-02022012.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# This is the program I wrote to crack this fun little cipher: http://keiththomsonbooks.com/cipher-02022012.html | |
# The clue clearly indicates that this is just a simple substitution cipher [1]; even better, it looks like ROT13 [2], | |
# except that you clearly don't move every letter along by exactly 13 places. So how many letters do you need to move | |
# it along by? There's only 26 letters in the English alphabet: let's try every possible value! | |
# | |
# [1] http://en.wikipedia.org/wiki/Substitution_cipher | |
# [2] http://en.wikipedia.org/wiki/ROT13 | |
# *All* good Perl programs start with: | |
use strict; | |
use warnings; | |
# So the one-liner I used eventually was: | |
# echo 'pm aol lhysf ipyk nlaz aol dvyt doha kvlz aol lhysf dvyt nla?' | perl -e '@letters = split(//, <STDIN>); for my $X ('a' .. 'z') { print $X . ": "; for(@letters) { if(/ /) { print; next; }print chr(ord('a') + ((ord($_) - ord($X)) % 26)); } print "\n"; }' | |
# Here it is in longer, cleaned up form: | |
my $code = 'pm aol lhysf ipyk nlaz aol dvyt doha kvlz aol lhysf dvyt nla?'; | |
# First, we need the letters to work on. | |
my @letters = split(//, $code); # split(//, $string) will split the string up into an array, with one character in each array cell. | |
# Now, we're going to shift each character along by fixed value, but | |
# we'll try every possible fixed value between 0 and 25. Since there's | |
# no harm in making it readable ... | |
for my $based_on_alphabet ('a' .. 'z') { # ... let's just loop over every letter in the alphabet! | |
# Which letter are we working on? | |
print "$based_on_alphabet: "; | |
# Let's go over all the letters in the code string. | |
for my $letter (@letters) { | |
# Shifting non-alphabetic characters won't help. So ignore them. | |
unless($letter =~ /[a-z]/) { | |
print $letter; | |
} else { | |
# Okay, we've got an alphabetical character. Now it gets interesting. | |
# We need to shift it along a certain number of characters. But we also | |
# need to make sure it 'loops around' at 26: so once it gets to | |
# character #26 ('z'), adding one to it should make it go back to #1 ('a'). | |
# That'd be pretty hard to make work, except for the wonderful 'mod' (%) operator. | |
# This is standard in all programming languages, and what it does is divides | |
# one number by another, and gives you the *remainder*. This works perfectly, but | |
# only if you count from zero, which is quite easy to do. So: | |
# 24 % 26 = 24, 25 % 26 = 25, 26 % 26 = 0, 27 % 26 = 1. | |
# Perfect. | |
# There's one last complication to work around: this would work perfectly if 'a' was | |
# 0 and 'z' was 25, but computers use the ASCII scheme to give numbers to letters so that the | |
# computer can use them. In the ASCII scheme, 'a' is 97. Luckily, it's as we'd expect | |
# after that: 'b' is 98, 'c' is 98, and 'z' is 122. In order to use mod to 'loop around', | |
# we're going to have to subtract 97 from the character code we have in $letter. | |
# $letter_position = ord($letter) - 97; | |
# would have been perfect, but we can do one better. Perl doesn't see the difference between | |
# the character 97 and the letter 'a', since it thinks in ASCII. So we can make our code a | |
# bit more readable by writing: | |
my $letter_position = ord($letter) - ord('a'); | |
# Now we just shift it along by the letter stored in $based_on_alphabet and | |
# mod it by 26. But $based_on_alphabet is in ASCII too, remember? So: | |
my $shift_by = ord($based_on_alphabet) - ord('a'); | |
# Now a's are represented by 0, b's by 1, and z's by 25. Perfect. | |
my $new_character = ($letter_position + $shift_by) % 26; | |
# Now we print this - oh, wait! Perl can't print this as | |
# a character unless it's back as ASCII, right? | |
$new_character = $new_character + ord('a'); | |
# Now all we need to do is print that, and we're done! | |
print chr($new_character); | |
} | |
} | |
print "\n"; # Print a newline so the output is neat. | |
} | |
__DATA__ | |
# Try it! You should get: | |
a: pm aol lhysf ipyk nlaz aol dvyt doha kvlz aol lhysf dvyt nla? | |
b: qn bpm miztg jqzl omba bpm ewzu epib lwma bpm miztg ewzu omb? | |
c: ro cqn njauh kram pncb cqn fxav fqjc mxnb cqn njauh fxav pnc? | |
d: sp dro okbvi lsbn qodc dro gybw grkd nyoc dro okbvi gybw qod? | |
e: tq esp plcwj mtco rped esp hzcx hsle ozpd esp plcwj hzcx rpe? | |
f: ur ftq qmdxk nudp sqfe ftq iady itmf paqe ftq qmdxk iady sqf? | |
g: vs gur rneyl oveq trgf gur jbez jung qbrf gur rneyl jbez trg? | |
h: wt hvs sofzm pwfr ushg hvs kcfa kvoh rcsg hvs sofzm kcfa ush? | |
i: xu iwt tpgan qxgs vtih iwt ldgb lwpi sdth iwt tpgan ldgb vti? | |
j: yv jxu uqhbo ryht wuji jxu mehc mxqj teui jxu uqhbo mehc wuj? | |
k: zw kyv vricp sziu xvkj kyv nfid nyrk ufvj kyv vricp nfid xvk? | |
l: ax lzw wsjdq tajv ywlk lzw ogje ozsl vgwk lzw wsjdq ogje ywl? | |
m: by max xtker ubkw zxml max phkf patm whxl max xtker phkf zxm? | |
n: cz nby yulfs vclx aynm nby qilg qbun xiym nby yulfs qilg ayn? | |
o: da ocz zvmgt wdmy bzon ocz rjmh rcvo yjzn ocz zvmgt rjmh bzo? | |
p: eb pda awnhu xenz capo pda skni sdwp zkao pda awnhu skni cap? | |
q: fc qeb bxoiv yfoa dbqp qeb tloj texq albp qeb bxoiv tloj dbq? | |
r: gd rfc cypjw zgpb ecrq rfc umpk ufyr bmcq rfc cypjw umpk ecr? | |
s: he sgd dzqkx ahqc fdsr sgd vnql vgzs cndr sgd dzqkx vnql fds? | |
t: if the early bird gets the worm what does the early worm get? | |
u: jg uif fbsmz cjse hfut uif xpsn xibu epft uif fbsmz xpsn hfu? | |
v: kh vjg gctna dktf igvu vjg yqto yjcv fqgu vjg gctna yqto igv? | |
w: li wkh hduob elug jhwv wkh zrup zkdw grhv wkh hduob zrup jhw? | |
x: mj xli ievpc fmvh kixw xli asvq alex hsiw xli ievpc asvq kix? | |
y: nk ymj jfwqd gnwi ljyx ymj btwr bmfy itjx ymj jfwqd btwr ljy? | |
z: ol znk kgxre hoxj mkzy znk cuxs cngz juky znk kgxre cuxs mkz? | |
# Do one of those lines look like English? Congratulations, you've | |
# broken the cipher! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment