|
||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
|
Announcements
Services
Chapters
Feature Zones
|
IntroductionThe general ideas of the XOR256 encryption/decryption method for the Stream Ciphering case I presented in a previous article with codeproject.com "Some Stream Cipher Encryption/Decryption Algorithms". In that article I used for the generation of the sequence of Pseudo-Random Numbers the Lehmer congruential method. I was criticized for selecting that method because it is considered weak and predictable. In order to improve my encryption method I searched the Internet for some secure Pseudo-Random Number Generators (PRNG) and I found the description of the Arcfour algorithm which seems suitable for my purposes. This algorithm is believed to be fully interoperable with the RC4 algoritm. RC4 is trademark of RSA Data Security, Inc. The most comprehensive description of the Arcfour algorithm I have found on the Internet is at http://www.tillerman.st/ietf/rodney_drafts/draft-kaukonen-cipher-arcfour-01.txt, but information can be found in a lot of other places, just give "Arcfour" to a search engine. Arcfour Algorithm Description and Implementation
The method implemented in Preliminary Key Setup:
S[0] = 0; S[1] = 1; etc. up to S[255] = 255; for(i=0; i<256; i++) { j = (j + S [i] + key[i % keylen]) % 256; //Swapping temp = S[i]; S[i] = S[j]; S[j] = temp; } Random Byte Generation - the pseudorandom byte K is generated: i = (i+1) % 256; j = (j + S[i]) % 256; //Swapping temp = S[i]; S[i] = S[j]; S[j] = temp; t = (S[i] + S[j]) % 256; K = S[t]; The class CArcfourPRNG { public: //CONSTRUCTOR CArcfourPRNG(); void SetKey(unsigned char *pucKeyData, int iKeyLen); void Reset(); unsigned char Rand(); //... };
The Key Setup phase is implemented in the unsigned char aucKey[] = {0x01, 0x02, 0x03, 0x04, 0x05}; CArcfourPRNG oArcfourPRNG; oArcfourPRNG.SetKey(aucKey, 5); unsigned char ucRand; //The first 20 Random Bytes for(int i=0; i<20; i++) cout << "Rand=" << (int)oArcfourPRNG.Rand() << endl; The XOR256 Stream Ciphering Method Description and Implementation
The usual method applied for Stream Ciphering is to generate a sequence of Pseudo-Random Bytes
and to XOR each Stream Byte with the corresponding Pseudo-Random Byte. A known disadvantage of this
method is that you cannot use the same key many times because if you have two cipher texts
generated by the same key, by XOR-ing those cipher texts you can get the same result you
would get by XOR-ing the corresponding plain texts. After that the plain texts could be easily decrypted.
My cipher[k] = (text[k]^seqX[k] + seq256[k]) % 256 (1)
where the two sequences if(seq256[k] <= cipher[k]) then cipher[k] = cipher[k] - seq256[k] else cipher[k] = 256 - seq256[k] + cipher[k] text[k] = cipher[k] ^ seqX[k]
Let's assume now the scenario for breaking the encryption, considering in equation (1) First Round: cipher[k] = (text[k]^seqX[k][0] + seq256[k][0]) % 256 Second Round: cipher[k] = (cipher[k]^seq[k][1] + seq[k][1]) % 256 ... NRounds-th Round: cipher[k] = (cipher[k]^seq[k][NRounds-1] + seq[k][NRounds-1]) % 256
where the number of iterations (rounds) NRounds is considered a method parameter.
It can be shown that in this case the number of solutions is Let's consider the plain text text0 text1 ... textk ... which is encrypted in the ciphertext cipher0 cipher1 ... cipherk ... For each stream byte we need to get 2*NRounds random bytes from the PRNG, where NRounds>=1. If k is the current stream position we have: for(int i=0; i<NRounds; i++) { seqX[k][i] = Rand(); seq256[k][i] = Rand(); } We apply the following encryption algorithm: First Round: prev = prev^text[k] cipher[k] = (prev^seqX[k][0] + seq256[k][0]) % 256 Second Round: cipher[k] = (cipher[k]^seq[k][1] + seq[k][1]) % 256 ... NRounds-th Round: cipher[k] = (cipher[k]^seq[k][NRounds-1] + seq[k][NRounds-1]) % 256
with NRounds-th Round: if(seq256[k][NRounds-1] <= cipher[k]) then cipher[k] = cipher[k] - seq256[k][NRounds-1] else cipher[k] = 256 - seq256[k][NRounds-1] + cipher[k] cipher[k] ^= seqX[k][NRounds-1] ... Second Round: if(seq256[k][1] <= cipher[k]) then cipher[k] = cipher[k] - seq256[k][1] else cipher[k] = 256 - seq256[k][1] + cipher[k] cipher[k] ^= seqX[k][1] First Round: if(seq256[k][0] <= cipher(k)) then cipher[k] = cipher[k] - seq256[k][0] else cipher[k] = 256 - seq256[k][0] + cipher[k] text[k] = cipher[k]^prev^seqX[k][0] prev = prev ^ text[k];
also with class CStreamXOR256 { public: //CONSTRUCTOR CStreamXOR256(string const& rostrKey, int iRounds); //DESTRUCTOR virtual ~CStreamXOR256(); void Reset(); void Encrypt(string const& rostrIn, string& rostrOut); void Decrypt(string const& rostrIn, string& rostrOut); //... };
In the constructor try { CStreamXOR256 oStreamXOR256("aaaaaaaa", 9); string ostrIn("xxxxxxxx"); string ostrOut; oStreamXOR256.Encrypt(ostrIn, ostrOut); oStreamXOR256.Reset(); ostrIn = ""; oStreamXOR256.Decrypt(ostrOut, ostrIn); } catch(exception& roexception) { cout << roexception.what() << endl; } In the project attached to this article a File Encryption/Decryption console application is implemented. To use this application is very easy, for example to encrypt the Readme.txt file using the key "sjehj": FileCrypt.exe -ksjehj -e ReadMe.txt ReadMe.crp and to decrypt it: FileCrypt.exe -ksjehj -d ReadMe.crp ReadMe.txt Some command line flags are used to specify the key and the action. The command: FileCrypt.exe -h will provide help. ConclusionThe presented XOR256 stream ciphering method has some advantages over the known XOR> method because it is making possible the reuse of the encryption key. Some disadvantages are that it is slower, involving more computation and also the decryption is slower compared to the encryption. Also the security of the method has not been extensively studied. At this moment I don't know any possible efficient attack. I am very much interested in any feedback from the readers, please e-mail to me!
|
|||||||||||||||||||||||||||||||||||