Заставляя Vigenére шифровать / дешифровать пропускать пробелы - PullRequest
2 голосов
/ 06 октября 2019

Я создал инструмент шифрования на основе меню, используя шифр Vigenére. На данный момент программа шифрует пробелы, как я могу заставить программу пропускать пробелы.

#creating variables to be used
text_in_use = ''
encrypt_key = ''
decrypt_key = ''

#function to encypypt input text
def encrypt(plaintext, key):
    keyLength = len(key)
    keyAsIntegers = [ord(i) for i in key] #create list with the ASCII value for each charachter in key
    plaintextAsIntegers = [ord(i) for i in plaintext] #create list with the ASCII value for each charachter in text
    encyptedtext = '' 
    for i in range(len(plaintextAsIntegers)): #
        encryptvalue = (plaintextAsIntegers[i] + keyAsIntegers[i % keyLength]) % 26 #execute encryption or characters according to vigenere definition
        encyptedtext += chr(encryptvalue + 65)
    return encyptedtext #return the encyptes tex

#function to decrypt the encrypted text
def decrypt(encyptedtext, key):
    keyLength = len(key)
    keyAsIntegers = [ord(i) for i in key] #create list with the ASCII value for each charachter in key
    encryptedTextAsIntegers = [ord(i) for i in encyptedtext] #create list with the ASCII value for each charachter in text
    plaintext = ''
    for i in range(len(encryptedTextAsIntegers)):
        value = (encryptedTextAsIntegers[i] - keyAsIntegers[i % keyLength]) % 26 #decryption of encrypted characters
        plaintext += chr(value + 65)
    return plaintext #return decrypted text

#check if user input is valid
def check_value(userEntry):
    while True:
        try: #check if userinput is an integer
            userInput = int(input(userEntry))
            if userInput not in range(1,6): #check if userinput is in valid range
                print("Invalid choice, valid choices are 1-5! Try again! \n")
        except ValueError:
            print("Invalid choice! Input can't be empty or a string! \n")
            print("""1: Input text to work with
2: Print the current text
3: Encrypt the current text
4: Decrypt the current text
5: Exit""")
        else:
            return userInput #return valid userinput


def menu():
    while True:
        print("""1: Input text to work with
2: Print the current text
3: Encrypt the current text
4: Decrypt the current text
5: Exit""")

        choice = check_value("Enter Choice: ")

        if choice == 1: #allows user to input text for use
            text_in_use = str(input("Enter Text: ")).upper()
            print("Text is set to:",text_in_use,"\n")
        elif choice == 2: #prints set text
            print("Your text:",text_in_use,"\n") 
        elif choice == 3: #ask user to set encryptionkey
            encrypt_key = str(input("Enter an encryptionkey: ")).upper()
            text_in_use = encrypt(text_in_use, encrypt_key)
            print("Your text:", text_in_use)
        elif choice == 4: #ask user for decryptionkey
            decrypt_key = str(input("Enter a the decryptionkey: ")).upper()
            text_in_use = decrypt(text_in_use, decrypt_key)
            print("Your text:", text_in_use)
        elif choice == 5:
            exit()

menu()

Я хочу, чтобы программа работала так, как она уже работает, но она должна пропускать пробелы в шифровании.

Например:

"HELLO MY MAN" --> encryption(key = asd) --> "HWOLG MQ MSQ"

Другими словами, пробелы должны оставаться в зашифрованном тексте.

Ответы [ 2 ]

1 голос
/ 06 октября 2019

Не уверен, как вы получили «HWOLG MQ MSQ», когда в качестве обычного текста «HELLO MY MAN» и клавиша «asd». Я получаю что-то еще.

В любом случае, может быть что-то вроде этого:

def encrypt(plaintext, key):
    from itertools import cycle
    from string import ascii_uppercase as alphabet

    offset = ord("A")

    key_char = cycle(key)

    encrypted_plaintext = ""
    for char in plaintext:
        # If the current character is any kind of whitespace...
        if char.isspace():
            # Append it to the final string with no changes.
            encrypted_plaintext += char
        else:
            # The character is not whitespace, so you have to encrypt it.
            char_sum = ord(char) + ord(next(key_char))
            char_sum_wrapped = char_sum % len(alphabet)
            encrypted_plaintext += chr(char_sum_wrapped + offset)
    return encrypted_plaintext

