Modified Vigenere Cipher in python - Alphabet

2019-09-17 19:15发布

问题:

This is what I have to do:

Write a script in Python that is an implementation of a version of the Vigenere cipher for English text. Your script should distinguish lowercase and uppercase letters (i.e., the encryption key and the plaintext are allowed to be composed of lowercase and uppercase letters but the ciphertext should be uppercase). In addition to letters, there will be four other characters in the plain text: comma (26), dot (27), dash (28), underscore (29) changing the encryption function to be under mod 30.

Your script should read from standard input and write to standard output. It should prompt the user for the encryption key of size k. The key is not allowed to be repeated as in the standard Vigenere cipher. Instead, we will follow a block cipher-based idea. Basically, the plaintext and ciphertext will have blocks of size k which is same as the key size. If the key length is shorter than the plaintext, the ciphertext of block size k of the previous block is concatenated to the key. Here is an example when the keyword is ”Carbondale” with k = 10:

Plaintext :  SIU_CS-Department_is_the_best
 Key       :  CarbondaleUIHAQBBDPTUZ,MUOUCX
 Ciphertext:  UIHAQBBDPTUZ,MUOUCXHTODQTPYUM

So, I want to know how to tackle the part of the extra characters "," "." "/" "_". This is the function that is making the encryption:

a = len(key)

b = len(text)

while (len(key1) <= len(text1)):

    for i in range(0,a):
        num1 = ord(text1[i+var])%97
        num2 = ord(key1[i+var])%97
        num3 = num1+num2
        if (num3 > 25):
            encr.append(num3%25)
        else:
            encr.append(num3)
        i + 1

    for i in range(0,a):
        encr1.append(chr(encr[i+var]+97))
        i + 1

    for i in range(0,a):
        key1.append(encr1[i+var])
        i + 1
    var = var + a

回答1:

You code currently has the following problems (I am assuming that var = 0, encr = [], encr1 = [], key1 = list(key) and text1 = list(text) happen before the code you have posted):

  1. Your while loop will never start if the key is longer than the plaintext, and never end otherwise, as you never shorten text1 (and doing so would break your indexing);
  2. You don't need to manually increment the counter in a for loop (and if you wanted to, i + 1 without assignment effectively does nothing, you need i += 1);
  3. When using mod (%), you don't need to check if e.g. num3 < 25; and
  4. If you get around to including them, note that the extra characters you list aren't the same as those specified ("/" != "-").

Rather than using ord and chr, I would build my own alphabet to cycle over, e.g.

from string import ascii_uppercase

alphabet = list(ascii_uppercase) + [",", ".", "-", "_"]

You might find this implementation of the "standard" Vigenère helpful:

from itertools import cycle

def vigenere(plain, key, alphabet):
    for p, k in zip(plain, cycle(key)):
        index = alphabet.index(p) + alphabet.index(k)
        yield alphabet[index % len(alphabet)]

Here is some pseudo code for your modified implementation:

convert all text (plain, key) to upper case
create a list to hold output
split plain into blocks of length len(key)
for each block in plain:
    if it's the first block, use key to encode
    otherwise, use the last block of encoded text in output