Симметричный потоковый шифр C

У кого-нибудь есть хорошая реализация потокового шифра, написанная на чистом портативном C? На данный момент меня не очень беспокоит надежность шифра, потому что он нужен только для проверки концепции, но важна скорость. Я подумал о том, чтобы просто Xor'ировать с константой, если я не могу найти приличный потоковый шифр.


person Steven Behnke    schedule 22.12.2008    source источник


Ответы (7)


РЕДАКТИРОВАТЬ (2018 г.): используйте NaCl или libsodium или TweetNaCl если вы ищете меньший размер кода. Они обеспечивают надежное шифрование и должны быть намного быстрее, чем RC4.

RC4 — это очень простой для реализации алгоритм.

Ознакомьтесь с реализацией Sterling Camden или реализация Адама Бэка.

person orip    schedule 22.12.2008
comment
Спасибо. Я попробую Rc4. - person Steven Behnke; 23.12.2008

См. проект ECRYPT eStream. Это серьезные хардкорные криптографические алгоритмы, оцененные экспертами по безопасности. Насколько я знаю, все алгоритмы-кандидаты должны были включать реализацию на чистом C (не C++).

edit: Самое замечательное в этом веб-сайте то, что он подробно рассказывает о различных алгоритмах, включая их известные слабости, и включает контрольные показатели эффективности.

person Jason S    schedule 22.12.2008
comment
Кажется, они еще не доступны, если только я не могу найти ссылку. - person Steven Behnke; 23.12.2008
comment
Ссылки есть, но нестандартные (без подчеркивания) - это элементы в таблицах. (наведите указатель мыши, и вы увидите, как курсор изменится на ссылку) - person Jason S; 23.12.2008

Для чистого POC-приложения можно быстро поставить ROT13 на место. http://en.wikipedia.org/wiki/ROT13

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

person Brian Knoblauch    schedule 22.12.2008
comment
Да, я надеялся на что-то более криптографически более сильное, чем Rot13, и я имею дело с двоичными данными, а не с потоком байтов ASCII. - person Steven Behnke; 22.12.2008
comment
3ROT128? :-) Извините, ничего не мог поделать. :-) - person Brian Knoblauch; 22.12.2008

Я получил Blowfish без особых проблем. Он утверждает, что работает быстрее, чем DES.

person David Norman    schedule 22.12.2008
comment
Blowfish — это блочный, а не поточный шифр. - person Steven Behnke; 22.12.2008
comment
из википедии en.wikipedia.org/wiki/Block_cipher: Потоковые шифры могут быть построены с использованием блочных шифров. . OFB-режим и режим CTR — это блочные режимы, которые превращают блочный шифр в потоковый шифр. - person Jason S; 23.12.2008

Вот чрезвычайно простая реализация потокового шифра на языке C. Это не ни в коем случае не должно быть безопасным. Он просто иллюстрирует выполнение основных необходимых шагов.

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

Этот пример шифрует по одному char за раз. Вам придется расширить эту концепцию на более крупные фрагменты данных, чтобы шифрование было почти безопасным. Еще раз, я сделал это просто, чтобы проиллюстрировать основные шаги.

Удачи с проектом!

#include <stdio.h>

char staticKey;

void CycleKey(char data)
{
    /* this is where the real magic should occur */
    /* this code does *not* do a good job of it. */

    staticKey += data;

    if (staticKey & 0x80)
    {
        staticKey ^= 0xD8;
    }
    else
    {
        staticKey += 0x8B;
    }
}

void ResetCipher(const char * key)
{
    staticKey = 0;

    while (*key)
    {
        CycleKey(*key);
        key++;
    }
}

void Encrypt(const char * plaintext, char * encrypted)
{
    while (*plaintext)
    {
        *encrypted = *plaintext + staticKey;

        CycleKey(*encrypted);

        encrypted++;
        plaintext++;
    }

    *encrypted = '\0';
}

void Decrypt(char * plaintext, const char * encrypted)
{
    while (*encrypted)
    {
        *plaintext = *encrypted - staticKey;

        CycleKey(*encrypted);

        plaintext++;
        encrypted++;
    }

    *plaintext = '\0';
}

int main(void)
{
    char * key = "123";
    char * message = "Hello, World!";
    char encrypted[20];
    char decrypted[20];

    ResetCipher(key);
    Encrypt(message, encrypted);

    ResetCipher(key);
    Decrypt(decrypted, encrypted);

    printf("output: %s\n", decrypted);

    return 0;
}
person e.James    schedule 22.12.2008

Вы смотрели на OpenSSL? Он имеет безопасную реализацию множества криптографических алгоритмов и примитивов. Вам не нужно использовать его с чем-либо, связанным с сетью. Тем не менее, он не очень хорошо документирован или прост в освоении. Если вы очень заботитесь о безопасности (например, если вы храните личные пользовательские данные, такие как кредитные карты), вам определенно следует использовать OpenSSL или какую-либо другую безопасную реализацию вместо создания собственной.

person Jay Conrod    schedule 22.12.2008
comment
RC4 в OpenSSL может работать. Я как бы надеялся просто иметь реализацию шифра в отдельном файле C, а не всю библиотеку для импорта. - person Steven Behnke; 22.12.2008

Вы можете обратиться к приведенному ниже коду для понимания цели. Код использует генератор псевдослучайных чисел для генерации ключа и написан исключительно на C.

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

