There are two kinds of symmetric key algorithms: One is block cipher. It divides a message into different blocks, then encrypt each block. There are five modes of cipher block operations: ECB, CBC, CTR, CFB, OFB. The other is stream cipher, which processes the message as a whole. The only stream cipher I know is RC4.
Obviously, the length of the message may not be the multiples of block size. Thus, padding is needed in most cases. There are several kinds of padding methods. For example, The input to the DES CBC encryption process shall be padded to a multiple of 8 octets, in the following manner. Let n be the length in octets of the input. Pad the input by appending 8-(n mod 8) octets to the end of the message, each having the value 8-(n mod 8), the number of octets being added. In hexadecimal, the possible paddings are: 01, 0202, 030303, 04040404, 0505050505, 060606060606, 07070707070707, and 0808080808080808. All input is padded with 1 to 8 octets to produce a multiple of 8 octets in length. The padding can be removed unambiguously after decryption.
In order to perform the timing tests, we decide to produce an array of random number.
If you're running on a Win32 OS, or a Unix OS with /dev/random, then you can
use AutoSeededRandomPool:
#include "osrng.h" using namespace CryptoPP; . . . AutoSeededRandomPool rng; byte randomBytes[10]; rng.GenerateBlock(randomBytes, 10);
Otherwise you should use RandomPool and seed it yourself with random,
unpredictable data:
RandomPool rng; rng.Put(seed, seedLen); byte randomBytes[10]; rng.GenerateBlock(randomBytes, 10);
e.g. The script is as follows:
else if (command == "des")
{
// VC60 workaround: use char array instead of std::string to workaround MSVC's
getline bug
char plaintext[1024] = "", ciphertext[1024]="";
char detext[1024] = "";
const byte passPhrase[] = {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
/* corresponding 56 bit key is 40,81,02,04,08,10,20 */
AutoSeededRandomPool rng;
rng.GenerateBlock((byte*)plaintext, 8);
cout << "\nThe plain text is "<< plaintext <<"\n";
gettimeofday(¤t_time, &tzp);
t1 = timeval2double(¤t_time);
cout << "\nCurrent Time is "<<t1;
const byte iv2[] = {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
CBC_Mode<DES>::Encryption encryption_DES_CBC(passPhrase, 8, iv2);
encryption_DES_CBC.ProcessString((byte*)ciphertext, (byte*)plaintext,
strlen(plaintext));
gettimeofday(¤t_time, &tzp);
t2 = timeval2double(¤t_time);
cout << "\nCurrent Time is "<<t2;
cout << "\nThe time difference is "<<t2-t1<<"\n";
cout << "\nThe cipher text is "<< ciphertext <<"\n";
CBC_Mode<DES>::Decryption decryption_DES_CBC;
decryption_DES_CBC.SetKeyWithIV(passPhrase, 8, iv2);//8x8bits = 64 bit key,
64bit IV
decryption_DES_CBC.ProcessString((byte*)detext, (byte*)ciphertext,
strlen(ciphertext));
cout << "\nThe decrypted text is "<< detext <<"\n";
return 0;
}
I use 8192 blocks plaintext in all. The code is:
struct timeval current_time;
struct timezone tzp;
double t1, t2, t3, t4;
char plaintext[65536] = "", ciphertext[65536]="", detext[65536] = "";
const byte passPhrase[] = {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
const byte iv2[] = {0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40};
int j=0;
AutoSeededRandomPool rng;
rng.GenerateBlock((byte*)plaintext, 65536);
.................................................
else if (command == "des")
{
// 65536=8192*8,ie,8192 blocks
gettimeofday(¤t_time, &tzp);
t1 = timeval2double(¤t_time);
CBC_Mode<DES>::Encryption encryption_DES_CBC(passPhrase, 8, iv2);
do{
encryption_DES_CBC.ProcessString((byte*)(ciphertext+j*64), (byte*)(plaintext+j*64),
64);
j++;
}while(j<1024);
gettimeofday(¤t_time, &tzp);
t2 = timeval2double(¤t_time);
cout << "\nThe encryption time difference is "<<t2-t1<<"\n";
CBC_Mode<DES>::Decryption decryption_DES_CBC;
decryption_DES_CBC.SetKeyWithIV(passPhrase, 8, iv2);//8x8bits = 64 bit key,
64bit IV
gettimeofday(¤t_time, &tzp);
t3 = timeval2double(¤t_time);
j = 0;
do{
decryption_DES_CBC.ProcessString((byte*)(detext+j*64), (byte*)(ciphertext+j*64),
64);
j++;
}while(j<1024);
gettimeofday(¤t_time, &tzp);
t4 = timeval2double(¤t_time);
cout << "\nThe decryption time difference is "<<t4-t3<<"\n";
return 0;
}
The test result is 0.015527 for encryption, and 0.016129 for decryption.
Substitution & Transposition.
EDESX[K, K1, K2](P) = EDES[K](P XOR K1) XOR K2
DDESX[K, K1, K2](C) = DDES[K](C XOR K3) XOR K2
If the user key length is 24 bytes, the first 8 bytes represent the key K used for the DES operation, and the two subsequent blocks of 8 bytes represent the "whitening" keys K1 and K2, in that order.
If the user key length is 16 bytes, the first 8 bytes represent the key K used for the DES operation, the second 8 bytes represent the whitening key K1, and K2 is derived from K and K1 as specified in the first reference below.
A block cipher developed by Ron Rivest at RSA Data Security, Inc.
The algorithm is designed to be easy to implement on 16-bit microprocessors.
A stream cipher licensed by RSA Data Security [RSADSI].
RC4 is vulnerable to related-key attacks, and therefore it should only be used with keys that are generated by a strong RNG, or by a source of bits that are sufficiently uncorrelated (such as the output of a hash function).
Integer rounds
[creation/read, default 12] - the number of
rounds to be performed (minimum 12, multiple of 2) The maximum key length is restricted to 2040 bits (see the RSA Labs FAQ entry for RC5); this is an incompatible change since SCAN 1.0.11.
Integer rounds
[creation/read, default 20] - the number of
rounds to be performed (minimum 8, multiple of 4)