Xor шифрование в C? - PullRequest
       37

Xor шифрование в C?

0 голосов
/ 28 апреля 2020

Я пытался изучить XOR в C и нашел этот пример на github.

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

void encryptDecrypt(char *input, char *output) {
    char key[] = {'K', 'C', 'Q'}; //Can be any chars, and any size array

    int i;
    for(i = 0; i < strlen(input); i++) {
        output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
    }
}

int main (int argc, char *argv[]) {
    char baseStr[] = "kylewbanks.com";

    char encrypted[strlen(baseStr)];
    encryptDecrypt(baseStr, encrypted);
    printf("Encrypted:%s\n", encrypted);

    char decrypted[strlen(baseStr)];
    encryptDecrypt(encrypted, decrypted);
    printf("Decrypted:%s\n", decrypted);
}

Можете ли вы объяснить мне это утверждение?

output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];

PS: Если я изменяю оператор в char baseStr [], вывод неправильный, почему? Например, если значение baseStr равно Test, выходные данные будут:

Encrypted: *?�
Decrypted:Test�&

РЕДАКТИРОВАТЬ: Я добавляю

memset(encrypted, '\0', sizeof(encrypted));
memset(decrypted, '\0', sizeof(decrypted));

, как предполагает user3386109, но проблема остается. , (Я добавляю memset после зашифрованного объявления и перед функцией encryptDecrypt)

Ответы [ 4 ]

2 голосов
/ 28 апреля 2020

PS: Если я изменяю оператор в char baseStr [], вывод неправильный, почему? Например, если значение baseStr равно Test, выходные данные будут:

Encrypted: *?�
Decrypted:Test�&

Это связано с тем, что encryptDecrypt использует strlen для определения конца "строки". strlen полагается на чтение нулевого байта для определения конца строки. При шифровании у вас есть нулевая завершенная строка. Но шифрование не создает строку с нулевым символом в конце, оно создает поток байтов, который не завершается нулем.

Мы можем это исправить.

void encryptDecrypt(char *input, char *output) {
    char key[] = {'K', 'C', 'Q'}; //Can be any chars, and any size array

    size_t len = strlen(input);
    for(size_t i = 0; i < len; i++) {
        printf("%zu\n", i);
        output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];
    }
    output[len] = '\0';
}

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

void encryptDecrypt(char *input, char *output, size_t *strlen)

// We know baseStr is a string and can use strlen.
char encrypted[strlen(baseStr)];
encryptDecrypt(baseStr, encrypted, strlen(baseStr));

// The encrypted string is the same length as `baseStr`.
char decrypted[strlen(baseStr)];
encryptDecrypt(encrypted, decrypted, strlen(baseStr));

output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];

(sizeof(key)/sizeof(char)) получает число элементов в key. sizeof производит количество байтов. Таким образом, (sizeof(key)/sizeof(char)) производит количество элементов путем деления размера массива на размер каждого элемента.

char всегда равен 1 байту, мы можем избавиться от sizeof(char), чтобы сделать вещи немного проще.

output[i] = input[i] ^ key[i % sizeof(key)];

Это делает xor каждого символа input с каждым символом key. Поскольку key и input, вероятно, имеют различную длину, а key, вероятно, короче , it must wrap around and reuse the key again.% `является оператором модуля, он разделит и оставит остаток.

  • 0% 3 = 0
  • 1% 3 = 1
  • 2% 3 = 2
  • 3% 3 = 0
  • 4% 3 = 1

Это также называется "математикой часов".

Таким образом, первый символ input является xor'd с первым символом key, второй со вторым, третий с третьим, но четвертый символ input - это xor'd с первым символом key.

Это можно увидеть в действии, напечатав i и Индекс ключа.

    for(size_t i = 0; i < len; i++) {
        printf("%zu\n", i);
        size_t ki = i % sizeof(key);
        printf("i = %zu, ki = %zu\n", i, ki);
        output[i] = input[i] ^ key[ki];
    }
2 голосов
/ 28 апреля 2020

Разбейте его на части, по частям:

  1. (sizeof(key)/sizeof(char)) Это длина массива key. В вашем случае это 3. Обратите внимание: sizeof(char) является избыточным и может быть опущен.
  2. key[i % 3] Это ограничивает индекс от key до 0, 1 или 2, таким образом, не обращаясь к памяти вне key массив.
  3. output[i] = input[i] ^ key[i % 3]; Вы выполняете XOR каждый char актер в input с key и присваиваете его output.

Примечание, если вы хотите напечатать encrypted и decrypted вы должны определить их следующим образом:

char encrypted[strlen(baseStr) + 1] = {'\0'};
char decrypted[strlen(baseStr) + 1] = {'\0'};

РЕДАКТИРОВАТЬ

Согласно user3386109 , Вы не можете предоставить инициализаторы при объявлении VLA . Таким образом, вы должны выполнить (например) следующее:

memset(encrypted, '\0', sizeof(encrypted));
memset(decrypted, '\0', sizeof(decrypted));
1 голос
/ 28 апреля 2020

Для:

output[i] = input[i] ^ key[i % (sizeof(key)/sizeof(char))];

sizeof(key)/sizeof(char) действительно получает количество элементов в списке: 3/1

I % numelemement получает остаток от I / цифры -so в этом случае при go повышении в позиции I будет 0,1,2,0,1,2 (в данном случае)

, поэтому

output_value = input_value XOR key [ остаток]

Вы не завершаете входные строки нулем, поэтому вызов strlen отличается от исходной строки.

0 голосов
/ 28 апреля 2020

Спецификатор формата %s предназначен для строк в стиле C. Вы не можете использовать его для произвольных массивов символов. Как видите, невозможно определить, сколько символов нужно напечатать.

Этот код довольно плохой. Он вызывает strlen на своем входе. Поэтому его входные данные должны быть строкой в ​​стиле C. Но его вывод не является строкой в ​​стиле C, это просто массив символов. Это отсутствие симметрии делает код трудным для использования и трудным для понимания.

...