1 /*
2    Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; see the file COPYING. If not, write to the
15    Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
16    MA  02110-1301  USA.
17 */
18 
19 /* based on Wei Dai's arc4.cpp from CryptoPP */
20 
21 #include "runtime.hpp"
22 #include "arc4.hpp"
23 
24 
25 #if defined(TAOCRYPT_X86ASM_AVAILABLE) && defined(TAO_ASM)
26     #define DO_ARC4_ASM
27 #endif
28 
29 
30 namespace TaoCrypt {
31 
SetKey(const byte * key,word32 length)32 void ARC4::SetKey(const byte* key, word32 length)
33 {
34     x_ = 1;
35     y_ = 0;
36 
37     word32 i;
38 
39     for (i = 0; i < STATE_SIZE; i++)
40         state_[i] = i;
41 
42     word32 keyIndex = 0, stateIndex = 0;
43 
44     for (i = 0; i < STATE_SIZE; i++) {
45         word32 a = state_[i];
46         stateIndex += key[keyIndex] + a;
47         stateIndex &= 0xFF;
48         state_[i] = state_[stateIndex];
49         state_[stateIndex] = a;
50 
51         if (++keyIndex >= length)
52             keyIndex = 0;
53     }
54 }
55 
56 
57 // local
58 namespace {
59 
MakeByte(word32 & x,word32 & y,byte * s)60 inline unsigned int MakeByte(word32& x, word32& y, byte* s)
61 {
62     word32 a = s[x];
63     y = (y+a) & 0xff;
64 
65     word32 b = s[y];
66     s[x] = b;
67     s[y] = a;
68     x = (x+1) & 0xff;
69 
70     return s[(a+b) & 0xff];
71 }
72 
73 } // namespace
74 
75 
76 
Process(byte * out,const byte * in,word32 length)77 void ARC4::Process(byte* out, const byte* in, word32 length)
78 {
79     if (length == 0) return;
80 
81 #ifdef DO_ARC4_ASM
82     if (isMMX) {
83         AsmProcess(out, in, length);
84         return;
85     }
86 #endif
87 
88     byte *const s = state_;
89     word32 x = x_;
90     word32 y = y_;
91 
92     if (in == out)
93         while (length--)
94             *out++ ^= MakeByte(x, y, s);
95     else
96         while(length--)
97             *out++ = *in++ ^ MakeByte(x, y, s);
98     x_ = x;
99     y_ = y;
100 }
101 
102 
103 
104 #ifdef DO_ARC4_ASM
105 
106 #ifdef _MSC_VER
107     __declspec(naked)
108 #else
109     __attribute__ ((noinline))
110 #endif
AsmProcess(byte * out,const byte * in,word32 length)111 void ARC4::AsmProcess(byte* out, const byte* in, word32 length)
112 {
113 #ifdef __GNUC__
114     #define AS1(x)    #x ";"
115     #define AS2(x, y) #x ", " #y ";"
116 
117     #define PROLOG()  \
118     __asm__ __volatile__ \
119     ( \
120         ".intel_syntax noprefix;" \
121         "push ebx;" \
122         "push ebp;" \
123         "mov ebp, eax;"
124     #define EPILOG()  \
125         "pop ebp;" \
126         "pop ebx;" \
127        	"emms;" \
128        	".att_syntax;" \
129             : \
130             : "c" (this), "D" (out), "S" (in), "a" (length) \
131             : "%edx", "memory", "cc" \
132     );
133 
134 #else
135     #define AS1(x)    __asm x
136     #define AS2(x, y) __asm x, y
137 
138     #define PROLOG() \
139         AS1(    push  ebp                       )   \
140         AS2(    mov   ebp, esp                  )   \
141         AS2(    movd  mm3, edi                  )   \
142         AS2(    movd  mm4, ebx                  )   \
143         AS2(    movd  mm5, esi                  )   \
144         AS2(    movd  mm6, ebp                  )   \
145         AS2(    mov   edi, DWORD PTR [ebp +  8] )   \
146         AS2(    mov   esi, DWORD PTR [ebp + 12] )   \
147         AS2(    mov   ebp, DWORD PTR [ebp + 16] )
148 
149     #define EPILOG() \
150         AS2(    movd  ebp, mm6                  )   \
151         AS2(    movd  esi, mm5                  )   \
152         AS2(    movd  ebx, mm4                  )   \
153         AS2(    movd  edi, mm3                  )   \
154         AS2(    mov   esp, ebp                  )   \
155         AS1(    pop   ebp                       )   \
156         AS1(    emms                            )   \
157         AS1(    ret 12                          )
158 
159 #endif
160 
161     PROLOG()
162 
163     AS2(    sub    esp, 4                   )   // make room
164 
165     AS2(    cmp    ebp, 0                   )
166     AS1(    jz     nothing                  )
167 
168     AS2(    mov    [esp], ebp               )   // length
169 
170     AS2(    movzx  edx, BYTE PTR [ecx + 1]  )   // y
171     AS2(    lea    ebp, [ecx + 2]           )   // state_
172     AS2(    movzx  ecx, BYTE PTR [ecx]      )   // x
173 
174     // setup loop
175     // a = s[x];
176     AS2(    movzx  eax, BYTE PTR [ebp + ecx]    )
177 
178 
179 #ifdef _MSC_VER
180     AS1( loopStart: )  // loopStart
181 #else
182     AS1( 0: )          // loopStart for some gas (need numeric for jump back
183 #endif
184 
185     // y = (y+a) & 0xff;
186     AS2(    add    edx, eax                     )
187     AS2(    and    edx, 255                     )
188 
189     // b = s[y];
190     AS2(    movzx  ebx, BYTE PTR [ebp + edx]    )
191 
192     // s[x] = b;
193     AS2(    mov    [ebp + ecx], bl              )
194 
195     // s[y] = a;
196     AS2(    mov    [ebp + edx], al              )
197 
198     // x = (x+1) & 0xff;
199     AS1(    inc    ecx                          )
200     AS2(    and    ecx, 255                     )
201 
202     //return s[(a+b) & 0xff];
203     AS2(    add    eax, ebx                     )
204     AS2(    and    eax, 255                     )
205 
206     AS2(    movzx  ebx, BYTE PTR [ebp + eax]    )
207 
208     // a = s[x];   for next round
209     AS2(    movzx  eax, BYTE PTR [ebp + ecx]    )
210 
211     // xOr w/ inByte
212     AS2(    xor    bl,  BYTE PTR [esi]          )
213     AS1(    inc    esi                          )
214 
215     // write to outByte
216     AS2(    mov    [edi], bl                    )
217     AS1(    inc    edi                          )
218 
219     AS1(    dec    DWORD PTR [esp]              )
220 #ifdef _MSC_VER
221     AS1(    jnz   loopStart )  // loopStart
222 #else
223     AS1(    jnz   0b )         // loopStart
224 #endif
225 
226 
227     // write back to x_ and y_
228     AS2(    mov    [ebp - 2], cl            )
229     AS2(    mov    [ebp - 1], dl            )
230 
231 
232 AS1( nothing:                           )
233 
234     // inline adjust
235     AS2(    add   esp, 4               )   // fix room on stack
236 
237     EPILOG()
238 }
239 
240 #endif // DO_ARC4_ASM
241 
242 
243 }  // namespace
244