#๐ vigenere cipher
24 messages ยท Page 1 of 1 (latest)
@slate brook
Remember to:
- Ask your Python question, not if you can ask or if there's an expert who can help.
- Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
- Explain what you expect to happen and what actually happens.
:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.
import itertools
import string
import sys
import textwrap
"""
Run this script in a shell with the ciphertext to decode on STDIN
"""
####################################################################################################
# Vienere encryption and decryption functions
####################################################################################################
def vigenere(plaintext, key, a_is_zero=True):
key = key.lower()
if not all(k in string.ascii_lowercase for k in key):
raise ValueError("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
+ (0 if a_is_zero else 2) # Account for non-zero indexing
) % 26) if letter in string.ascii_lowercase # Ignore non-alphabetic chars
else letter
for letter in plaintext.lower()
)
def vigenere_decrypt(ciphertext, key, a_is_zero=True):
# Decryption is encryption with the inverse key
key_ind = [ord(k) - ord('a') for k in key.lower()]
inverse = "".join(chr(ord('a') +
((26 if a_is_zero else 22) -
(ord(k) - ord('a'))
) % 26) for k in key)
return vigenere(ciphertext, inverse, a_is_zero)```
Explain what you expect to happen and what actually happens.
def test_vigenere(text, key, a_is_zero=True):
ciphertext = vigenere(text, key, a_is_zero)
plaintext = vigenere_decrypt(ciphertext, key, a_is_zero)
assert plaintext == text, "{!r} -> {!r} -> {!r} (a {}= 0)".format(
text, ciphertext, plaintext, "" if a_is_zero else "!")
# Test that the Vigenere encrypt and decrypt work (or are at least inverses)
for text in ["rewind", "text with spaces", "pun.ctuation", "numb3rs"]:
for key in ["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)```
def compare_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
"""
if not text:
return None
text = [t for t in text.lower() if t in string.ascii_lowercase]
freq = [0] * 26
total = float(len(text))
for l in text:
freq[ord(l) - ord('a')] += 1
return sum(abs(f / total - E) for f, E in zip(freq, ENGLISH_FREQ))
def solve_vigenere(text, key_min_size=None, key_max_size=None, a_is_zero=True):
best_keys = []
key_min_size = key_min_size or 1
key_max_size = key_max_size or 20
text_letters = [c for c in text.lower() if c in string.ascii_lowercase]
for key_length in range(key_min_size, key_max_size):
# Try all possible key lengths
key = [None] * key_length
for key_index in range(key_length):
letters = "".join(itertools.islice(text_letters, key_index, None, key_length))
shifts = []
for key_char in string.ascii_lowercase:
shifts.append(
(compare_freq(vigenere_decrypt(letters, key_char, a_is_zero)), key_char)
)
key[key_index] = min(shifts, key=lambda x: x[0])[1]
best_keys.append("".join(key))
best_keys.sort(key=lambda key: compare_freq(vigenere_decrypt(text, key, a_is_zero)))
return best_keys[:2]
CIPHERTEXT = sys.stdin.read().strip()
print "Solving Vigenere cipher:"
print "*" * 80
print textwrap.fill(CIPHERTEXT, 80)
print "*" * 80
for key in reversed(solve_vigenere(CIPHERTEXT)):
print ""
print "Found key: {!r}".format(key)
print "Solution:"
print "=" * 80
print textwrap.fill(vigenere_decrypt(CIPHERTEXT, key))
print "=" * 80
Already explained in general chat also I have very little experience with Python. Like maybe 1 semester + random messing around worth of experience. This isn't for homework this is just for a random event I'm participating in.
lovely
the website i downloaded the code from says "Python script that solves English Vigenere ciphers by comparing the input against the letter frequency distribution of the English language"
so i expect it to do that
it no longer gives me errors but now idk what to do lol
entering the text im suppose to decode doesnt do anything lol
im tired so im probably gonna go pass out but if you want to try and figure it out you can use "pqdzh byium bdstav @prvq sglijwlv ux mhc wmjcdw wm wlx" to check if it works
First, this looks like Python 2 mixed with Python 3. Try running it in Python 2.
Also it expects you to run the file with the argument on the same line
I have almost 0 experience
Ex: C:\Users\...\...\...\solver.py otasiro natrsi nato
Like a semester + some messing around
But I really do gotta get some sleep lol
It's almost 5am
If you need more information look up command-line arguments and Python 2 vs 3
Good idea
This help channel has been closed and it's no longer possible to send messages here. If your question wasn't answered, feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.