Шифрование с шифром замещения не генерирует действительный вывод ASCII - PullRequest
0 голосов
/ 18 января 2020

Я не могу понять, почему он говорит: «вывод не является допустимым текстом ASCII»!

Для того, чтобы вы поняли контекст проблемы, я опубликую то, что описано, чтобы сделать. ОНА НАЧИНАЕТСЯ ЗДЕСЬ!

В шифре замещения мы «зашифровываем» (то есть обратимым образом) сообщение, заменяя каждую букву другой буквой. Для этого мы используем ключ: в этом случае отображение каждой из букв алфавита на букву, которой она должна соответствовать, когда мы ее шифруем. Чтобы «расшифровать» сообщение, получатель сообщения должен знать ключ, чтобы он мог повернуть процесс вспять: перевести зашифрованный текст (обычно называемый шифротекстом) обратно в исходное сообщение (обычно называемое открытым текстом).

Ключом, например, может быть строка NQXPOMAFTRHLZGECYJIUWSKDVB. Эта 26-символьная клавиша означает, что A (первая буква алфавита) следует преобразовать в N (первый символ клавиши), B (вторая буква алфавита) следует преобразовать в Q (второй символ ключа) и т. Д.

Сообщение, подобное HELLO, будет затем зашифровано как FOLLE, заменяя каждую из букв в соответствии с отображением, определенным key.

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

Вот несколько примеров как программа может работать. Например, если пользователь вводит ключ YTNSHKVEFXRBAUQZCLWDMIPGJO и открытый текст HELLO:

$ ./substitution YTNSHKVEFXRBAUQZCLWDMIPGJO
plaintext:  HELLO
ciphertext: EHBBQ

Вот как может работать программа, если пользователь предоставляет ключ VCHPRZGJNTLSKFBDQWAXEUYMOI и открытый текст hello, world:

$ ./substitution VCHPRZGJNTLSKFBDQWAXEUYMOI
plaintext:  hello, world
ciphertext: jrssb, ybwsp

Обратите внимание, что ни запятая, ни пробел не были заменены шифром. Подставляйте только буквы алфавита! Также обратите внимание, что регистр исходного сообщения был сохранен. Строчные буквы остаются строчными, а прописные - прописными.

Не имеет значения, являются ли символы в самой клавише прописными или строчными. Ключ VCHPRZGJNTLSKFBDQWAXEUYMOI функционально идентичен ключу vchprzgjntlskfbdqwaxeuymoi (как, впрочем, VcHpRzGjNtLsKfBdQwAxEuYmOi).

#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Usage: ./substitution KEY");
        return 1;               
    }
    else if (argc == 2)
    {
        string text = argv[1];
        string storing = text;
        int counter = 0;
        int i = 0;
        bool number = true;
        bool flag = true;
        while (flag == true && i < 26)
        {
            if ((int)text[i] >= 48 && (int)text[i] <= 57)
            {
                 number = false;
            }
            if (((int)text[i] >= 65 && (int)text[i] <= 90) || ((int)text[i] >= 97 && (int)text[i] <= 122))
            {
                counter++;
                for ( int j = 0; j < counter - 1; j++)
                {
                    if ((int)storing[j] == (int)text[i] || (int)storing[j] + 32 == (int)text[i])
                    {
                        flag = false;
                    }
                }
            }
            i++;
        }
        if (number == false)
        {
            printf("Key must only contain alphabetic characters.");
            return 1;
        }
        if (flag == false)
        {
            printf("Key must not contain repeated characters.");
            return 1;
        }
        if (counter < 26)
        {
            printf("Key must contain 26 characters.");
            return 1;
        }
    }
    string plaintext = get_string("plaintext:");
    string key = argv[1];
    int counter;
    bool not_letter;
    bool capital1;
    bool capital;
    int crypto[strlen(plaintext)];
    for (int i = 0; i < strlen(plaintext); i++)
    {
        capital1 = false;
        capital = false;
        not_letter = false;
        if ((int)plaintext[i] >=65 && (int)plaintext[i] <= 90)
        {           
            counter =  (int)plaintext[i] - 65;            
            capital = true;
        }
        else if ((int)plaintext[i] >=97 && (int)plaintext[i] <= 122)
        {
            counter =  (int)plaintext[i] - 97;                          
            capital1 = true;
        }
        else
        {
            not_letter = true;
        }
        if (not_letter == true)
        {
            crypto[i] = (int)plaintext[i];
        }
        else if (capital == true)
        {
            if ((int)key[i] >=65 && (int)key[i] <= 90)
            {
                crypto[i] = (int)key[counter];
            }
            else if ((int)key[i] >=97 && (int)key[i] <= 122)
            {
                crypto[i] = (int)key[counter] - 32;
            }
        }
        else if (capital1 == true)
        {
            if ((int)key[i] >=65 && (int)key[i] <= 90)
            {
                crypto[i] = (int)key[counter] + 32;
            }
            else if ((int)key[i] >=97 && (int)key[i] <= 122)
            {
                crypto[i] = (int)key[counter];
            }  
        }
    }
    printf("ciphertext: ");
    for (int i = 0; i < strlen(plaintext); i++)
    {
        printf("%c", (char)crypto[i]);
    }
    printf("\n");
    return 0;
}

