def columnarTransportExample():

    print("Example of the columnar transport cipher")

    key = "BIRTHDAY"
    ptext = "THEQUICKBROWNFOXJUMPSOVERTHELAZYDOG"
    rank = uniqueRank(key)

    print("\nThe Key Is {}".format(key))

    print("Each letter of the key is ranked to get")
    print(*rank)

    print("\nThe plaintext is\n{}".format(ptext))

    print(
        "\nNow the text is read into the grid by rows. The key is placed above.\n"
    )

    print(" ".join([str(i) for i in rank]))
    for i in groups(ptext, 8):
        print(" ".join([e for e in i]))

    print(
        "\nFinally the grid is read off in accordance with column numbers starting with zero, then one, and so on.\n"
    )

    ctext, dtext = example(columnarTransport, ptext, key, complete=False)
    print(ctext)
Ejemplo n.º 2
0
def hillCipher(text,key,decode=False,alphabet="ABCDEFGHIJKLMNOPQRSTUVWXYZ"):
    
    """Encrypt text using matrix multiplication."""
    
    M = len(alphabet)
    
    # If a list is provided turn it into a sympy Matrix
    if type(key) == list:
        key = Matrix(key)
    
    # If we are decoding invert the key
    if decode == True:
        key = key.inv_mod(M)

    # Get the dimension of the key
    N = key.shape[0]

    # Apply any nulls needed
    rem = len(text) % N
    if rem != 0:
        text += "X"*(N-rem)
    
    out = ""
    for i in groups(text,N):
        x = Matrix([alphabet.index(let) for let in i])
        y = key.dot(x)
        out += "".join([alphabet[j%M] for j in y])

    return out
Ejemplo n.º 3
0
def binaryBraille(text, decode=False):
    alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    braille = [
        "010000", "100000", "101000", "110000", "110100", "100100", "111000",
        "111100", "101100", "011000", "011100", "100010", "101010", "110010",
        "110110", "100110", "111010", "111110", "101110", "011010", "011110",
        "100011", "101011", "011101", "110011", "110111", "100111"
    ]
    D = {}
    if decode == False:
        for i, j in zip(alpha, braille):
            D[i] = j

        out = ""
        for i in text:
            out += D[i]

        return out

    if decode == True:
        for i, j in zip(alpha, braille):
            D[j] = i

        out = ""
        for i in groups(text, 6):
            out += D[i]

        return out
def columnarTransport(text,key,decode=False,complete=False):
    
    k = uniqueRank(key)
    
    # Determine how many columns
    numcol = len(k)
    
    numrow,rem = divmod(len(text),numcol)
    longCols = k[:rem]
    

    # If complete is selected nulls are added so that the ciphertext fits
    # perfectly into the grid.
    if complete == True:
        if rem > 0:
            text = addNulls(text,total_len=numcol*(numrow+1))
        else:
            text = addNulls(text,total_len=numcol*numrow)
    
    if decode == False:
        
        # Read the text into the rows
        L = groups(text,len(k))

        # Read down each column
        out = []
        for col in argsort(k):
            for row in L:
                if len(row) > col:
                    out.append(row[col])
        return "".join(out)
    
    if decode == True:

        ctr = 0
        L = []
        for i in range(numcol):
            if i in longCols:
                L.append(text[ctr:ctr+numrow+1])
                #print("#",text[ctr:ctr+numrow+1],"#")
                ctr += (numrow+1)
                
            else:
                L.append(text[ctr:ctr+numrow])
                #print("#",text[ctr:ctr+numrow],"#")
                ctr += numrow

        out = []
        
        for row in range(numrow+1):
            for col in k:
                if len(L[col]) > row:
                    out.append( L[col][row] )

        return "".join(out)
