The Vigenère cipher made its rounds in the mid-1550s up until the end of the American Civil War. It was very easy for soldiers to encode messages and pass them around to all the allied camps.
The cipher requires a key and a message. It works like this:
- Key:
- Message:
- TODAYISMYBIRTHDAY
REDDITREDDITREDDI
TODAYISMYBIRTHDAY
--------------------------
KSGDGBJQBEQKKLGDG
Using a 0 based alphabet (A=0), R is the 17th letter of the alphabet and T is the 19th letter of the alphabet. (17 + 19) mod 26 = 11 which is where K resides in the alphabet. Repeat for each key/message letter combination until done.
Today's problem of the day is two part. The first part is to implement a Vigenère cipher in the programming language of your choice. Feel free to post solutions or links to solutions in the comments.
The second part is to try and implement something to crack the message below (the key is 5 or less characters).
ZEJFOKHTMSRMELCPODWHCGAW
Good luck!
Comments:
Anonymous - 10 years, 9 months ago
From what I know of Vigenere ciphers, the message you've given us can't really be cracked (it's too short) without brute force. I can confirm that the key isn't 1 or 2 characters long (I tried brute forcing it), but short of using a dictionary to automatically find possible solutions, it'll take far too long to parse the results of keys that are 3+ characters.
reply permalink
Anonymous - 10 years, 9 months ago
The goal is "to try and implement something to crack the message".
Runtime is irrelevant.
reply permalink
J. D. - 10 years, 9 months ago
Got a basic python script down, but keeps printing out wrong answer. Anyone fix it?
<pre><code>import string
alphabet=list(string.ascii_uppercase) encodedKey="" maths=0 counter=0 key=(str(input("Key: "))).upper() cipher=(str(input("Encode: "))).upper()
while len(key)<len(cipher): key+=key[counter] counter+=1
for i in range(0,len(cipher)): maths=(int(alphabet.index(key[i]))+int(alphabet.index(cipher[i])))%25 encodedKey+=alphabet[maths]
print(encodedKey) </code></pre>
reply permalink
Max Burstein - 10 years, 9 months ago
If you mod by 26 instead of 25 it works. That was my mistake in the description.
reply permalink
Anonymous - 10 years, 9 months ago
I think is 'mod 26', no?
reply permalink
Max Burstein - 10 years, 9 months ago
You're correct. 25 was my mistake. I updated the problem to reflect that.
reply permalink
Anonymous - 10 years, 9 months ago
This is my python attempt:
reply permalink
Anonymous - 10 years, 9 months ago
I found two bugs in your code
The first is that the line
isn't wrapped in your for Loop, so it outputs "G"
The second is in your algorithm. The characters that do not exceed 25 when being converted comes out 1 character off.
My hats off to you though, I had never used itertools before today, so after I had solved it, I resolved it using a variation of your strategy.
I had originally written the transpose method I just liked the way you did the NORMALISER variable instead of explicitly calling out the 65. And I also implemented your for loop style into what I already had instead of a separate indexer for the key that would reset.
reply permalink
Larry - 10 years, 9 months ago
You should definitely use a monospaced font for the example. It looks like the result is longer than the original message. My first thought was 'where did these extra characters come from?'.
reply permalink
Anonymous - 10 years, 9 months ago
When I encrypt the authors code I get the following: Assuming A=0 for the encryption => LSGDHCKQCEQLLLGDH Assuming A=1 for the encryption => KRFCGBJPBDPKKKFCG
Anyone could confirm that either his encrypted string is wrong or am I?
reply permalink
Crow - 10 years, 9 months ago
You're indexing the alphabet starting from 1. He's indexing it starting from 0.
reply permalink
Anonymous - 10 years, 9 months ago
Javascript with jQuery (though without jQuery isn't much different) var phrase = 'TodayIsMyBirthday', key = 'Reddit'; phrase.toUpperCase().split('').map(function(v, i) { return String.fromCharCode((((v.charCodeAt(0) - 65) + (key.toUpperCase().split('')[i % key.length].charCodeAt(0) - 65)) % 25) + 65) }).join('');
reply permalink
Ezekiel B - 10 years, 9 months ago
(17 + 19) mod 26 = 10, which does then translate to K. Thinking that was another typo.
reply permalink
Anonymous - 10 years, 9 months ago
My ruby attempt:
key = ARGV[0].split(//) message = ARGV[1].split(//)
cipher = "" char_offset = 'A'.ord
(0..(message.length - 1)).each do |i| key_num = key[i % key.length].ord - char_offset message_num = message[i].ord - char_offset
cipher = cipher + ((key_num + message_num) % 26) + char_offset).chr end
puts cipher
reply permalink
Anonymous - 10 years, 9 months ago
reply permalink
Cautious Poke - 10 years, 9 months ago
c# solution to Code a message
reply permalink
Anonymous - 10 years, 9 months ago
PHP
reply permalink
Anonymous - 10 years, 9 months ago
I wanted to give it a shot in Clojure in a point-free (aka "pointless") style.
reply permalink
Egon Wilzer - 10 years, 9 months ago
PHP
reply permalink
Michae Von Hell - 10 years, 9 months ago
A simple implementation in c++ <code> string crypt(string key, string message){ for (int x = 0; x < message.length(); x++){ message[x] = (message[x] - 'A' + (key[x%key.length()] - 'A'))%26 + 'A'; } return message; } </code>
reply permalink
Michae Von Heaven - 10 years, 9 months ago
I give up <pre><code>string crypt(string key, string message){ for (int x = 0; x < message.length(); x++){ message[x] = (message[x] - 'A' + (key[x%key.length()] - 'A'))%26 + 'A'; } return message; } </code></pre>
reply permalink
Anonymous - 10 years, 9 months ago
<script src="https://gist.github.com/anonymous/9399359.js"></script>
reply permalink
icendoan - 10 years, 9 months ago
This is my haskell attempt, using the way haskell has an ordering on characters as unicode. There's another couple of functions to tidy the i/o up a little, as well as a nice main :: IO () to get the command line working.
reply permalink
Grant McConnaughey - 10 years, 9 months ago
In Groovy:
{code} def convertLetterToNumber(letter) { ((int) letter?.toUpperCase()) - 65 }
def convertNumberToLetter(number) { (char) (number + 65) }
def vigenereCipher(key, message) {
def encryptedMessage = ''
}
assert vigenereCipher('REDDIT', 'TODAYISMYBIRTHDAY') == 'KSGDGBJQBEQKKLGDG' {code}
reply permalink
Luke Brooks - 10 years, 9 months ago
I did something kind of naughty but I couldn't help myself. Hard to read code and no validation but it works (with correct inputs).
print ''.join( [ chr( (ord(sys.argv[1][i])+ord(sys.argv[2][i%len(sys.argv[2])])) % 26 + 65) for i in range(len(sys.argv[1])) ] )
reply permalink
Ben Lucyk - 10 years, 9 months ago
Here's a very simple javascript implementation: http://codepen.io/anon/pen/taHIx
Now do I waste more time on to the codebreaking?! :)
reply permalink
rekh127 - 10 years, 9 months ago
Heres a complete encrypt/decrypt solution in C.
reply permalink
AndreaM - 10 years, 9 months ago
Javascript one liner (to encode). Supports a custom alphabet.
reply permalink
factorial720 - 10 years, 9 months ago
Code (in Python):
One small cheat in the above code, originally I had it displaying all possible keys which contained the word THE. There were a lot of course, but in glancing over the list the actual key showed up and for the posted code instead looked for WELCOME.
Output: KSGDGBJQBEQKKLGDG TODAYISMYBIRTHDAY I=1 I=2 I=3 Key: DAY, Output: WELCOMETOPROBLEMOFTHEDAY I=4 I=5
reply permalink
Michae Von Heaven - 10 years, 9 months ago
Damn it, didn't thought about the "THE" chear :\
reply permalink
Michae Von Heaven - 10 years, 9 months ago
I've brute forced up to 3 letter password, here are the results: 1 letter 2 lletters 3 letters
reply permalink
CF - 10 years, 9 months ago
Perl: `#!/usr/bin/perl use strict;
my $encryption="reddit"; my $cleartext="todayismybirthday"; my $encrypted;
for( my $i = 0 ; $i < length($cleartext) ; $i ++ ) { my $chr = ord(substr($cleartext,$i,1)) - 97; my $key = ord(substr($encryption,$i % length($encryption), 1)) - 97; my $enc = chr((($chr+$key) % 26) + 97); $encrypted = $encrypted . $enc; }
print "$cleartext\n$encrypted\n"; `
reply permalink
Anonymous - 10 years, 9 months ago
I was curious about the brute force approach so I wrote a program which systematically attempts keys and then matches the results against words > 4 chars long from a dictionary file.
My approach looks like this (written in go):
1) Read the dictionary file in (/usr/share/dict/web2 is what I used, on Debian testing)
2) If a word is more than 4 chars long, create a new regexp object whose pattern is the lowercased word. If there's an error in compiling the regex (dictionary words with weird characters in it) skip it. Store this regex in a list, and then as the key to a map (with the original word as the value of the map).
3) Via a recursive permutation function, get all of the keys up to and including MAX_KEY_LENGTH (in this case, I set it to 5 since that was in the problem parameter). So it does a-z, then aa-az, ba-bz... up until zzzzz.
Each time you generate a key, use it to create a decrypt attempt of the ciphertext.
4) Test this decrypt attempt against all of the regexes in the list. If there's a match, report it (along with the word stored in the regex - string map to show which word triggered the match).
It didn't take especially long to find the message - eliminating all of the things that didn't contain dictionary words made it way easier to eyeball-grep the results and find the right answer.
As for run time, I didn't let the program finish because I was tailing the results as they were coming through and stopped it when I hit the answer.
The longer the max key length gets, the longer this will take (dramatically). 5 was already pushing it - 7 or 8 would take absolutely forever.
reply permalink
Anonymous - 10 years, 9 months ago
Can you paste your go code?
reply permalink
Anonymous - 10 years, 9 months ago
Here's complete encrypt/decrypt/all possible combinations in PHP for 3 letters. I was grepping the output (including up to 5 letter ciphers) for words like "SECRET" and "MESSAGE" etc... didn't think to try "WELCOME". :)
reply permalink
Anonymous - 10 years, 9 months ago
Only did the first part in Haskell. Haven't got a clue about the rest.
<code> import Control.Monad import Data.List
f = fmap ((!!) alphabet . flip rem 26 . sum) . sequence . fmap (flip elemIndex alphabet) where alphabet = ['A'..'Z']
main = do x <- getLine y <- getLine let z = sequence $ fmap f [[x, y] | (x, y) <- (zip y $ cycle x)] print z </code>
reply permalink
Anonymous - 10 years, 9 months ago
D solution for the encoding/decoding of a Vigenère cipher :
reply permalink
Tornchi - 10 years, 6 months ago
My Solution also in D. Also includes a solution to the second part.
reply permalink
James - 10 years, 9 months ago
Here is my solution written in c# console for Part 1. <pre><code> using System; using System.Text;
namespace Vigenère_cipher { class Program { static void Main(string[] args) { const string key = "REDDIT"; const string message = "TODAYISMYBIRTHDAY";
} </code></pre>
reply permalink
David - 10 years, 9 months ago
an OO-style solution in Ruby.
```ruby class VigenereCipher def initialize(key) @key = key.downcase end
def encode(message) cipher(message, :+) end
def decode(message) cipher(message, :-) end
private def index_for_char(char) char.ord - 'a'.ord end
def char_for_index(index) ('a'.ord + index).chr end
def cipher(message, direction) message.downcase! message.split('').map.with_index {|c, i| key_char = @key[i % @key.length] char_index = index_for_char(c).send(direction, index_for_char(key_char)) % 26 char_for_index(char_index) }.join end end
class VigenereCipherCracker def initialize(key_max_length) @key_max_length = key_max_length end
def crack(message) (1..@key_max_length).each do |key_length| keys_of_length(key_length).each do |key| attempt = VigenereCipher.new(key).decode(message) return [attempt, key] if successful_attempt(attempt) end end end
private def successful_attempt(attempt) puts attempt # TODO: verification of the attempt is out of scope for the prompt false end
def keys_of_length(length) return [''] if length == 0 keys_of_length(length - 1).map {|shorter_key| ('a'..'z').map do |new_char| shorter_key + new_char end }.flatten end end ```
reply permalink
David - 10 years, 9 months ago
whoops, thought the markdown parser would take triple backticks for code blocks... let's see if it likes four spaces
reply permalink
Pascal Seitz - 10 years, 9 months ago
Javascript solution to encode a message
var alphabet = ['a', 'b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'];
function encrypt(key, string){
}
reply permalink
Michael Mulqueen - 10 years, 9 months ago
My Python code: https://gist.github.com/mmulqueen/9401026
Cracks the code in about 8 seconds.
reply permalink
K - 10 years, 9 months ago
<pre> ordinal_difference = 65 def cipher(key, message): key = key.upper() lenkey = len(key)
def alpha_pos(char): return ord(char) - ordinal_difference </pre>
reply permalink
El Ninja - 10 years, 9 months ago
Cracked it!
Using a dictionary attack, with a multithreaded python application, here's the source:
https://github.com/ibarrajo/problemoftheday-vigenere/blob/master/vigenere.py
My plan was to sort all of the answers based on the score, but when I glanced at the console output, there it was =]
reply permalink
Anonymous - 10 years, 9 months ago
Fortran! http://pastebin.com/LtxrSHL3
reply permalink
Anonymous - 10 years, 9 months ago
Here is my working Python 2.7 code to create the cipher. Still working on being able to break one.
<code>from string import ascii_lowercase
def make_key(key,message):
def make_cipher(key, message): new_message = '' key, message = key.lower(),message.lower()
print make_cipher('REDDIT','TODAYISMYBIRTHDAY')
</code>
reply permalink
Derek - 10 years, 9 months ago
Here's my Ruby solution:
The cracking algorithm uses a word list to check for matches - the word list is culled from a "most popular words on the internet" list I found, and pared down by removing words containing apostrophes and words two letters or shorter. It sorts potential candidates based on the longest word found and returns the first 1000. My thinking was that the longer the word, the less likely it is to be a fluke.
However, it turns out this step is unnecessary. Under manual inspection the result comes up almost immediately, and it's not necessary to continue.
reply permalink
Dave - 10 years, 9 months ago
Here is my working Python 2.7 code to create the cipher. Still working on being able to break one.
<pre><code>from string import ascii_lowercase
def make_key(key,message):
def make_cipher(key, message): new_message = '' key, message = key.lower(),message.lower()
print make_cipher('REDDIT','TODAYISMYBIRTHDAY')
</code></pre>
reply permalink
paluche - 10 years, 9 months ago
Java:
reply permalink
im not telling you - 10 years, 9 months ago
C# handling nulls and some other cases....sorry didn't know what the procedure is when the key has values outside 'A' - 'Z'...
public string Encrypt(string key, string text) { return string.Concat((text ?? "").ToUpper().Select((ch, i) => (ch < 65 || ch > 90) ? ch : (char)(((string.IsNullOrWhiteSpace(key) ? 65 : key.ToUpper()[i % key.Length]) + ch - 130) % 26 + 65))); }
reply permalink
Jacob - 10 years, 9 months ago
Well, once I had encryption and decryption built, and possible key lengths known (1, 2, 3, 4), I figured the next problem would be to find out when I found the key - and I went with a full dictionary check on the decoded string.
I hadn't made any assumptions on whether the key would be a word so I did it brute force and checked each decoded string against a subset of a dictionary, leaving me with about 400,000 words to check each output against.
Once a second I output a sorted list of the decoded strings that have words in them, including the words it matched against, and the key. It takes about 6 minutes, 30 seconds to try 17,576 keys using multi-threaded word search on my quad-core Intel 2500K. It's slow but I'm sure I can do a lot to improve performance, especially by making my own match algorithm to make searching more efficient.
reply permalink
Jacob - 10 years, 9 months ago
Got it down to 1.7 seconds now, brute forcing all keys between AAA and ZZZ, that was fun. Thanks Max!
reply permalink
Anonymous - 10 years, 9 months ago
Here is a solution in C, doesn't crack the message though but bruteforces a list of keys and messages. #include<stdio.h> #include<ctype.h>
reply permalink
Alex - 10 years, 9 months ago
Complete solution for parts 1 and 2 in C
reply permalink
Alex - 10 years, 9 months ago
I copied and pasted the wrong code: Need to loop over generateWords from len = 1 to 5... forgot to include that. This could be optimized in the recursive generateWords functions since all n-1 length strings are a subset of n length strings.
reply permalink
Rahul Sharma - 10 years, 1 month ago
below is the encryption code in JAVA Ill also try to do the decryption part
package vignerecipher;
public class Main {
}
reply permalink
Anonymous - 9 years, 11 months ago
welcometoproblemoftheday
reply permalink
١юὸⅻѾἄTṂW⇑ - 9 years, 3 months ago
this is a very simple crack, using a certain method (http://www.guballa.de/vigenere-solver) we know the key is day and the answer is WELCOMETOPROBLEMOFTHEDAY
reply permalink
0x7c00 - 8 years, 12 months ago
Key = DAY
Message = welcometoproblemoftheday
reply permalink