alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def shift_cipher(plaintext, shift):
"""Shift (Caesar) cipher: shift each letter by shift places in alphabet"""
ciphertext=[]
for i in range(len(plaintext)):
c = plaintext[i]
numc = alpha.find(c) # convert letter to number
shiftnumc = (numc + shift) % 26
codedc = alpha[shiftnumc] # convert back to a letter
ciphertext.append(codedc)
return ciphertext
shift_cipher("HELLOZ", 3)
# CHALLENGE: finish Vigenere cipher
# first do case where key has length 3
def vig_cipher3(plaintext, key):
"""Vigenere cipher with key length 3:
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:
shift ith char in plaintext by key[i % len(key)]"""
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])
# to decrypt, use -key with same function
vig_cipher(['K', 'F', 'O', 'M', 'R', 'A'], [-3,-1])
# vig twice, with different keys, same length
vig_cipher(vig_cipher("HELLOZ", [3,5,7]),[9,1,2])
# to decrypt above, use negatives of keys, also reverse order in which applied
vig_cipher(vig_cipher(['T', 'K', 'U', 'X', 'U', 'I'], [-9,-1,-2]),[-3,-5,-7])
# double encryption above is same as encrypting just once
# with key being the sum of the two keys
# [3,5,7]),[9,1,2] -> [3+9, 5+1, 7+2] = [12,6,9]
vig_cipher("HELLOZ", [12,6,9])
# vig twice, with different keys, different length
vig_cipher(vig_cipher("HELLOZ", [3,5,7]),[7,3,2,5])
# can't just add keys together, since lengths are different
# 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: shift ith char in plaintext by key[i]"""
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
codedc = alpha[codednumc]
ciphertext.append(codedc)
return ciphertext
onetimepad("HELLOZ", [3,1,2,0,25,2])
onetimepad("HELLOZ", [3,1,2,0])