PHP RC4 Security Algorithm

tekz

Active member
Joined
Aug 22, 2015
Posts
29
here is code i wrote to simulate how WEP crypto work, and how it's key is generated. wrote simple crib drag function to decrypt messages with same key used for encryption. WPA also uses RC4, but improved the way keys are generated, so crib dragging is no longer possible since same key wont be generated in as few packets.

Code:
#include <stdio.h>

#include <random>


void ksa(unsigned char state[], unsigned char key[], unsigned int len)
{
	int i, j = 0, k;


	for (i = 0; i <= 255; ++i)
	{
		state[i] = i;
	}


	for (i = 0; i <= 255; ++i)
	{
		j = (j + state[i] + key[i & (len - 1)]) & 255;


		k = state[i];
		state[i] = state[j];
		state[j] = k;
	}
}


void prga(unsigned char state[], unsigned char stream[], unsigned int len)
{
	int i, j = 0, k = 0, l;


	for (i = 0; i < len; ++i)
	{
		j = (j + 1) & 255;
		k = (k + state[j]) & 255;


		l = state[j];
		state[j] = state[k];
		state[k] = l;


		stream[i] = state[(state[j] + state[k]) & 255];
	}
}


void _xor(unsigned char data1[], unsigned char data2[], unsigned int len)
{
	for (int i = 0; i < len; i++)
	{
		data1[i] ^= data2[i];
	}
}


void crib_drag(unsigned char data[], unsigned char crib[], unsigned int data_len, unsigned int crib_len)
{
	int i, j;


	unsigned char *temp = new unsigned char[crib_len];


	for (i = 0; i <= data_len - crib_len; i++)
	{
		for (j = 0; j < crib_len; j++)
		{
			temp[j] = crib[j];
		}


		for (j = 0; j < crib_len; j++)
		{
			temp[j] ^= data[j + i];


			printf("%02X ", temp[j]);
		}


		printf("\n");
	}


	delete[] temp;
}


int main()
{
	unsigned char state[256];
	unsigned char data[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 };
	unsigned char *stream = new unsigned char[sizeof(data) / sizeof(data[0])];


	unsigned int iv;
	unsigned long long key;


	std::random_device rd;
	std::mt19937 mt(rd());
	std::uniform_real_distribution<float> dist(0.0, 16777215.0);


	iv = dist(mt);
	key = 10000000000;


	printf("iv + key: %d + %llu", iv, key);


	unsigned char seed[] =
	{
		(unsigned char)(iv >> 0), (unsigned char)(iv >> 8), (unsigned char)(iv >> 16),
		(unsigned char)(key >> 0), (unsigned char)(key >> 8), (unsigned char)(key >> 16), (unsigned char)(key >> 24), (unsigned char)(key >> 32)
	};


	ksa(state, seed, sizeof(seed) / sizeof(seed[0]));
	prga(state, stream, sizeof(data) / sizeof(data[0]));
	_xor(data, stream, sizeof(data) / sizeof(data[0]));


	printf("\nencoded data: ");


	for (int i = 0; i < sizeof(data) / sizeof(data[0]); i++)
	{
		printf("%02X ", data[i]);
	}


	ksa(state, seed, sizeof(seed) / sizeof(seed[0]));
	prga(state, stream, sizeof(data) / sizeof(data[0]));
	_xor(data, stream, sizeof(data) / sizeof(data[0]));


	printf("\ndecoded data: ");


	for (int i = 0; i < sizeof(data) / sizeof(data[0]); i++)
	{
		printf("%02X ", data[i]);
	}


	delete[] stream;


	getchar();
}
 
Interesting :)

A few things to mention though:
- I wouldn't use prefixed functions like that as they are reserved for other things; _xor
* You seem to declare your variables in an ANSI C (C89) way when you re-use them (especially in for loops), then the consistency stopped in the main() function haha. Not a real issue, just something I noticed.

Last.. This isn't a good way to seed:
Code:
std::random_device rd;
  std::mt19937 mt(rd());

Technically you could have done this:
Code:
std::mt19937 mt(std::random_device{}());

As it is identical to the above, but this way of seeding is still not great. std::random_device is good, but its implementation doesn't make it easy to use for seeding random number generators. What that does is creates an object which is meant to ask the OS for system provided randomness, retrieves a single 32 bit integer from that device object, then creates a std::seed_seq object to initialize/seed the Mersenne Twister. This is problematic when you understand that the Mersenne Twister's internal state uses 624 32 bit integers, plus a few more for other things.
 
