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