Steven Behnke
Steven Behnke

Reputation: 3344

C Symmetric Stream Cipher

Does anyone have a good implementation of a stream cipher written in pure portable C? I am not terribly concerned with the strength of the cipher at this point in time because it is only for a proof of concept, but speed would be important. I've thought about just Xor'ing with a constant if I cannot find a decent stream cipher.

Upvotes: 6

Views: 11452

Answers (7)

orip
orip

Reputation: 75437

EDIT (2018): use NaCl or libsodium, or TweetNaCl if you're looking for a smaller code footprint. They provide strong encryption and should be much faster than RC4.

RC4 is a very simple algorithm to implement.

Check out Sterling Camden's implementation or Adam Back's implementation.

Upvotes: 6

Prateek Joshi
Prateek Joshi

Reputation: 4067

You can refer to the below code for understanding purpose. The code uses pseudo random number generator to generate key and purely written in 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");
}

Output:

Enter data to encrypt: prateekjoshi

Data in binary:

01110000011100100110000101110100011001010110010101101011011010100110111101110011011 0100001101001

Enter key to encrypt data with:

password

Key in binary:

101010100101110000101101000101

encrypted Data:

11011010001011100100110001100000011001010110010101101011011010100110111101110011011 0100001101001

Decrypted binary data:

01110000011100100110000101110100011001010110010101101011011010100110111101110011011 0100001101001

Decrypted Data in String:

prateekjoshi

Upvotes: 0

Jason S
Jason S

Reputation: 189626

See the ECRYPT eStream project. These are serious hardcore cryptographic algorithms judged by security experts. As far as I know all the candidate algorithms were required to include an implementation in pure C (not C++).

edit: The great thing about that website is it goes into a lot of depth about the different algorithms, including their known weaknesses, and includes performance benchmarks as well.

Upvotes: 4

James Eichele
James Eichele

Reputation: 119096

Here is an extremely basic implementation of a stream cipher in C. It is not, by any means meant to be secure. It simply illustrates how to perform the basic steps required.

The real magic needs to be done in the CycleKey function, which generates new key values as each chunk of data is passed through the encryption stream.

This example encrypts one char at a time. You would have to extend the concept to larger chunks of data for the encryption to be anywhere near secure. Once again, I have done this simply to illustrate the basic steps.

Good luck with the project!

#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;
}

Upvotes: 1

Brian Knoblauch
Brian Knoblauch

Reputation: 21349

For a pure POC application, you can quickly throw ROT13 into place. http://en.wikipedia.org/wiki/ROT13

However, I'm very hesitant in making the suggestion since too frequently simple POC code that's meant to be replaced later never is...

Upvotes: 2

David Norman
David Norman

Reputation: 19879

I got Blowfish going without much trouble. It claims to be faster than DES.

Upvotes: 1

Jay Conrod
Jay Conrod

Reputation: 29681

Have you looked at OpenSSL? It has a secure implementation of a lot of cryptographic algorithms and primitives. You don't have to use it with anything network related. However, it's not really well documented or easy to learn. If you care a lot about security (for instance, if you are storing private user data such as credit cards) you should definitely use OpenSSL or some other secure implementation instead of rolling your own.

Upvotes: 0

Related Questions