edited:
Code:
#include <stdio.h>

#include <random>


void ksa(unsigned char state[], unsigned char key[], unsigned int len)
{
    int i, j = 0, k;


    for (i = 0; i <= 255; ++i)
    {
        state[i] = i;
    }


    for (i = 0; i <= 255; ++i)
    {
        j = (j + state[i] + key[i & (len - 1)]) & 255;


        k = state[i];
        state[i] = state[j];
        state[j] = k;
    }
}


void prga(unsigned char state[], unsigned char stream[], unsigned int len)
{
    int i, j = 0, k = 0, l;


    for (i = 0; i < len; ++i)
    {
        j = (j + 1) & 255;
        k = (k + state[j]) & 255;


        l = state[j];
        state[j] = state[k];
        state[k] = l;


        stream[i] = state[(state[j] + state[k]) & 255];
    }
}


void _xor(unsigned char data1[], unsigned char data2[], unsigned int len)
{
    int i;


    for (i = 0; i < len; i++)
    {
        data1[i] ^= data2[i];
    }
}


void crib_drag(unsigned char data[], unsigned char crib[], unsigned int data_len, unsigned int crib_len)
{
    int i, j;


    unsigned char *temp = new unsigned char[crib_len];


    for (i = 0; i <= data_len - crib_len; i++)
    {
        for (j = 0; j < crib_len; j++)
        {
            temp[j] = crib[j];
        }


        for (j = 0; j < crib_len; j++)
        {
            temp[j] ^= data[j + i];


            printf("%02X ", temp[j]);
        }


        printf("\n");
    }


    delete[] temp;
}


int main()
{
    unsigned char state[256];
    unsigned char data[] = { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F, 0x72, 0x6C, 0x64 };
    unsigned char *stream = new unsigned char[sizeof(data) / sizeof(data[0])];


    unsigned int iv;
    unsigned long long key;


    int i;


    std::mt19937_64 generator(std::random_device{}());
    std::uniform_real_distribution<float> distribution(0.0, 16777215.0);


    iv = distribution(generator);
    key = 10000000000;


    printf("iv + key: %d + %llu", iv, key);


    unsigned char seed[] =
    {
        (unsigned char)(iv >> 0), (unsigned char)(iv >> 8), (unsigned char)(iv >> 16),
        (unsigned char)(key >> 0), (unsigned char)(key >> 8), (unsigned char)(key >> 16), (unsigned char)(key >> 24), (unsigned char)(key >> 32)
    };


    ksa(state, seed, sizeof(seed) / sizeof(seed[0]));
    prga(state, stream, sizeof(data) / sizeof(data[0]));
    _xor(data, stream, sizeof(data) / sizeof(data[0]));


    printf("\nencoded data: ");


    for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
    {
        printf("%02X ", data[i]);
    }


    ksa(state, seed, sizeof(seed) / sizeof(seed[0]));
    prga(state, stream, sizeof(data) / sizeof(data[0]));
    _xor(data, stream, sizeof(data) / sizeof(data[0]));


    printf("\ndecoded data: ");


    for (i = 0; i < sizeof(data) / sizeof(data[0]); i++)
    {
        printf("%02X ", data[i]);
    }


    delete[] stream;


    getchar();
}

thanks for your feedback, i realize that there is better way to seed it after i read c++ - Best way to seed mt19937_64 for Monte Carlo simulations - Stack Overflow, but i felt like it wasn't necessary for the purpose of this project.
 
With numbers for an LCG preferred by Knuth, here's a still rather easy, but better alternative:
Code:
[NO-PARSE]typedef std::linear_congruential_engine
< uint64_t, 0x5851F42D4C957F2DU, 0x14057B7EF767814FU, 0U >
knuth_lcg;[/NO-PARSE]

Use:
Code:
[NO-PARSE]std::random_device rdev;
uint64_t rng_seed = (uint64_t(rdev()) << 32) | rdev();
knuth_lcg rng { rng_seed };[/NO-PARSE]

:thumbsup2:

Interestingly, if you use GCC, you probably should try to use something other than std::random_device because AFAIK they have not allowed it to support non-deterministic results like Microsoft has with their compiler packaged with Visual Studio. That is a big issue.. :confused2::eek4:
 
Last edited:

Has Sysnative Forums helped you? Please consider donating to help us support the site!

Back
Top