1 /// \file
2 ///
3 /// This file is part of RakNet Copyright 2003 Jenkins Software LLC
4 ///
5 /// Raknet is available under the terms of the GPLv3 license, see /usr/local/share/licenses/raknet-3.9.2_10,1/GPLv3.
6 
7 
8 #include "DataBlockEncryptor.h"
9 #include "CheckSum.h"
10 #include "GetTime.h"
11 #include "Rand.h"
12 #include "RakAssert.h"
13 #include <string.h>
14 #include "Rijndael.h"
15 //#include "Types.h"
16 
DataBlockEncryptor()17 DataBlockEncryptor::DataBlockEncryptor()
18 {
19 	keySet = false;
20 }
21 
~DataBlockEncryptor()22 DataBlockEncryptor::~DataBlockEncryptor()
23 {}
24 
IsKeySet(void) const25 bool DataBlockEncryptor::IsKeySet( void ) const
26 {
27 	return keySet;
28 }
29 
SetKey(const unsigned char key[16])30 void DataBlockEncryptor::SetKey( const unsigned char key[ 16 ] )
31 {
32 	keySet = true;
33 	//secretKeyAES128.set_key( key );
34 	makeKey(&keyEncrypt, DIR_ENCRYPT, 16, (char*)key);
35 	makeKey(&keyDecrypt, DIR_DECRYPT, 16, (char*)key);
36 	cipherInit(&cipherInst, MODE_ECB, 0); // ECB is not secure except that I chain manually farther down.
37 }
38 
UnsetKey(void)39 void DataBlockEncryptor::UnsetKey( void )
40 {
41 	keySet = false;
42 }
43 
Encrypt(unsigned char * input,unsigned int inputLength,unsigned char * output,unsigned int * outputLength,RakNetRandom * rnr)44 void DataBlockEncryptor::Encrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength, RakNetRandom *rnr )
45 {
46 	unsigned index, byteIndex, lastBlock;
47 	unsigned int checkSum;
48 	unsigned char paddingBytes;
49 	unsigned char encodedPad;
50 	unsigned char randomChar;
51 	CheckSum checkSumCalculator;
52 
53 #ifdef _DEBUG
54 
55 	RakAssert( keySet );
56 #endif
57 
58 	RakAssert( input && inputLength );
59 
60 
61 	// randomChar will randomize the data so the same data sent twice will not look the same
62 	randomChar = (unsigned char) rnr->RandomMT();
63 
64 	// 16-(((x-1) % 16)+1)
65 
66 	// # of padding bytes is 16 -(((input_length + extra_data -1) % 16)+1)
67 	paddingBytes = (unsigned char) ( 16 - ( ( ( inputLength + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) - 1 ) % 16 ) + 1 ) );
68 
69 	// Randomize the pad size variable
70 	encodedPad = (unsigned char) rnr->RandomMT();
71 	encodedPad <<= 4;
72 	encodedPad |= paddingBytes;
73 
74 	*outputLength = inputLength + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) + paddingBytes;
75 
76 	// Write the data first, in case we are overwriting ourselves
77 
78 	if ( input == output )
79 		memmove( output + sizeof( checkSum ) + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes, input, inputLength );
80 	else
81 		memcpy( output + sizeof( checkSum ) + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes, input, inputLength );
82 
83 	// Write the random char
84 	memcpy( output + sizeof( checkSum ), ( char* ) & randomChar, sizeof( randomChar ) );
85 
86 	// Write the pad size variable
87 	memcpy( output + sizeof( checkSum ) + sizeof( randomChar ), ( char* ) & encodedPad, sizeof( encodedPad ) );
88 
89 	// Write the padding
90 	for ( index = 0; index < paddingBytes; index++ )
91 		*( output + sizeof( checkSum ) + sizeof( randomChar ) + sizeof( encodedPad ) + index ) = (unsigned char) rnr->RandomMT();
92 
93 	// Calculate the checksum on the data
94 	checkSumCalculator.Add( output + sizeof( checkSum ), inputLength + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes );
95 
96 	checkSum = checkSumCalculator.Get();
97 
98 	// Write checksum
99 #ifdef HOST_ENDIAN_IS_BIG
100 	output[0] = checkSum&0xFF;
101 	output[1] = (checkSum>>8)&0xFF;
102 	output[2] = (checkSum>>16)&0xFF;
103 	output[3] = (checkSum>>24)&0xFF;
104 #else
105 	memcpy( output, ( char* ) & checkSum, sizeof( checkSum ) );
106 #endif
107 
108 	// AES on the first block
109 //	secretKeyAES128.encrypt16( output );
110 	blockEncrypt(&cipherInst, &keyEncrypt, output, 16, output);
111 
112 	lastBlock = 0;
113 
114 	// Now do AES on every other block from back to front
115 	for ( index = *outputLength - 16; index >= 16; index -= 16 )
116 	{
117 		for ( byteIndex = 0; byteIndex < 16; byteIndex++ )
118 			output[ index + byteIndex ] ^= output[ lastBlock + byteIndex ];
119 
120 		//secretKeyAES128.encrypt16( output + index );
121 		blockEncrypt(&cipherInst, &keyEncrypt, output+index, 16, output+index);
122 
123 		lastBlock = index;
124 	}
125 }
126 
Decrypt(unsigned char * input,unsigned int inputLength,unsigned char * output,unsigned int * outputLength)127 bool DataBlockEncryptor::Decrypt( unsigned char *input, unsigned int inputLength, unsigned char *output, unsigned int *outputLength )
128 {
129 	unsigned index, byteIndex;
130 	unsigned int checkSum;
131 	unsigned char paddingBytes;
132 	unsigned char encodedPad;
133 	unsigned char randomChar;
134 	CheckSum checkSumCalculator;
135 #ifdef _DEBUG
136 
137 	RakAssert( keySet );
138 #endif
139 
140 	if ( input == 0 || inputLength < 16 || ( inputLength % 16 ) != 0 )
141 	{
142 		return false;
143 	}
144 
145 	// Unchain in reverse order
146 	for ( index = 16; index <= inputLength - 16;index += 16 )
147 	{
148 	//	secretKeyAES128.decrypt16( input + index );
149 		blockDecrypt(&cipherInst, &keyDecrypt, input + index, 16, output + index);
150 
151 		for ( byteIndex = 0; byteIndex < 16; byteIndex++ )
152 		{
153 			if ( index + 16 == ( unsigned ) inputLength )
154 				output[ index + byteIndex ] ^= input[ byteIndex ];
155 			else
156 				output[ index + byteIndex ] ^= input[ index + 16 + byteIndex ];
157 		}
158 
159 	//	lastBlock = index;
160 	};
161 
162 	// Decrypt the first block
163 	//secretKeyAES128.decrypt16( input );
164 	blockDecrypt(&cipherInst, &keyDecrypt, input, 16, output);
165 
166 	// Read checksum
167 #ifdef HOST_ENDIAN_IS_BIG
168 	checkSum = (unsigned int)output[0] | (unsigned int)(output[1]<<8) |
169 		(unsigned int)(output[2]<<16)|(unsigned int)(output[3]<<24);
170 #else
171 	memcpy( ( char* ) & checkSum, output, sizeof( checkSum ) );
172 #endif
173 
174 	// Read the pad size variable
175 	memcpy( ( char* ) & encodedPad, output + sizeof( randomChar ) + sizeof( checkSum ), sizeof( encodedPad ) );
176 
177 	// Ignore the high 4 bytes
178 	paddingBytes = encodedPad & 0x0F;
179 
180 
181 	// Get the data length
182 	*outputLength = inputLength - sizeof( randomChar ) - sizeof( checkSum ) - sizeof( encodedPad ) - paddingBytes;
183 
184 	// Calculate the checksum on the data.
185 	checkSumCalculator.Add( output + sizeof( checkSum ), *outputLength + sizeof( randomChar ) + sizeof( encodedPad ) + paddingBytes );
186 
187 	if ( checkSum != checkSumCalculator.Get() )
188 		return false;
189 
190 	// Read the data
191 	//if ( input == output )
192 		memmove( output, output + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) + paddingBytes, *outputLength );
193 	//else
194 	//	memcpy( output, input + sizeof( randomChar ) + sizeof( checkSum ) + sizeof( encodedPad ) + paddingBytes, *outputLength );
195 
196 	return true;
197 }
198