alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
# shift (Caesar) cipher
# slight modification of code from last time
# looping over position in plaintext, rather than character
def shift_cipher(plaintext, shift):
ciphertext = []
for i in range(len(plaintext)): # this line differs from last time, but does same thing
c = plaintext[i]
numc = alpha.find(c)
shiftnumc = (numc + shift) % 26
codedc = alpha[shiftnumc]
ciphertext.append(codedc)
return ciphertext
shift_cipher("HELLOZ", 3)
# CHALLENGE: finish this function
def vig_cipher3(plaintext, key):
"""Assume key has length 3.
Vigenere cipher: shift ith char in plaintext by key[i % 3]"""
ciphertext = []
for i in range(len(plaintext)):
c = plaintext[i]
numc = alpha.find(c)
codednumc = (numc + key[i % 3]) % 26
codedc = alpha[codednumc]
ciphertext.append(codedc)
return ciphertext
vig_cipher3("HELLOZ", [3,1,2])
def vig_cipher(plaintext, key):
"""Vigenere cipher: shifting ith char in plaintext by key[i % len(key)].
key is a list of numbers"""
ciphertext = []
for i in range(len(plaintext)):
c = plaintext[i]
numc = alpha.find(c)
codednumc = (numc + key[i % len(key)]) % 26
codedc = alpha[codednumc]
ciphertext.append(codedc)
return ciphertext
vig_cipher("HELLOZ", [3,1,2])
vig_cipher("HELLOZ", [3,1])
# to decrypt, use same function, use negative of original key
vig_cipher(['K', 'F', 'O', 'M', 'R', 'A'], [-3,-1])
# encrypt twice with different keys of same length
vig_cipher(vig_cipher("HELLOZ",[3,1,2]), [5,7,19])
# above is same as encrypting just once with key being the sum of the two keys
# [3,1,2], [5,7,19] -> [3+5, 1+7, 2+19] = [8, 8, 21]
vig_cipher("HELLOZ",[8,8,21])
# encrypt twice with different keys of different length
vig_cipher(vig_cipher("HELLOZ",[3,1,2]), [5,7,19,3])
# can't just add keys together in the above, since have different length
# ONE-TIME PAD: Vigenere cipher, with key same length as message
# This is unbreakable ("information-theoretically secure"),
# but only if key is never reused (hence "one-time") and key is random
def onetimepad(plaintext, key):
"""One time pad: Vigenere cipher, with key same length as (or longer than) message"""
if (len(plaintext)>len(key)):
print("ERROR: key size is too small")
return
ciphertext = []
for i in range(len(plaintext)):
c = plaintext[i]
numc = alpha.find(c)
codednumc = (numc + key[i]) % 26 # don't need mod key(length), since never wraps around
codedc = alpha[codednumc]
ciphertext.append(codedc)
return ciphertext
onetimepad("HELLOZ", [3,0,1,2,25,1])
onetimepad("HELLOZ", [3,0,1,2])
# using the same key twice in onetimepad
# is equivalent to a vig cipher
onetimepad("SECRET" , [3,1,7,19,13,0])
onetimepad("MESSAG", [3,1,7,19,13,0])
vig_cipher("SECRETMESSAG", [3,1,7,19,13,0])