/* Function declarations */
int getSize(char *array);
int hashCode(const char *str, int size);
void convertIntToBinaryArray(int num, int *arr, int *index);
void encryptStreamCipher(int key[], int data[], int encypted_data[],int data_size);
void decryptStreamCipher(int key[], int enc_data[], int data_size);
void convertCharToBinary(char c,int *binary_arr,int *index);
void convertStringToBinary(char *str,int *binary_arr, int *size);
void convertBinaryToString(int *data,char *array_string,int *index);
char convertBinaryToChar(char *str);
void displayIntArray(int *array, int size);
void displayCharArray(char *array, int size);
#define MAX_SIZE 10000


int main(int argc, char **argv) {
    char array_string[MAX_SIZE];
    char ascii_key[MAX_SIZE];
    int data[MAX_SIZE];
    int key[MAX_SIZE];
    int encypted_data[MAX_SIZE];
    int seed;
    int key_int;
    int key_size = 0;
    int index;
    int data_size = 0;
    /* 1. Enter the data to encrypt (Do not use space in between)*/
    fprintf(stdout, "Enter data to encrypt: \n");
    fscanf(stdin, "%s", array_string);

    /* 2. Convert the string to binary data */
    convertStringToBinary(array_string,data,&data_size);
    printf("Data in binary: \n");
    displayIntArray(data,data_size);

    /* 3. Read the key string from user */
    fprintf(stdout, "Enter key to encrypt data with: \n");
    fscanf(stdin, "%s", ascii_key);

    /* 4.Get hash code from the key */
    key_size = getSize(ascii_key);
    seed = hashCode(ascii_key, key_size);

    /* 5. Set the key as seed to random number generator to create a key of random bits */
    srand(seed);
    key_int = rand();

    /* 6. Convert key to binary int array */
    convertIntToBinaryArray(key_int, key, &index);
    printf("Key in binary: \n");
    displayIntArray(key,index);

    /* 7. Encrypt : (Binary data) XOR (Binary key) */
    encryptStreamCipher(key, data, encypted_data, data_size);

    /* 8. Display encrypted data */
    printf("encrypted Data: \n");
    displayIntArray(encypted_data,data_size);

    /* 9.Now, Decrypt data and verify initial data */
    decryptStreamCipher(key, encypted_data, data_size);
    printf("Decrypted binary data: \n");
    displayIntArray(encypted_data,data_size);

    /* 10. Convert decrypted data in binary to string */
    memset(array_string,0,sizeof(array_string));
    convertBinaryToString(encypted_data,array_string,&data_size);

    /* 11.Display the original message in string */
    printf("Decrypted Data in String: \n");
    displayCharArray(array_string,data_size);

    return 0;
}

int getSize(char *array) {
    int size = 0;
    int i = 0;
    while ((i != MAX_SIZE) && (array[i] != '\0')) {
        i++;
        size++;
    }
    return size;
}

int hashCode(const char *str, int size) {
    int hash = 0;
    for (int i = 0; i < size; i++) {
        hash = 31 * hash + str[i];
    }
    return hash;
}

void convertIntToBinaryArray(int num, int *arr, int *index) {
    if (num == 0 || *index >= MAX_SIZE)
        return;
    convertIntToBinaryArray(num / 2, arr, index);
    if (num % 2 == 0)
        arr[(*index)++] = 0;
    else
        arr[(*index)++] = 1;

}

void encryptStreamCipher(int key[], int data[], int encypted_data[],
        int data_size) {
    for (int i = 0; i < data_size; i++) {
        encypted_data[i] = data[i] ^ key[i];
    }
}

void decryptStreamCipher(int key[], int enc_data[], int data_size) {
    for (int i = 0; i < data_size; i++) {
        enc_data[i] = enc_data[i] ^ key[i];
    }
}

void convertStringToBinary(char *str,int *binary_arr,int *index) {
    *index=0;
    for (int i = 0; i<strlen(str); i++) {
        convertCharToBinary(str[i],binary_arr,index);
    }
}

void convertCharToBinary(char c,int *binary_arr,int *index) {
    for (int i = 7; i >= 0; --i) {
        binary_arr[*index]=((c & (1 << i)) ? 1 : 0);
        (*index)++;
    }
}

void convertBinaryToString(int *data,char *array_string,int *index){
    int data_size=*index;
    char char_array[data_size];
    *index=0;

    for(int i=0;i<data_size;i++){
        char_array[i]=(data[i] == 1?'1':'0');
    }

    for(int i=0;i<data_size;i=i+8){
        char sub_str[8];
        memcpy(sub_str,char_array+i,8);
        array_string[(*index)++]=convertBinaryToChar(sub_str);
    }
}

char convertBinaryToChar(char *str){
    char c=strtol(str,0,2);
    return c;
}

void displayIntArray(int *array, int size)
{
    for (int i = 0; i < size; i++) {
        printf("%d",array[i]);
    }
    printf("\n");
}

void displayCharArray(char *array, int size)
{
    for (int i = 0; i < size; i++) {
        printf("%c",array[i]);
    }
    printf("\n");
}

Вывод:

Введите данные для шифрования: prateekjoshi

Данные в двоичном формате:

01110000011100100110000101110100011001010110010101101011011010100110111101110011011 0100001101001

Введите ключ для шифрования данных с помощью:

пароль

Ключ в двоичном формате:

101010100101110000101101000101

зашифрованные данные:

11011010001011100100110001100000011001010110010101101011011010100110111101110011011 0100001101001

Расшифрованные двоичные данные:

01110000011100100110000101110100011001010110010101101011011010100110111101110011011 0100001101001

Расшифрованные данные в строке:

пратекджоши

person Prateek Joshi    schedule 16.09.2017