Brute Force Vigenere Cipher Key Generator Python
Posted By admin On 17.12.20I have written a pair of programs in Python that can be used to encrypt, decrypt, and crack Caesar and Vigenere Ciphered text. I am fairly new to Python and I wrote these programs largely to try and test myself on what I had learned so far with a practical problem, although I cannot claim that every line of these programs is my own. Feb 10, 2017 Recover the encryption key and plain text of the vigenere cipher text using Kerckhoff's method. The project is about the implementation of Kerchoff's method to crack vigenere cipher using python 2.7.12. The code results number of coincedences with corresponding shifts in descending order. lil wayne eat you alive download The sample result is shown as below.
I'll be using Python 2.7 since it comes default on Mac /doom-3-product-key-generator.html. Avs video editor key generator.
A super easy to understand algorithm. It basically reverses a given input string. To decipher/hack it, simply enter the encrypted string again.
Files:
- reverse.py - The main program: enter a string, it'll reverse it for you.
Another easy to understand algorithm. Every character is shifted by a key. For example, if the key was 3, then A->D, B->E, and so on. Z->C, since it just wraps around the alphabets.
Files:
- caesar.py
- caesarAdvanced.py - An advanced version of Caesar shift, shifts all characters, not just letters.
- caesarTest.py - A program to test caesar.py, runs it against a bunch of strings/key to ensure that it's working properly
- caesarHack.py - Hacks caesar.py, brute forces all 26 possible keys.
A little tougher to crack compared to Caesar Shift. Given a key N, this algorithm creates N columns of arrays. For each character in a given string, it will fill up the table from left to right, but READ it top to bottom. For example: 'Hello Raymond' with key 5 will be read as 'H oeRnladlyom'. To decipher this, you do some fancy math to find the correct number of columns, and do as you would to encrypt.
Hacking this is harder, since they number of keys is proportional to the length of the string, a long string can have a bunch of possible keys. So, we must split the string into words, and brute force each word against the key, and compare the results to words in the English dictionary. If there are enough matches of words, we can say with enough certainty that we have the correct key.
Files:
- transposition.py - The main program, used to en/decrypt strings with a given key.
- transpositionTest.py - Ensures that our program's algorithm is running correctly by testing 1000 random strings/keys.
- transpositionHack.py - Works with detectEnglish.py to crack transposition.py's encryption.
- detectEnglish.py - Given a string, determines how many of 'words' can be found in dictionary.txt
- dictionary.txt - a list of English words
A more advanced version of Caesar Cipher. Instead of shifting letters of the Alphabets by a key, letters are directly replaced by other letters of the alphabet, resulting in a 26 unique characters key. This gives a possibility of 26!(factorial) combinations! So instead of brute forcing each possible key, we want to map each word to its cipher pattern, so we can compare them to those similar in the dictionary. A word's pattern is determined by the amount of unique letters it has. Example: 'Hello' = '0.1.2.2.3' and 'Raymond' = '0.1.2.3.4.5.6.7' and 'Happy' = '0.1.2.2.3'. See how 'Hello' and 'Happy' maps to the same pattern? That's how we can determine possible substitutions.
Files:
- substitution.py - The main program: en/decrypts a string/file with a 26 character key.
- substitutionTest.py - Tests our main program by generating random strings/keys to ensure algorithm is correct.
- makeWordPatterns.py - A program to create a python file.
- wordPatterns.py - Created by makeWordPatterns.py. Contains a single map of all the words in the dictionary, and their corresponding cipher pattern.
- subHack.py - Copied algorithms directly from Hacking Ciphers book. This program is used to find intersection of words. The more words in a string the better, to eliminate bad substitutions. Prints the potential key map, and (possible) deciphered text.
- dictionary.txt - Needed again by makeWordPatterns.py
- textfile.txt/enc.textfile.txt/hacked.enc.textfile.txt - See how well our program did by comparing hacked.enc.textfile.txt and the original textfile.txt
Another variation of the Caesar Cipher. The key consists of multiple shifts. The key is often a word, where each letter of the word is a subkey. A = 0, Z = 25, and everything in between.
Files:
- vigenere.py - The main program: en/decrypts a string/file with a key of user's choice.
- vigenereTest.py - Tests the main program to ensure algorithms is working correctly.
Vigenere Cipher Decoder
importitertools |
importstring |
importsys |
importtextwrap |
'' |
Run this script in a shell with the ciphertext to decode on STDIN |
'' |
#################################################################################################### |
# Vienere encryption and decryption functions |
#################################################################################################### |
defvigenere(plaintext, key, a_is_zero=True): |
key=key.lower() |
ifnotall(kinstring.ascii_lowercaseforkinkey): |
raiseValueError('Invalid key {!r}; the key can only consist of English letters'.format(key)) |
key_iter=itertools.cycle(map(ord, key)) |
return'.join( |
chr(ord('a') + ( |
(next(key_iter) -ord('a') +ord(letter) -ord('a')) # Calculate shifted value |
+ (0ifa_is_zeroelse2) # Account for non-zero indexing |
) %26) ifletterinstring.ascii_lowercase# Ignore non-alphabetic chars |
elseletter |
forletterinplaintext.lower() |
) |
defvigenere_decrypt(ciphertext, key, a_is_zero=True): |
# Decryption is encryption with the inverse key |
key_ind= [ord(k) -ord('a') forkinkey.lower()] |
inverse='.join(chr(ord('a') + |
((26ifa_is_zeroelse22) - |
(ord(k) -ord('a')) |
) %26) forkinkey) |
returnvigenere(ciphertext, inverse, a_is_zero) |
deftest_vigenere(text, key, a_is_zero=True): |
ciphertext=vigenere(text, key, a_is_zero) |
plaintext=vigenere_decrypt(ciphertext, key, a_is_zero) |
assertplaintexttext, '{!r} -> {!r} -> {!r} (a {}= 0)'.format( |
text, ciphertext, plaintext, 'ifa_is_zeroelse'!') |
# Test that the Vigenere encrypt and decrypt work (or are at least inverses) |
fortextin ['rewind', 'text with spaces', 'pun.ctuation', 'numb3rs']: |
forkeyin ['iepw', 'aceaq', 'safe', 'pwa']: |
test_vigenere(text, key, True) |
test_vigenere(text, key, False) |
# Now that we're sure that all the vigenere stuff is working. |
#################################################################################################### |
# Cipher solver |
#################################################################################################### |
# From http://code.activestate.com/recipes/142813-deciphering-caesar-code/ |
ENGLISH_FREQ= (0.0749, 0.0129, 0.0354, 0.0362, 0.1400, 0.0218, 0.0174, 0.0422, 0.0665, 0.0027, 0.0047, |
0.0357, 0.0339, 0.0674, 0.0737, 0.0243, 0.0026, 0.0614, 0.0695, 0.0985, 0.0300, 0.0116, |
0.0169, 0.0028, 0.0164, 0.0004) |
defcompare_freq(text): |
'' |
Compare the letter distribution of the given text with normal English. Lower is closer. |
Performs a simple sum of absolute difference for each letter |
'' |
ifnottext: |
returnNone |
text= [tfortintext.lower() iftinstring.ascii_lowercase] |
freq= [0] *26 |
total=float(len(text)) |
forlintext: |
freq[ord(l) -ord('a')] +=1 |
returnsum(abs(f/total-E) forf, Einzip(freq, ENGLISH_FREQ)) |
defsolve_vigenere(text, key_min_size=None, key_max_size=None, a_is_zero=True): |
'' |
Solve a Vigenere cipher by finding keys such that the plaintext resembles English |
Returns: |
the first and second best from the set of best keys for each length |
This is not a brute force solver; instead, it takes advantage of a weakness in the cipher to |
solve in O(n * K^2) where n is the length of the text to decrypt and K is the length of the |
longest key to try. |
The idea is that for any key length, the key is used repeatedly, so if the key is of length k |
and we take every k'th letter, those letters should have approximately the same distribution as |
the English language on a whole. Furthermore, since each letter in the key is independent, we |
can perform the analysis for each letter in the key by taking every k'th letter at different |
starting offsets. Then, since the letters in the key are independent, we can construct the best |
key for a given length by simply joining the best candidates for each position. |
'' |
best_keys= [] |
key_min_size=key_min_sizeor1 |
key_max_size=key_max_sizeor20 |
text_letters= [cforcintext.lower() ifcinstring.ascii_lowercase] |
forkey_lengthinrange(key_min_size, key_max_size): |
# Try all possible key lengths |
key= [None] *key_length |
forkey_indexinrange(key_length): |
letters='.join(itertools.islice(text_letters, key_index, None, key_length)) |
shifts= [] |
forkey_charinstring.ascii_lowercase: |
shifts.append( |
(compare_freq(vigenere_decrypt(letters, key_char, a_is_zero)), key_char) |
) |
key[key_index] =min(shifts, key=lambdax: x[0])[1] |
best_keys.append('.join(key)) |
best_keys.sort(key=lambdakey: compare_freq(vigenere_decrypt(text, key, a_is_zero))) |
returnbest_keys[:2] |
CIPHERTEXT=sys.stdin.read().strip() |
print'Solving Vigenere cipher:' |
print'*'*80 |
printtextwrap.fill(CIPHERTEXT, 80) |
print'*'*80 |
forkeyinreversed(solve_vigenere(CIPHERTEXT)): |
print' |
print'Found key: {!r}'.format(key) |
print'Solution:' |
print'='*80 |
printtextwrap.fill(vigenere_decrypt(CIPHERTEXT, key)) |
print'='*80 |