3

To clarify before beginning: I'm aware there are similar topics, but nothing that has really offered any direct help. Also: this is a class project; so I'm not looking for anyone to code my project for me. Tips and advice is what I'm looking for. (I would go to my professor for this kind of thing, but he can't be bothered to check his e-mail.)

This program is meant to take a user supplied seed, generate a key based on the integer, then to generate a 95 x 95 matrix in which all printable ascii characters are available for encryption/decryption purposes. (Key is all alpha, and capitalized)

The kicker: all the cells must be randomized. See image below: Randomized Vigenere Matrix

I will post my code below (Python is certainly not my forte, though I will definitely take constructive criticisms.):

import random

class Vigenere(object):

    def __init__(self, seed):
        random.seed(seed)
        #string containing all valid characters
        self.symbols= """!"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] ^_`abcdefghijklmnopqrstuvwxyz{|}~"""
        self.eTable = [[0 for i in range(len(self.symbols))] for i in range(len(self.symbols))]
        self.dTable = [[0 for i in range(len(self.symbols))] for i in range(len(self.symbols))]
        self.keyWord = ""
        self.message = ""
        self.ciphertext = ""
        self.keywordFromSeed(seed)

    def setMessage(self,message):
        self.message = message

    #Generate psuedorandom keyword from seed
    def keywordFromSeed(self,seed):
        Letters = []

        while seed > 0:
            Letters.insert(0,chr((seed % 100) % 26 + 65))
            seed = seed // 100
        self.keyWord = "".join(Letters)
        self.buildVigenere()

    #Contructs a 95 x 95 matrix filled randomly
    def buildVigenere(self):
        n = len(self.symbols)

        #Build the vigenere matrix
        for i in range(n):
            temp = self.symbols

            for j in range(n):
                r = random.randrange(len(temp))
                self.eTable[i][j] = temp[r]

                #This line below does not fill entire matrix. Why?
                self.dTable[j][(ord(temp[r])-32)] = chr(i+32)

                temp = temp.replace(temp[r],'')

    def encrypt(self):
        for i in range(len(self.message)):
            mi = i
            ki = i % len(self.keyWord)
            self.ciphertext = self.ciphertext + self.eRetrieve(ki,mi)

    def decrypt(self):
        for i in range(len(self.message)):
            emi = i
            ki = i % len(self.keyWord)
            char = self.dRetrieve(ki,emi)
            self.ciphertext = self.ciphertext + char
        print(self.ciphertext)

    def eRetrieve(self,ki,mi):       
        row = ord(self.message[mi]) - 32
        col = ord(self.keyWord[ki]) - 32
        print(row, col)
        return self.eTable[row][col]

    def dRetrieve(self,ki,emi):
        n = len(self.symbols)
        whichRow = ord(self.keyWord[ki]) - 32
        whichCol = ord(self.message[emi]) - 32
        return(self.dTable[whichRow][whichCol])

And just in case it helps, here's my main.py:

import argparse
import randomized_vigenere as rv

def main():

    #Parse parameters
    parser = argparse.ArgumentParser()
    parser.add_argument("-m", "--mode", dest="mode", default = "encrypt", help="Encrypt or Decrypt")
    parser.add_argument("-i", "--inputfile", dest="inputFile", default = "inputFile.txt", help="Input Name")
    parser.add_argument("-o", "--outputfile", dest="outputFile", default = "outputFile.txt", help="Output Name")
    parser.add_argument("-s", "--seed", dest="seed", default =7487383487438734, help="Integer seed")
    args = parser.parse_args()

    #Set seed and generate keyword
    seed = args.seed

    #Construct Matrix

    f = open(args.inputFile,'r')
    message = f.read()
    Matrix = rv.Vigenere(seed)
    Matrix.setMessage(message)

    if(args.mode == 'encrypt'):
        Matrix.encrypt()

        Matrix.setMessage(Matrix.ciphertext)
        Matrix.decrypt()
    else:
        Matrix.decrypt()

    o = open(args.outputFile,'w')
    o.write(str(Matrix.ciphertext))

if __name__ == '__main__':
    main()

I've just been using the default seed: 7487383487438734

My Plaintext: ABCdefXYZ

  • First, I presume the defs in Vigenere class are indented? Then you really need to have a look at Python class model: functions inside a class must have a first argument called self. – Eric Levieil Jul 25 '15 at 22:59
  • Also your "randomized vigenere cipher" is not a common cipher (contrary to the original vigenere). So please include a theoretical description. – Eric Levieil Jul 25 '15 at 23:12
  • Thanks! I went back and and fixed my class. I'll post the updated version soon. As far as my description essentially what I want to have is E[x][y]=z => D[y][z]=x – Taylor Kirk Jul 26 '15 at 04:18

2 Answers2

0

I am going to answer this question:

#This line below does not fill entire matrix. Why?

I think it is your current question. If I am not mistaken, this should be the first line of your question, not a simple comment in function:

def buildVigenere(self):
    n = len(self.symbols)

    #Build the vigenere matrix
    for i in range(n):
        temp = self.symbols

        for j in range(n):
            r = random.randrange(len(temp))
            self.eTable[i][j] = temp[r]

            #This line below does not fill entire matrix. Why?
            self.dTable[j][(ord(temp[r])-32)] = chr(i+32)

            temp = temp.replace(temp[r],'')

First thing I did was to build a small self-contained example like this:

import random

