def quagmire4(text, keys, decode=False, alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"): key1 = alphabetPermutation(keys[0], alphabet) key2 = alphabetPermutation(keys[1], alphabet) M = len(alphabet) indicator = keys[2] table = [] for lt in indicator: sh = key2.index(lt) % M table.append(key2[sh:] + key2[:sh]) out = [] if decode == False: for ctr, ltr in enumerate(text): t = table[ctr % len(indicator)] out.append(t[key1.index(ltr)]) if decode == True: for ctr, ltr in enumerate(text): t = table[ctr % len(indicator)] out.append(key1[t.index(ltr)]) return "".join(out)
def chaocipher(text, keys=["", ""], decode=False): if keys[0] == "": L = "ABCDEFGHIJKLMONPQRSTUVWXYZ" else: L = alphabetPermutation(keys[0]) if keys[1] == "": R = "ABCDEFGHIJKLMONPQRSTUVWXYZ" else: R = alphabetPermutation(keys[1]) validptext(text, "ABCDEFGHIJKLMONPQRSTUVWXYZ") validkeys(keys, [str, str]) if decode == False: out = "" for letter in text: pos = R.index(letter) out += L[pos] L = permuteL(L, L[pos]) R = permuteR(R, letter) return out if decode == True: out = "" for letter in text: pos = L.index(letter) out += R[pos] L = permuteL(L, letter) R = permuteR(R, R[pos]) return out
def straddlingCheckerboard(text,keys=["A",[0,1]],decode=False,alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"): if len(keys) != 2: raise Exception('must provide both keys') if len(keys[1]) != 2: raise Exception('must provide two numbers for checkboard') # Derive the internally used key from the input KEY = alphabetPermutation(keys[0],alphabet) # Divide they KEY into a mutable list so we can pop from it KEY = list(KEY) D = {} if decode == False: # First row of the checkerboard for i in range(10): if i not in keys[1]: D[KEY.pop(0)] = str(i) # Second row for i in range(10): codegroup = str(keys[1][0])+str(i) D[KEY.pop(0)] = codegroup # Third row for i in range(len(KEY)): codegroup = str(keys[1][1])+str(i) D[KEY.pop(0)] = codegroup return "".join([D[letter] for letter in text]) if decode == True: # First row of the checkerboard for i in range(10): if i not in keys[1]: D[str(i)] = KEY.pop(0) # Second row for i in range(10): codegroup = str(keys[1][0])+str(i) D[codegroup] = KEY.pop(0) # Third row for i in range(len(KEY)): codegroup = str(keys[1][1])+str(i) D[codegroup] = KEY.pop(0) L = [] text = [sym for sym in text] while len(text) > 0: if text[0] in str(keys[1]): L.append(text.pop(0)+text.pop(0)) else: L.append(text.pop(0)) return "".join([D[i] for i in L])
def cipherDisk(text, key=["", "A"], decode=False, gaprange=[5, 9], turn=0): # The outer ring is in order outer = "ABCDEFGHIJKLMONPQRSTUVWXYZ0123456789" # Determine the inner ring if key[0] == "": inner = outer else: inner = alphabetPermutation(key[0], outer) if key[1] not in outer: raise Exception("Start position must exist in the inner ring.") # Turn the inner ring until the correct symbol is in the first position while inner[0] != key[1]: inner = stepN(inner, 1) out = [] if decode == False: # Raise an error if there are digits in the plaintext since they will # cause decoding errors. for i in "0123456789": if i in text: raise Exception("Cannot include numbers in the plaintext.") # Choose were the first gap is gap = random.randint(gaprange[0], gaprange[1]) for i in text: # Encrypt letters one by one and count down to the gap out.append(inner[outer.index(i)]) gap -= 1 if gap == 0: # If we reached the gap encrypt a number, turn the wheel, and # choose the size of the next gap R = random.choice("0123456789") out += inner[outer.index(R)] inner = stepN(inner, int(R)) gap = random.randint(gaprange[0], gaprange[1]) # Turn the inner ring if the cipher is set to do that inner = stepN(inner, turn) # Decoding works like simple substitution but numbers are skipped and the # the inner ring turns instead if decode == True: for i in text: dec = outer[inner.index(i)] if dec in "0123456789": inner = stepN(inner, int(dec)) else: out.append(dec) inner = stepN(inner, turn) return "".join(out)
def polybiusSquare(text, key="", decode=False, mode="EX", sep=""): #the IJ version of the polybius (25 characters) if mode == "IJ": alpha = "ABCEDFGHIKLMNOPQRSTUVWXYZ" text = text.replace("J", "I") key = key.replace("J", "I") #the CK version of the polybius (25 characters) if mode == "CK": alpha = "ABEDFGHIJKLMNOPQRSTUVWXYZ" text = text.replace("C", "K") key = key.replace("C", "K") #the KQ version of the polybius (25 characters) if mode == "KQ": alpha = "ABCEDFGHIJKLMNOPRSTUVWXYZ" text = text.replace("Q", "K") key = key.replace("Q", "K") #the extended version of the polybius (36 characters) if mode == "EX": alpha = "ABCEDFGHIJKLMNOPQRSTUVWXYZ0123456789" # Generate the internal key using user key k = alphabetPermutation(key, alphabet=alpha) if mode == "EX": codegroups = ["".join(i) for i in product("123456", repeat=2)] else: codegroups = ["".join(i) for i in product("12345", repeat=2)] if decode == False: # Pair each letter with a codegroup D = {} for i, j in zip(k, codegroups): D[i] = j ctext = [D[let] for let in text] return sep.join(ctext) if decode == True: # Pair each codegrou with a letter D = {} for i, j in zip(k, codegroups): D[j] = i if sep != "": grps = text.split(sep) else: grps = [text[2 * j:2 * j + 2] for j in range(len(text) // 2)] dtext = [D[pair] for pair in grps] return "".join(dtext)
def ADFGX(text,keys=["A",[0,1]],decode=False,printkey=False): """ :param text: The text to be encrypyed. Must be alphanumeric and uppercase. The letter J will be replaced with I. :param keys: Two keywords, the first to prepare a 5x5 square a the second to control a columnar transport cipher. :param decode: Boolean. If false encrypt plaintext. If true decode ciphertext """ # Adjust the text if necessary text = text.replace("J","I") while len(text) % len(keys[1]) != 0: text += "X" alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ" alpha = alphabetPermutation(keys[0],alpha) if printkey == True: sq = makeSquare(keys[0],mode="EX") for i in range(6): print(" ".join(sq[i])) pairs = product("ADFGX",repeat=2) D1 = {} D2 = {} for letter,pair in zip(alpha,pairs): D1[letter] = "".join(pair) D2["".join(pair)] = letter # The ADFGX cipher has a roughly symmetric encode and decoding process # the only difference is that the columnar transport is reversed. # Turn every letter into a pair of symbols ctext = "".join([D1[i] for i in text]) # Scramble the symbols, this will break apart some of the pairs ctext = columnarTransport(ctext,keys[1],decode=decode) # Now take the scrambled symbols and turn them back into letters ctext = groups(ctext,2) ctext = "".join([D2[i] for i in ctext]) return ctext
def hutton(text,keys=["",""],decode=False): alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" k1 = [alpha.index(i) + 1 for i in keys[0]] # Generate the initial alphabet then turn it into a list so it is easier to # manipulate by swapping letters. k2 = list(alphabetPermutation(keys[1])) out = "" if decode == False: for ctr,letter in enumerate(text): # Current position pos = k2.index(letter) # First increment, the alphabetic position of the first letter of the key inc1 = alpha.index(k2[0])+1 # Second increment, the cyclic values from the first key aka "password" inc2 = k1[ctr%len(k1)] A = (pos+inc1+inc2) % 26 out = out + k2[A] swap(k2,letter,k2[A]) if decode == True: for ctr,letter in enumerate(text): # Current position pos = k2.index(letter) # First increment, the alphabetic position of the first letter of the key inc1 = alpha.index(k2[0])+1 # Second increment, the cyclic values from the first key aka "password" inc2 = k1[ctr%len(k1)] A = (pos-inc1-inc2) % 26 out = out + k2[A] swap(k2,letter,k2[A]) return out
def substitution(text, key, decode=False, alphabet=""): if alphabet == "": alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" validptext(text, alphabet) validkeys(key, str) # Derive the internally used key from the input KEY = alphabetPermutation(key, alphabet) out = [] if decode == False: for i in text: out.append(KEY[alphabet.index(i)]) if decode == True: for i in text: out.append(alphabet[KEY.index(i)]) return "".join(out)
def trifid(text, key, decode=False): triplets = product("123", repeat=3) alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ+" alphabet = alphabetPermutation(key, alphabet) D1 = {} D2 = {} for trip, alph in zip(triplets, alphabet): D1[alph] = "".join(trip) D2["".join(trip)] = alph if decode == False: A, B, C = "", "", "" # Convert the letter into their triplets for letter in text: gr = D1[letter] A += gr[0] B += gr[1] C += gr[2] ctext = "" for gr in groups(A + B + C, 3): ctext += D2[gr] return ctext if decode == True: grs = "" for letter in text: gr = D1[letter] grs += gr A = grs[:len(grs) // 3] B = grs[len(grs) // 3:2 * len(grs) // 3] C = grs[2 * len(grs) // 3:] dtext = [i + j + k for i, j, k in zip(A, B, C)] return "".join([D2[n] for n in dtext])
def ADFGVX(text, keys=["A", [0, 1]], decode=False, printkey=False): """ :param text: The text to be encrypyed. Must be alphanumeric and uppercase. :param keys: Two keywords, the first to prepare a 6x6 square a the second to control a columnar transport cipher. :param decode: Boolean. If false encrypt plaintext. If true decode ciphertext """ while len(text) % len(keys[1]) != 0: text += "X" alpha = alphabetPermutation(keys[0], "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") sq = makeSquare(keys[0], mode="EX") if printkey == True: for i in range(6): print(" ".join(sq[i])) pairs = product("ADFGVX", repeat=2) D1 = {} D2 = {} for letter, pair in zip(alpha, pairs): D1[letter] = "".join(pair) D2["".join(pair)] = letter # Turn every letter into a pair of symbols ctext = "".join([D1[i] for i in text]) # Scramble the symbols, this will break apart some of the pairs ctext = columnarTransport(ctext, keys[1], decode=decode) # Now take the scrambled symbols and turn them back into letters ctext = groups(ctext, 2) ctext = "".join([D2[i] for i in ctext]) return ctext