Ejemplo n.º 5
0
def DRYAD(text, key, decode=False, codepage=False):

    # Extend the text with zeroes so groups are all the same size
    while len(text) % 5 != 0:
        text += "0"

    # Use the key value to generate a random DRYAD page
    page = []
    random.seed(key)
    for i in range(26):
        L = [let for let in "ABCDEFGHIJKLMNOPQRSTUVWXYZ"]
        random.shuffle(L)
        pos = 0
        row = []
        for chunk in [4, 3, 3, 2, 2, 3, 2, 2, 2, 2]:
            row.append("".join(L[pos:pos + chunk]))
            pos += chunk
        page.append(row)

    # If one wants to simply produce a DRYAD codepage this does so
    if codepage == True:
        ctr = 0
        for let, row in zip("ABCDEFGHIJKLMNOPQRSTUVWXYZ", page):
            if ctr % 4 == 0:
                print("\n       0   1   2  3  4   5  6  7  8  9")
            ctr += 1
            print(let, ":", " ".join(row))

    # Now reset the random seed
    random.seed()

    if decode == False:
        out = []
        for grp in groups(text, 5):
            row = random.choice([n for n in range(26)])
            # write down the letter indicating the row we are using
            out.append(chr(row + 65))
            # Pick a random letter from the options to represent that digit
            for digit in grp:
                out.append(random.choice(page[row][int(digit)]))
            out.append(" ")
        # The [:-1] removes the trailing space
        return "".join(out)[:-1]

    if decode == True:
        out = []
        text = text.split(" ")
        for section in text:
            code = page[ord(section[0]) - 65]
            for letter in section[1:]:
                for x, y in enumerate(code):
                    if letter in y:
                        out.append(str(x))
        return "".join(out)
Ejemplo n.º 6
0
def routeCipher(text, key, decode=False):
    while len(text) % key != 0:
        text += "X"

    if decode == False:
        G = groups(text, key)
        out = ""
        ctr = 0
        while ctr < key:
            gr = []
            for i in G:
                gr.append(i[ctr])
            if ctr % 2 == 1:
                gr.reverse()
            out += "".join(gr)
            ctr += 1

        return out

    if decode == True:

        key = len(text) // key

        G = groups(text, key)

        out = ""

        for passthru in range(key):
            for pos, lets in enumerate(G):

                if pos % 2 == 0:
                    a = lets[0]
                    G[pos] = lets[1:]

                if pos % 2 == 1:
                    a = lets[-1]
                    G[pos] = lets[:-1]

                out += a

        return out
Ejemplo n.º 7
0
def fourSquare(text,keys,decode=False,mode="IJ",printkey=False):
        
    # Convert the squares to numpy arrays to we can use numpy's indexing
    sq1 = np.array(makeSquare(keys[0],mode=mode))
    sq2 = np.array(makeSquare(keys[1],mode=mode))
    alphasq = np.array(makeSquare("",mode=mode))
    
    if mode == "IJ" or mode == "JI":
        text = text.replace("J","I")
    if mode == "KQ" or mode == "QK":
        text = text.replace("Q","K")
    if mode == "CK" or mode == "KC":
        text = text.replace("C","K")
    
    if printkey == True:
        n = 5
        if mode == "EX":
            n = 6
        for i in range(n):
            print(" ".join(alphasq[i]),end="  ")
            print(" ".join(sq1[i]))
        print()
        for i in range(n):
            print(" ".join(sq2[i]),end="  ")
            print(" ".join(alphasq[i]))
        return ""


    if len(text) % 2 == 1:
        text += "X"
    G = groups(text,2)
    
    if decode == False:
        out = ""
        for g in G:
            A = np.where(sq1 == g[0])
            B = np.where(sq2 == g[1])
            
            out += alphasq[A[0],B[1]][0]
            out += alphasq[B[0],A[1]][0]
            
        return out
    
    if decode == True:
        out = ""
        for g in G:
            A = np.where(alphasq == g[0])
            B = np.where(alphasq == g[1])
            
            out += sq1[A[0],B[1]][0]
            out += sq2[B[0],A[1]][0]
            
        return out