def buildVigenere():
    symbols= """!"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\] ^_`abcdefghijklmnopqrstuvwxyz{|}~"""

    n = len(symbols)
    eTable = [[0 for i in range(len(symbols))] for i in range(len(symbols))]
    dTable = [[0 for i in range(len(symbols))] for i in range(len(symbols))]

    #Build the vigenere matrix
    for i in range(n):
        temp = symbols

        for j in range(n):
            r = random.randrange(len(temp))
            eTable[i][j] = temp[r]
            print (r,  len(temp),  j,  len(symbols),  temp[r])
            #This line below does not fill entire matrix. Why?
            print (ord(temp[r])-32)
            dTable[j][(ord(temp[r])-32)] = chr(i+32)

            temp = temp.replace(temp[r],'')
    print dTable

buildVigenere()

You really should learn to do that if you want answers here, and more generally be a successful programmer. Finding where the problem is and being able to reproduce it in a simple case is often the key.

Here I get an error:

Exception "unhandled IndexError"
list assignment index out of range

I add some print statements(see above) and I found that the error come from the fact that < > = are missing in the symbols string.

Why don't you use chr to build your string symbols?

And for buildVigenere, you can make a much simpler version by using random.shuffle(x)

Eric Levieil
  • 3,244
  • 2
  • 9
  • 16
  • Thank you for your response! I'm not sure why it's not on the symbol list here. My symbol list does contain the <=> characters. Weird. But, that still would not explain why the decryption table is left only about half full. – Taylor Kirk Jul 26 '15 at 18:52
0

I was able to get it working. I'll post my implementation below:

main.py

import argparse
import randomized_vigenere as rv

def main():

    #Parse parameters
    parser = argparse.ArgumentParser()
    parser.add_argument("-m", "--mode", dest="mode", default = "encrypt", help="Encrypt or Decrypt")
    parser.add_argument("-i", "--inputfile", dest="inputFile", default = "inputFile.txt", help="Input Name")
    parser.add_argument("-o", "--outputfile", dest="outputFile", default = "outputFile.txt", help="Output Name")
    parser.add_argument("-s", "--seed", dest="seed", default =7487383487438734, help="Integer seed")
    args = parser.parse_args()

    #Set seed and generate keyword
    seed = args.seed

    #Construct Matrix
    f = open(args.inputFile,'r')
    message = f.read()
    Matrix = rv.Vigenere(seed)
    Matrix.setMessage(message)

    if(args.mode == 'encrypt'):
        Matrix.encrypt()
    else:
        Matrix.decrypt()

    o = open(args.outputFile,'w')
    o.write(str(Matrix.ciphertext))

    print("Seed used:",Matrix.seed)
    print("Key Generated:",Matrix.keyWord)
    print("Original Message:",Matrix.message)
    print("Decoded Message:",Matrix.ciphertext)

if __name__ == '__main__':
    main()

randomized_vigenere.py

(Be sure to add '<', '=', and '>' to the symbol list. For some reason they keep getting removed from this post.)

import random

class Vigenere(object):

    #Initialize Vigenere object.
        #Sets the random seed based on integer passed to the object
        #Establishes all valid symbols
        #Generates empty matrix which will contain values for encryption/decryption
        #Generates a keyword based on the integer passed to the object
    def __init__(self, seed):
        random.seed(seed)
        self.seed = seed
        self.symbols= """ !"#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"""
        self.Table = [[0 for i in range(len(self.symbols))] for i in range(len(self.symbols))]
        self.keyWord = ""
        self.message = ""
        self.ciphertext = ""
        self.keywordFromSeed(seed)

    #Sets the plaintext that will be encrypted/decrypted
    def setMessage(self,message):
        self.message = message

    #Generate psuedorandom keyword from seed
    def keywordFromSeed(self,seed):
        Letters = []

        while seed > 0:
            Letters.insert(0,chr((seed % 100) % 26 + 65))
            seed = seed // 100
        self.keyWord = "".join(Letters)
        self.buildVigenere()

    #Contructs a 95 x 95 matrix filled randomly with no repeats within same line
    def buildVigenere(self):
        random.seed(self.seed)
        temp = list(self.symbols)
        random.shuffle(temp)
        temp = ''.join(temp)

        for sym in temp:
            random.seed(self.seed)
            myList = []
            for i in range(len(temp)):
                r = random.randrange(len(temp))
                if r not in myList:
                    myList.append(r)
                else:
                    while(r in myList):
                        r = random.randrange(len(temp))
                    myList.append(r)
                while(self.Table[i][r] != 0):
                    r = (r + 1) % len(temp)
                self.Table[i][r] = sym

    #Encryption function that iterates through both the message and the keyword
        #and grabs values from Table based on the ordinal value of the current
        #character being pointed to be the iterator
    def encrypt(self):
        for i in range(len(self.message)):
            mi = i
            ki = i % len(self.keyWord)
            self.ciphertext = self.ciphertext + self.eRetrieve(ki,mi)

    def eRetrieve(self,ki,mi):       
        row = ord(self.message[mi]) - 32
        col = ord(self.keyWord[ki]) - 32
        return self.Table[row][col]

    #Decryption function that iterates through both the message and the keyword
        #and grabs values from Table based on the ordinal value of the current
        #keyWord character being pointed to be the iterator, then traversing the
        #row that corresponds to that value. While traversing that row, once there
        #is a match of the message value being searched for, take the iterator value
        #and convert it to an ascii character. This is the decrypted character
    def decrypt(self):
        self.ciphertext = ""
        for i in range(len(self.message)):
            emi = i
            ki = i % len(self.keyWord)
            self.ciphertext = self.ciphertext + self.dRetrieve(ki,emi)

    def dRetrieve(self,ki,emi):
        n = len(self.symbols)
        whichRow = ord(self.keyWord[ki]) - 32
        for i in range(n):
            if self.Table[i][whichRow] == self.message[emi]:
                decryptChar = chr(i + 32)
                return(decryptChar)

Thank you to @Eric-Levieil for assistance