Когда я тестирую программу с check50 cs50/problems/2020/x/substitution из CS50, она говорит:

:) substitution.c exists
:) substitution.c compiles
:) encrypts "A" as "Z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
:) encrypts "a" as "z" using ZYXWVUTSRQPONMLKJIHGFEDCBA as key
:) encrypts "ABC" as "NJQ" using NJQSUYBRXMOPFTHZVAWCGILKED as key
:) encrypts "XyZ" as "KeD" using NJQSUYBRXMOPFTHZVAWCGILKED as key
:) encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZTEOGXHCIPJSQD as key
:) encrypts "This is CS50" as "Cbah ah KH50" using yukfrnlbavmwzteogxhcipjsqd as key
! :( encrypts "This is CS50" as "Cbah ah KH50" using YUKFRNLBAVMWZteogxhcipjsqd as key
    output not valid ASCII text
! :( encrypts all alphabetic characters using DWUSXNPQKEGCZFJBTLYROHIAVM as key
    output not valid ASCII text
:) handles lack of key
:) handles invalid key length
:) handles invalid characters in key
:) handles duplicate characters in key
:) handles multiple duplicate characters in key

1 Ответ

0 голосов
/ 18 января 2020

Давайте предположим, что вы преобразовали свой ключ в верхний регистр.

Тогда давайте упростим черт из вашего l oop:

int keyIndex;
bool lowercase;
for (int i = 0; i < strlen(plaintext); i++) {
    if (plaintext[i] >= 'A' && plaintext[i] <= 'Z') {
        keyIndex = plaintext[i] - 'A';
        lowercase = false;
    } else if (plaintext[i] >= 'a' && plaintext[i] <= 'z') {
        keyIndex = plaintext[i] - 'a';
        lowercase = true;
    } else {
        // do not encrypt that character
        ciphertext[i] = plaintext[i];
        // and skip the rest of the loop
        continue;
    }

    ciphertext[i] = key[keyIndex];

    // revert back to lowercase, if necessary
    if (lowercase) {
        ciphertext[i] += 'a' - 'A';
    }
}

Проблема, с которой вы столкнулись, заключается в что вы не разбили свою большую проблему на маленькие проблемы. Поэтому, если вы, например, заранее создаете все прописные буквы, вам не нужно принимать это во внимание позже.

Также очень важно сохранить симметрию в вашем приложении. Поэтому, если вы присваиваете значение в одной части if, то также делайте это в else. И если вам удастся остановиться рано (например, когда нужно сохранить символ), сделайте это.

Конечно, было бы одинаково правильно преобразовать ключ во все строчные буквы и затем преобразовать символы там, где это необходимо, в верхний регистр.

Никогда не используйте имена переменных, такие как counter или uppercase1. Это делает ваш код очень трудным для чтения; имена переменных должны быть максимально понятными.

Массив ciphertext - это просто строка / символьный массив в приведенном выше коде. Если вы используете C вместо C ++, то, как я полагаю, вы обычно используете char* или char[].

Конечно, это по-прежнему без разделения между функциями. Он также не использует функциональность платформы. Если вам удастся это сделать, то отладка / поддержка вашего приложения станет еще проще.

...