Ejemplo n.º 8
0
def enigmaExample():
        
    print("Enigma Example\n")
    
    # The Enigma machine had a codebook with different settings to be used
    # each day. This example just uses a hash of the date to randomly pick
    # what the settings will be. In actual use a stronger form of randomness is
    # needed.
    today = datetime.datetime.now().date()
    print("Today is {}\nThe Codebook Settings Are:".format(today))
    random.seed(hash(today))
    
    # Randomly pick the rotors, the reflector, the positions, and the plugboard
    # settings for the day
    rotors = random.sample(["I","II","III","IV","V"],k=3)
    reflector = random.choice(["A","B","C"])
    positions = random.choices("ABCDEFGHIJKLMNOPQRSTUVWXYZ",k=3)
    plugs = []
    for i in groups(random.sample("ABCDEFGHIJKLMNOPQRSTUVWXYZ",k=20),2):
        plugs.append("".join(i))

    # Write out those settings separated by a | symbol
    print(reflector,end = " | ")
    for i in rotors:
        print(i,end = " ")
    print("| ",end = "")
    for i in positions:
        print(i,end = "")
    print(" | ",end = "")
    for i in plugs:
        print(i,end = " ")
        
    # Whenever an Enigma message was sent it was preceeded by the ring settings
    # which told the recieving operator what offset from the day's rotor
    # positions should be used. This meant that a different cipher could be
    # used for every message without revealing exactly what the settnings were.
    rings = ["A","B","C"]
    print("\n\nRing Settings:",end= " ")
    for i in rings:
        print(i,end = " ")
    print("\n")
    
    ptext = "THEQUICKBROWNFOXJUMPSOVERTHELAZYDOGANDJACKDAWSLOVEMYBIGSPHINXOFQUARTZ"
    ctext = enigma(ptext,keys=[rotors,reflector,positions,plugs,rings])
    dtext = enigma(ctext,keys=[rotors,reflector,positions,plugs,rings])
    print(ctext)
    if dtext != ptext:
        print("ERROR")
        print(dtext)
Ejemplo n.º 9
0
def VICtranskeys(kstr,num):
    
    # Turn the first ten outputs into a unique list of integers
    transKey = uniqueRank(kstr[:10])
    # Break the rest of the keystream into ten rows
    G = groups(kstr[10:],10)
        
    transLens = [num+kstr[-2], num+kstr[-1]]
    #print(transLens)
    out = []
    for col in range(10):
        for row in G:
            out.append( row[transKey.index(col)] )
            if len(out) == sum(transLens):
                return out[:transLens[0]], out[transLens[0]:]
    return out[:transLens[0]], out[transLens[0]:]   