Если текущий символ является пробелом, просто добавьте его в последнюю строку без каких-либо изменений. str.isspace возвращает истину, если каждый символ в строке (текущий символ) является своего рода пробелом (пробел, табуляция, перевод строки, возврат каретки и т. Д.).

Я стараюсь избегать работы с индексами и жестко закодированными числами всякий раз, когдаЯ могу, поэтому я изменил некоторые вещи. Например, вместо того, чтобы превращать все символы в открытом тексте и ключе в целые числа, прежде чем делать что-либо еще, как вы, я просто конвертирую символы в цикле. Между прочим, цикл также отличается - я перебираю символы в открытом тексте, в отличие от выполнения цикла for на основе диапазона, а затем трактую i как индекс для текущего символа. Все остальное в основном одинаково (за исключением вещей key_char и itertools.cycle, прочитайте мои заметки ниже).

Еще одна вещь, которую стоит отметить, - в этой реализации итератор key_char будеттолько продвигаться, если текущий символ в открытом тексте не является пробелом - однако, вы можете захотеть, чтобы он продвигался независимо. Просто кое-что, что нужно иметь в виду.

Не имеет значения, кажется, это желаемое поведение для этого шифра.

Кроме того, просто примечание, ваша программа начинается с этих нескольких строк:

#creating variables to be used
text_in_use = ''
encrypt_key = ''
decrypt_key = ''

Они вообще не вносят вклад, вы можете безопасно удалить их.

РЕДАКТИРОВАТЬ - Еще немного информации:

itertools.cycle - это функция, которая, учитываяИтерируемый (как строка или список), возвращает итератор, который возвращает элементы в этой итерируемой. Например:

>>> from itertools import cycle
>>> char_iterator = cycle("ABC")
>>> next(char_iterator)
'A'
>>> next(char_iterator)
'B'
>>> next(char_iterator)
'C'
>>> next(char_iterator)
'A'
>>> next(char_iterator)
'B'
>>> next(char_iterator)
'C'
>>> next(char_iterator)
'A'
>>> 

Как видите, цикл повторяется бесконечно. По этой причине я решил использовать itertools.cycle для замены keyAsIntegers[i % keyLength] в исходном коде.

string.ascii_uppercase - это просто строка, состоящая из всех заглавных букв между AZ. В моем коде я импортирую ascii_uppercase и в той же строке переименую его в alphabet, но они совпадают.

>>> from string import ascii_uppercase as alphabet
>>> alphabet
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
>>> 
0 голосов
/ 06 октября 2019

Вы можете либо проигнорировать метод шифрования для пробела, либо изменить свой код, чтобы просто запустить шифрование на реальных словах, например, используя plaintext.split(' '), чтобы получить список слов для шифрования, затем запустив шифрование / дешифрование для каждого элемента. в списке.

Вот как игнорировать пробелы во время шифрования. Обратите внимание, что эта реализация предполагает, что, «пропуская пустое пространство», вы подразумеваете, что вы обычно все еще шифруют пробельные символы. Ключ все еще продвигается для пробела, что не совсем правильное поведение.

def encrypt(plain_text, key):
    ...
    for i in range(len(plaintextAsIntegers)):
        if plain_text[i] == ' ':
            encryptedtext += ' '
        else:
            encryptvalue = (plaintextAsIntegers[i] + keyAsIntegers[i % keyLength]) % 26 
            encyptedtext += chr(encryptvalue + 65)

Расшифровка должна быть противоположной процедурой.

...
if encryptedtext[i] == ' ':
    plain_text += ' ':
else:
...

Это делает шифрование более слабым, поскольку можно догадаться, какие слова могут быть какими, исходя из их длины. Гораздо лучше включить все пробелы (включая вкладки и т. Д.) В качестве символа для шифрования.

...