source: trunk/CrypPlugins/Libs/NativeCryptography/NativeCryptography.cpp @ 2698

Last change on this file since 2698 was 2698, checked in by Sven Rech, 11 years ago

hopefully faster entropy calculation in NativeCryptography by using float instead of double (float is precise enough)

File size: 8.1 KB
Line 
1// This is the main DLL file.
2
3#include "NativeCryptography.h"
4#include <stdlib.h>
5#include <string.h>
6
7namespace NativeCryptography {
8
9        /* Fast way to xor an AES block */
10        void Crypto::xorBlockAES(int *t1, int *t2)
11        {
12                t1[0] ^= t2[0];
13                t1[1] ^= t2[1];
14                t1[2] ^= t2[2];
15                t1[3] ^= t2[3];
16        }
17
18        /* Fast way to xor an DES block */
19        void Crypto::xorBlockDES(int *t1, int *t2)
20        {
21                t1[0] ^= t2[0];
22                t1[1] ^= t2[1];
23        }
24
25        void Crypto::encrypt(unsigned char* in, unsigned char* out, const cryptMethod method, AES_KEY* aeskey, DES_key_schedule* deskey)
26        {
27                if (method == cryptMethod::methodAES)
28                        AES_encrypt(in, out, aeskey);
29                else
30                        DES_ecb_encrypt((const_DES_cblock*)in, (const_DES_cblock*)out, deskey, DES_ENCRYPT);
31        }
32
33        void Crypto::decrypt(unsigned char* in, unsigned char* out, const cryptMethod method, AES_KEY* aeskey, DES_key_schedule* deskey)
34        {
35                if (method == cryptMethod::methodAES)
36                        AES_decrypt(in, out, aeskey);
37                else
38                        DES_ecb_encrypt((const_DES_cblock*)in, (const_DES_cblock*)out, deskey, DES_DECRYPT);
39        }
40
41
42        void Crypto::xorblock(unsigned char* t1, unsigned char* t2, const cryptMethod method) {
43                if (method == cryptMethod::methodAES)
44                        xorBlockAES((int*)t1, (int*)t2);
45                else
46                        xorBlockDES((int*)t1, (int*)t2); 
47        }
48
49        array<unsigned char>^ Crypto::decryptAESorDES(array<unsigned char>^ Input, array<unsigned char>^ Key, array<unsigned char>^ IV, const int bits, const int length, const int mode, const int blockSize, const cryptMethod method)
50        {
51                int numBlocks = length / blockSize;
52                if (length % blockSize != 0)
53                        numBlocks++;
54
55                bool noIV = false;
56
57                if (IV == nullptr)
58                {
59                        noIV = true;
60                        if (blockSize == 8)
61                                IV = zeroIV8;
62                        else if (blockSize == 16)
63                                IV = zeroIV16;
64                        else
65                                return nullptr;
66                }
67
68                pin_ptr<unsigned char> input = &Input[0];
69                pin_ptr<unsigned char> key = &Key[0];
70                pin_ptr<unsigned char> iv = &IV[0];
71
72                array<unsigned char>^ output = gcnew array<unsigned char>(length);
73                pin_ptr<unsigned char> outp = &output[0];
74
75                AES_KEY aeskey;
76                DES_key_schedule deskey;
77                if (mode == 2)  //CFB
78                {                       
79                        unsigned char block[16];        //16 is enough for AES and DES
80                        unsigned char shiftregister[16];
81                        //works only for little endian architectures:
82                        if (blockSize == 8)
83                        {
84                                *((unsigned int*)shiftregister) = *((unsigned int*)&iv[1]);
85                                *((unsigned int*)&shiftregister[4]) = (*((unsigned int*)&iv[4]) >> 8) | ((unsigned int)(input[0]) << 24);
86                        }
87                        else if (blockSize == 16)
88                        {
89                                *((unsigned int*)shiftregister) = *((unsigned int*)&iv[1]);
90                                *((unsigned int*)&shiftregister[4]) = (*((unsigned int*)&iv[4]) >> 8) | ((unsigned int)iv[8] << 24);
91                                *((unsigned int*)&shiftregister[8]) = (*((unsigned int*)&iv[8]) >> 8) | ((unsigned int)iv[12] << 24);
92                                *((unsigned int*)&shiftregister[12]) = (*((unsigned int*)&iv[12]) >> 8) | ((unsigned int)input[0] << 24);
93                        }
94                        else
95                                return nullptr;
96                       
97                        if (method == cryptMethod::methodAES)
98                                AES_set_encrypt_key(key, bits, &aeskey);
99                        else
100                                DES_set_key_unchecked((const_DES_cblock*)key, &deskey);
101
102                        encrypt(iv, block, method, &aeskey, &deskey);
103                        unsigned char leftmost = block[0];
104                        outp[0] = leftmost ^ input[0];
105
106                        for (int i = 1; i < length; i++)
107                        {
108                                encrypt(shiftregister, block, method, &aeskey, &deskey);
109                                leftmost = block[0];
110                                outp[i] = leftmost ^ input[i];
111                               
112                                //shift input[i] in register:
113                                if (blockSize == 8)
114                                {
115                                        *((unsigned int*)shiftregister) = *((unsigned int*)&shiftregister[1]);
116                                        *((unsigned int*)&shiftregister[4]) = (*((unsigned int*)&shiftregister[4]) >> 8) | ((unsigned int)input[i] << 24);
117                                }
118                                else if (blockSize == 16)
119                                {
120                                        *((unsigned int*)shiftregister) = *((unsigned int*)&shiftregister[1]);
121                                        *((unsigned int*)&shiftregister[4]) = (*((unsigned int*)&shiftregister[4]) >> 8) | ((unsigned int)shiftregister[8] << 24);
122                                        *((unsigned int*)&shiftregister[8]) = (*((unsigned int*)&shiftregister[8]) >> 8) | ((unsigned int)shiftregister[12] << 24);
123                                        *((unsigned int*)&shiftregister[12]) = (*((unsigned int*)&shiftregister[12]) >> 8) | ((unsigned int)input[i] << 24);
124                                }
125                        }
126                }
127                else    //CBC or ECB
128                {
129                        if (method == cryptMethod::methodAES)
130                                AES_set_decrypt_key(key, bits, &aeskey);
131                        else
132                                DES_set_key_unchecked((const_DES_cblock*)key, &deskey);
133
134                        decrypt(input, outp, method, &aeskey, &deskey);                         
135                        if (mode == 1 && !noIV)         //CBC
136                                xorblock(outp, iv, method);     
137                        for (int c = 1; c < numBlocks; c++)
138                        {
139                                decrypt(input+c*blockSize, outp+c*blockSize, method, &aeskey, &deskey);
140                                if (mode == 1)          //CBC
141                                        xorblock(outp+c*blockSize, input+(c-1)*blockSize, method);                             
142                        }
143                }
144
145                return output;
146        }
147
148        array<unsigned char>^ Crypto::encryptAESorDES(array<unsigned char>^ Input, array<unsigned char>^ Key, array<unsigned char>^ IV, const int bits, const int length, const int mode, const int blockSize, const cryptMethod method)
149        {
150                int numBlocks = length / blockSize;             
151                if (length % blockSize != 0)
152                        throw gcnew System::Exception("Input must be multiple of " + blockSize);
153
154                bool noIV = false;
155
156                if (IV == nullptr)
157                {
158                        noIV = true;
159                        if (blockSize == 8)
160                                IV = zeroIV8;
161                        else if (blockSize == 16)
162                                IV = zeroIV16;
163                        else
164                                return nullptr;
165                }
166
167                pin_ptr<unsigned char> input = &Input[0];
168                pin_ptr<unsigned char> key = &Key[0];
169                pin_ptr<unsigned char> iv = &IV[0];
170
171                array<unsigned char>^ output = gcnew array<unsigned char>(length);
172                pin_ptr<unsigned char> outp = &output[0];
173
174                array<unsigned char>^ block = nullptr;
175                pin_ptr<unsigned char> blockp = nullptr;
176                if (mode == 1)
177                {
178                        block = gcnew array<unsigned char>(blockSize);
179                        blockp = &block[0];
180                }               
181
182                AES_KEY aeskey;
183                DES_key_schedule deskey;
184                if (mode == 2)  //CFB
185                {                       
186                        throw gcnew System::Exception("Encrypting CFB not supported (yet?)");
187                }
188                else    //CBC or ECB
189                {
190                        if (method == cryptMethod::methodAES)
191                                AES_set_encrypt_key(key, bits, &aeskey);
192                        else
193                                DES_set_key_unchecked((const_DES_cblock*)key, &deskey);
194                                               
195                        if (mode == 1 && !noIV)         //CBC
196                        {                               
197                                for (int d = 0; d < blockSize; d++)
198                                        block[d] = input[d];
199                                xorblock(blockp, iv, method);
200                                encrypt(blockp, outp, method, &aeskey, &deskey);
201                        }
202                        else
203                                encrypt(input, outp, method, &aeskey, &deskey);
204
205                        for (int c = 1; c < numBlocks; c++)
206                        {
207                                if (mode == 1)          //CBC
208                                {
209                                        for (int d = 0; d < blockSize; d++)
210                                                block[d] = input[c*blockSize+d];
211                                        xorblock(blockp, outp+(c-1)*blockSize, method);
212                                        encrypt(blockp, outp+c*blockSize, method, &aeskey, &deskey);
213                                }
214                                else
215                                        encrypt(input+c*blockSize, outp+c*blockSize, method, &aeskey, &deskey);
216                        }
217                }
218
219                return output;
220        }
221
222        float *xlogx = 0;
223
224        void prepareEntropy(int size)
225    {
226                if (xlogx != 0)
227                        free(xlogx);
228        xlogx = (float*)malloc((size + 1)*sizeof(float));
229        //precomputations for fast entropy calculation 
230        xlogx[0] = 0.0;
231        for (int i = 1; i <= size; i++)
232                        xlogx[i] = -1.0 * i * Math::Log(i / (float)size) / Math::Log(2.0);
233    }
234
235
236        double Crypto::calculateEntropy(array<unsigned char>^ text, int bytesToUse)
237        {
238        if (bytesToUse > text->Length)
239            bytesToUse = text->Length;
240                static int lastUsedSize = -1;
241
242        if (lastUsedSize != bytesToUse)
243        {
244            try
245            {
246                prepareMutex->WaitOne();
247                if (lastUsedSize != bytesToUse)
248                {
249                    prepareEntropy(bytesToUse);
250                    lastUsedSize = bytesToUse;
251                }
252            }
253            finally
254            {
255                prepareMutex->ReleaseMutex();
256            }
257        }
258
259                pin_ptr<unsigned char> t = &text[0];
260
261        int n[256];
262                memset(n,0,sizeof(n));
263        //count all ASCII symbols
264        for (int counter = 0; counter < bytesToUse; counter++)
265        {
266            n[t[counter]]++;
267        }
268
269        float entropy = 0;
270        //calculate probabilities and sum entropy
271        for (short i = 0; i < 256; i++)                 
272            entropy += xlogx[n[i]];
273
274        return entropy / (double)bytesToUse;
275        }
276
277}
Note: See TracBrowser for help on using the repository browser.