Ejemplo n.º 10
0
def printGrille(key, N):
    S = N * 2
    key = groups(key, (N // 2)**2)
    # The grille is actual key used for encryption, the key argument provided
    # specifies how to put it together.
    grille = np.zeros([S, S], dtype=int)

    # Generate the grille to be used as the key
    for block in key:
        for digit in block:
            pos = np.divmod(digit, S // 2)
            grille[pos[0], pos[1]] = 1
        grille = np.rot90(grille)

    # If requested print out the grille in a more human readable way
    for i in grille:
        t = ["_" if j == 0 else "#" for j in i]
        print("|", "|".join(t), "|", sep="")
Ejemplo n.º 11
0
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
Ejemplo n.º 12
0
def baconCode(text, decode=False):
    letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    codes = [
        "00000", "00001", "00010", "00011", "00100", "00101", "00110", "00111",
        "01000", "01001", "01010", "01011", "01100", "01101", "01110", "01111",
        "10000", "10001", "10010", "10011", "10100", "10101", "10110", "10111",
        "11000", "11001"
    ]

    if decode == False:
        out = ""
        for letter in text:
            out += codes[letters.index(letter)]

        return out

    if decode == True:
        out = ""
        for code in groups(text, 5):
            out += letters[codes.index(code)]
        return out
Ejemplo n.º 13
0
def turningGrilleExtended(text, key, decode=False, N=4):

    S = N * 2
    block_size = S**2

    # If the length of the text is not a multiple of the block size first
    # append some Xs to indicate the end of the message then random letters
    ctr = 0
    while len(text) % S**2 != 0:

        if ctr > 3:
            text += choice(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
        else:
            text += "X"
            ctr += 1

    out = []
    for i in groups(text, block_size):
        out.append(turningGrille(i, key=key, decode=decode, N=N))

    return "".join(out)
Ejemplo n.º 14
0
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])
Ejemplo n.º 15
0
def ASCII(text, decode=False, mode="BIN"):

    # We use Python's triple quotes so that its possible to include " and '
    # There are other ASCII characters but they are control characters not text
    chars = """ !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"""

    # Use the mode to determine the base to convert to and how many digits are
    # will be used. This determines any padding needed.
    modes = {
        "BIN": [2, 7],
        "UTF": [2, 8],
        "OCT": [8, 3],
        "DEC": [10, 3],
        "HEX": [16, 2]
    }

    base, length = modes[mode]

    out = []

    # Convert to a number then convert that number to a binary string
    if decode == False:
        for let in text:
            if let not in chars:
                raise Exception("{} is not part of the ASCII67 standard")

            t = baseConvert(chars.index(let) + 32, base)
            while len(t) < length:
                t = "0" + t

            out.append(t)

    if decode == True:
        for block in groups(text, length):
            n = str2dec(block, base)
            out.append(chars[n - 32])

    return "".join(out)
Ejemplo n.º 16
0
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
Ejemplo n.º 17
0
def twoSquare(text, keys, decode=False, mode="EX", printkey=False):

    # Convert the squares to numpy arrays to we can use numpy's indexing
    sq1 = np.array(makeSquare(keys[0], mode))
    sq2 = np.array(makeSquare(keys[1], mode))

    if mode == "IJ" or mode == "JI":
        text = text.replace("J", "I")
    if mode == "KQ" or mode == "QK":
        text = text.replace("Q", "K")
    if mode == "CK" or mode == "KC":
        text = text.replace("C", "K")

    if len(text) % 2 == 1:
        text += "X"

    # Print out the key in a nice way if the user needs it
    if printkey == True:
        if mode == "EX":
            for i in range(6):
                print(" ".join(sq1[i]))
            print()
            for i in range(6):
                print(" ".join(sq2[i]))
        else:
            for i in range(5):
                print(" ".join(sq1[i]))
            print()
            for i in range(5):
                print(" ".join(sq2[i]))

    if mode == "EX":
        sz = 6
    else:
        sz = 5

    G = groups(text, 2)

    if decode == False:
        out = ""
        for g in G:
            A = np.where(sq1 == g[0])
            B = np.where(sq2 == g[1])

            if A[0] == B[0]:
                out += sq1[(A[0] + 1) % sz, A[1]][0]
                out += sq2[(B[0] + 1) % sz, B[1]][0]

            elif A[1] == B[1]:
                out += sq1[A[0], (A[1] + 1) % sz][0]
                out += sq2[B[0], (B[1] + 1) % sz][0]

            else:
                out += sq1[A[0], B[1]][0]
                out += sq2[B[0], A[1]][0]

    if decode == True:
        out = ""
        for g in G:
            A = np.where(sq1 == g[0])
            B = np.where(sq2 == g[1])

            if A[0] == B[0]:
                out += sq1[(A[0] - 1) % sz, A[1]][0]
                out += sq2[(B[0] - 1) % sz, B[1]][0]

            elif A[1] == B[1]:
                out += sq1[A[0], (A[1] - 1) % sz][0]
                out += sq2[B[0], (B[1] - 1) % sz][0]

            else:
                out += sq1[A[0], B[1]][0]
                out += sq2[B[0], A[1]][0]
    return out
Ejemplo n.º 18
0
def turningGrille(text, key, decode=False, N=4):

    if len(key) != N**2:
        raise Exception("Key must have of the size {}".format(N**2))

    key = groups(key, (N // 2)**2)
    S = N * 2

    # Can't work with more than S^2 characters at a time
    if len(text) > S**2:
        raise Exception("Text cannot be longer than {}".format(S**2))

    # If we have less than 64 characters first insert Xs as nulls to indicate
    # that we have reached the end of the message. Then put in common letters
    # to make the less less obvious.
    ctr = 0
    while len(text) < S**2:

        if ctr > 3:
            text += choice(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"))
        else:
            text += "X"
            ctr += 1

    # The grille is actual key used for encryption, the key argument provided
    # specifies how to put it together.
    grille = np.zeros([S, S], dtype=int)
    # This matrix is what we will write the results into
    outmat = np.full([S, S], "")

    # Generate the grille to be used as the key
    for block in key:
        for digit in block:
            pos = np.divmod(digit, S // 2)
            grille[pos[0], pos[1]] = 1
        grille = np.rot90(grille)

    # When encoding write the letters of the text into the open spaces of the
    # grille. Then rotate the grille 90 degrees and continue.
    if decode == False:
        for rot in range(4):
            X = np.where(grille == 1)
            for i, j in zip(X[0], X[1]):
                a, text = text[0], text[1:]
                outmat[i, j] = a
            grille = np.rot90(grille)

        out = ""
        for i in outmat:
            out += "".join(i)

        return out

    if decode == True:

        gr = groups(text, S)
        out = ""
        for rot in range(4):
            X = np.where(grille == 1)
            for i, j in zip(X[0], X[1]):
                out += gr[i][j]
            grille = np.rot90(grille)

        return out
Ejemplo n.º 19
0
def hillCipherCracker(ctext, crib, N):

    if len(crib) < N * N:
        raise Exception("crib must have length {}".format(N * N))

    bestScore = quadgramScore(ctext)
    bestKey = Matrix.eye(N)

    # We can use this to reduce a matrix modulo 26
    mod26 = lambda x: x % 26

    # Convert the text and crib to numbers so they're more useful
    alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    ctextN = [alpha.index(i) for i in ctext]
    cribN = [alpha.index(i) for i in crib]

    # Break text into pieces
    G = groups(ctextN, N)

    # If the crib is long enough try it in sections to find if they line up
    # properly.
    for pos in range(len(crib) - (N * N - 1)):

        subCrib = cribN[pos:pos + (N * N)]
        #print(subCrib)
        A = Matrix(groups(subCrib, N)).T

        for i in range(len(G) - (N - 1)):

            L = []
            for x in range(N):
                L.append(G[x + i])
                B = Matrix(L).T

            # If the matrix is not invertible skip it
            if B.det() % 2 == 0:
                continue

            if B.det() % 13 == 0:
                continue

            C = A * (B.inv_mod(26))

            tKey = C.applyfunc(mod26)

            # We run the Hill Cipher in encryption mode NOT decryption
            t = hillCipher(ctext, tKey)
            score = quadgramScore(t)

            if score > bestScore:
                bestScore = score
                bestKey = tKey

    if bestKey.det() % 2 == 0 or bestKey.det() % 13 == 0:
        print("Non-singular matrix error")
        print("Key Should be Inverse of:")
        pprint(bestKey)
        print()
    else:
        print("Key Is:")
        pprint(bestKey.inv_mod(26))
        print()

    print("Decrypt Looks Like:")
    print(hillCipher(ctext, bestKey))
Ejemplo n.º 20
0
def playfair(text, key, decode=False, mode="IJ", printkey=False):

    # Make sure the text will work correctly for a playfair cipher in this mode
    text = playfairPrep(text, mode=mode)

    # Derive the alphabet to be used for the key based on the mode
    sq = makeSquare(key, mode=mode)
    sqWhere = squareIndex(sq)

    if printkey == True:
        if mode == "EX":
            for i in range(6):
                print(" ".join(sq[i]))

        else:
            for i in range(5):
                print(" ".join(sq[i]))

    G = groups(text, 2)

    if decode == False:

        if mode == "EX":
            sz = 6
        else:
            sz = 5

        out = ""

        for g in G:
            A = sqWhere[g[0]]
            B = sqWhere[g[1]]

            # If they share a column
            if A[0] == B[0]:
                out += sq[A[0]][(A[1] + 1) % sz]
                out += sq[B[0]][(B[1] + 1) % sz]

            # If they share a row
            elif A[1] == B[1]:
                out += sq[(A[0] + 1) % sz][A[1]]
                out += sq[(B[0] + 1) % sz][B[1]]

            # Otherwise
            else:
                out += sq[A[0]][B[1]]
                out += sq[B[0]][A[1]]

        return out

    if decode == True:
        if mode == "EX":
            sz = 6
        else:
            sz = 5

        out = ""

        for g in G:
            A = sqWhere[g[0]]
            B = sqWhere[g[1]]

            if A[0] == B[0]:
                out += sq[A[0]][(A[1] - 1) % sz]
                out += sq[B[0]][(B[1] - 1) % sz]

            elif A[1] == B[1]:
                out += sq[(A[0] - 1) % sz][A[1]]
                out += sq[(B[0] - 1) % sz][B[1]]

            else:

                out += sq[A[0]][B[1]]
                out += sq[B[0]][A[1]]

        return out