source: trunk/NativeCryptography/NativeCryptography.cpp @ 1198

Last change on this file since 1198 was 1198, checked in by Sven Rech, 12 years ago

speed optimization for CFB

File size: 4.9 KB
Line 
1// This is the main DLL file.
2
3#include "NativeCryptography.h"
4
5namespace NativeCryptography {
6
7        /* Fast way to xor an AES block */
8        void Crypto::xorBlockAES(int *t1, int *t2)
9        {
10                t1[0] ^= t2[0];
11                t1[1] ^= t2[1];
12                t1[2] ^= t2[2];
13                t1[3] ^= t2[3];
14        }
15
16        /* Fast way to xor an DES block */
17        void Crypto::xorBlockDES(int *t1, int *t2)
18        {
19                t1[0] ^= t2[0];
20                t1[1] ^= t2[1];
21        }
22
23        void Crypto::encrypt(unsigned char* in, unsigned char* out, const cryptMethod method, AES_KEY* aeskey, DES_key_schedule* deskey)
24        {
25                if (method == cryptMethod::methodAES)
26                        AES_encrypt(in, out, aeskey);
27                else
28                        DES_ecb_encrypt((const_DES_cblock*)in, (const_DES_cblock*)out, deskey, DES_ENCRYPT);
29        }
30
31        void Crypto::decrypt(unsigned char* in, unsigned char* out, const cryptMethod method, AES_KEY* aeskey, DES_key_schedule* deskey)
32        {
33                if (method == cryptMethod::methodAES)
34                        AES_decrypt(in, out, aeskey);
35                else
36                        DES_ecb_encrypt((const_DES_cblock*)in, (const_DES_cblock*)out, deskey, DES_DECRYPT);
37        }
38
39
40        void Crypto::xorblock(unsigned char* t1, unsigned char* t2, const cryptMethod method) {
41                if (method == cryptMethod::methodAES)
42                        xorBlockAES((int*)t1, (int*)t2);
43                else
44                        xorBlockDES((int*)t1, (int*)t2); 
45        }
46
47        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)
48        {
49                static unsigned char lastIVencrypted[16];       //optimization
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                        if (IV != lastIV)
103                        {
104                                try{
105                                        lastivmutex->WaitOne();
106                                        if (IV != lastIV)
107                                        {
108                                                encrypt(iv, lastIVencrypted, method, &aeskey, &deskey);
109                                                lastIV = IV;
110                                        }
111                                } finally
112                                {
113                                        lastivmutex->ReleaseMutex();
114                                }
115                        }
116                       
117                        unsigned char leftmost = lastIVencrypted[0];
118                        outp[0] = leftmost ^ input[0];
119
120                        for (int i = 1; i < length; i++)
121                        {
122                                encrypt(shiftregister, block, method, &aeskey, &deskey);
123                                leftmost = block[0];
124                                outp[i] = leftmost ^ input[i];
125                               
126                                //shift input[i] in register:
127                                if (blockSize == 8)
128                                {
129                                        *((unsigned int*)shiftregister) = *((unsigned int*)&shiftregister[1]);
130                                        *((unsigned int*)&shiftregister[4]) = (*((unsigned int*)&shiftregister[4]) >> 8) | ((unsigned int)input[i] << 24);
131                                }
132                                else if (blockSize == 16)
133                                {
134                                        *((unsigned int*)shiftregister) = *((unsigned int*)&shiftregister[1]);
135                                        *((unsigned int*)&shiftregister[4]) = (*((unsigned int*)&shiftregister[4]) >> 8) | ((unsigned int)shiftregister[8] << 24);
136                                        *((unsigned int*)&shiftregister[8]) = (*((unsigned int*)&shiftregister[8]) >> 8) | ((unsigned int)shiftregister[12] << 24);
137                                        *((unsigned int*)&shiftregister[12]) = (*((unsigned int*)&shiftregister[12]) >> 8) | ((unsigned int)input[i] << 24);
138                                }
139                        }
140                }
141                else    //CBC or ECB
142                {
143                        if (method == cryptMethod::methodAES)
144                                AES_set_decrypt_key(key, bits, &aeskey);
145                        else
146                                DES_set_key_unchecked((const_DES_cblock*)key, &deskey);
147
148                        decrypt(input, outp, method, &aeskey, &deskey);                         
149                        if (mode == 1 && !noIV)         //CBC
150                                xorblock(outp, iv, method);     
151                        for (int c = 1; c < numBlocks; c++)
152                        {
153                                decrypt(input+c*blockSize, outp+c*blockSize, method, &aeskey, &deskey);
154                                if (mode == 1)          //CBC
155                                        xorblock(outp+c*blockSize, input+(c-1)*blockSize, method);                             
156                        }
157                }
158
159                return output;
160        }
161
162}
Note: See TracBrowser for help on using the repository browser.