Initial revision
[silc.git] / lib / silccrypt / rc6.c
1 /* Modified for SILC. -Pekka */
2
3 /* This is an independent implementation of the encryption algorithm:   */
4 /*                                                                      */
5 /*         RC6 by Ron Rivest and RSA Labs                               */
6 /*                                                                      */
7 /* which is a candidate algorithm in the Advanced Encryption Standard   */
8 /* programme of the US National Institute of Standards and Technology.  */
9 /*                                                                      */
10 /* Copyright in this implementation is held by Dr B R Gladman but I     */
11 /* hereby give permission for its free direct or derivative use subject */
12 /* to acknowledgment of its origin and compliance with any conditions   */
13 /* that the originators of the algorithm place on its exploitation.     */
14 /*                                                                      */
15 /* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */
16
17 /* Timing data for RC6 (rc6.c)
18
19 128 bit key:
20 Key Setup:    1632 cycles
21 Encrypt:       270 cycles =    94.8 mbits/sec
22 Decrypt:       226 cycles =   113.3 mbits/sec
23 Mean:          248 cycles =   103.2 mbits/sec
24
25 192 bit key:
26 Key Setup:    1885 cycles
27 Encrypt:       267 cycles =    95.9 mbits/sec
28 Decrypt:       235 cycles =   108.9 mbits/sec
29 Mean:          251 cycles =   102.0 mbits/sec
30
31 256 bit key:
32 Key Setup:    1877 cycles
33 Encrypt:       270 cycles =    94.8 mbits/sec
34 Decrypt:       227 cycles =   112.8 mbits/sec
35 Mean:          249 cycles =   103.0 mbits/sec
36
37 */
38
39 #include "silcincludes.h"
40 #include "rc6.h"
41
42 /* 
43  * SILC Crypto API for RC6
44  */
45
46 /* Sets the key for the cipher. */
47
48 SILC_CIPHER_API_SET_KEY(rc6)
49 {
50   rc6_set_key((RC6Context *)context, (unsigned int *)key, keylen);
51   return 1;
52 }
53
54 /* Sets the string as a new key for the cipher. The string is first
55    hashed and then used as a new key. */
56
57 SILC_CIPHER_API_SET_KEY_WITH_STRING(rc6)
58 {
59   return 1;
60 }
61
62 /* Encrypts with the cipher in CBC mode. Source and destination buffers
63    maybe one and same. */
64
65 SILC_CIPHER_API_ENCRYPT_CBC(rc6)
66 {
67   unsigned int *in, *out, *tiv;
68   unsigned int tmp[4];
69   int i;
70
71   in = (unsigned int *)src;
72   out = (unsigned int *)dst;
73   tiv = (unsigned int *)iv;
74
75   tmp[0] = in[0] ^ tiv[0];
76   tmp[1] = in[1] ^ tiv[1];
77   tmp[2] = in[2] ^ tiv[2];
78   tmp[3] = in[3] ^ tiv[3];
79   rc6_encrypt((RC6Context *)context, tmp, out);
80   in += 4;
81   out += 4;
82
83   for (i = 16; i < len; i += 16) {
84     tmp[0] = in[0] ^ out[0 - 4];
85     tmp[1] = in[1] ^ out[1 - 4];
86     tmp[2] = in[2] ^ out[2 - 4];
87     tmp[3] = in[3] ^ out[3 - 4];
88     rc6_encrypt((RC6Context *)context, tmp, out);
89     in += 4;
90     out += 4;
91   }
92
93   tiv[0] = out[0 - 4];
94   tiv[1] = out[1 - 4];
95   tiv[2] = out[2 - 4];
96   tiv[3] = out[3 - 4];
97
98   return TRUE;
99 }
100
101 /* Decrypts with the cipher in CBC mode. Source and destination buffers
102    maybe one and same. */
103
104 SILC_CIPHER_API_DECRYPT_CBC(rc6)
105 {
106   unsigned int *in, *out, *tiv;
107   unsigned int tmp[4], tmp2[4];
108   int i;
109
110   in = (unsigned int *)src;
111   out = (unsigned int *)dst;
112   tiv = (unsigned int *)iv;
113
114   tmp[0] = in[0];
115   tmp[1] = in[1];
116   tmp[2] = in[2];
117   tmp[3] = in[3];
118   rc6_decrypt((RC6Context *)context, in, out);
119   out[0] ^= tiv[0];
120   out[1] ^= tiv[1];
121   out[2] ^= tiv[2];
122   out[3] ^= tiv[3];
123   in += 4;
124   out += 4;
125
126   for (i = 16; i < len; i += 16) {
127     tmp2[0] = tmp[0];
128     tmp2[1] = tmp[1];
129     tmp2[2] = tmp[2];
130     tmp2[3] = tmp[3];
131     tmp[0] = in[0];
132     tmp[1] = in[1];
133     tmp[2] = in[2];
134     tmp[3] = in[3];
135     rc6_decrypt((RC6Context *)context, in, out);
136     out[0] ^= tmp2[0];
137     out[1] ^= tmp2[1];
138     out[2] ^= tmp2[2];
139     out[3] ^= tmp2[3];
140     in += 4;
141     out += 4;
142   }
143
144   tiv[0] = tmp[0];
145   tiv[1] = tmp[1];
146   tiv[2] = tmp[2];
147   tiv[3] = tmp[3];
148
149   return TRUE;
150 }
151
152 /* Returns the size of the cipher context. */
153
154 SILC_CIPHER_API_CONTEXT_LEN(rc6)
155 {
156   return sizeof(RC6Context);
157 }
158
159
160 #define f_rnd(i,a,b,c,d)                    \
161         u = rotl(d * (d + d + 1), 5);       \
162         t = rotl(b * (b + b + 1), 5);       \
163         a = rotl(a ^ t, u) + l_key[i];      \
164         c = rotl(c ^ u, t) + l_key[i + 1]
165
166 #define i_rnd(i,a,b,c,d)                    \
167         u = rotl(d * (d + d + 1), 5);       \
168         t = rotl(b * (b + b + 1), 5);       \
169         c = rotr(c - l_key[i + 1], t) ^ u;  \
170         a = rotr(a - l_key[i], u) ^ t
171
172 /* initialise the key schedule from the user supplied key   */
173
174 u4byte *rc6_set_key(RC6Context *ctx, 
175                     const u4byte in_key[], const u4byte key_len)
176 {   
177     u4byte  i, j, k, a, b, l[8], t;
178     u4byte *l_key = ctx->l_key;
179
180     l_key[0] = 0xb7e15163;
181
182     for(k = 1; k < 44; ++k)
183         
184         l_key[k] = l_key[k - 1] + 0x9e3779b9;
185
186     for(k = 0; k < key_len / 32; ++k)
187
188         l[k] = in_key[k];
189
190     t = (key_len / 32) - 1; // t = (key_len / 32);
191
192     a = b = i = j = 0;
193
194     for(k = 0; k < 132; ++k)
195     {   a = rotl(l_key[i] + a + b, 3); b += a;
196         b = rotl(l[j] + b, b);
197         l_key[i] = a; l[j] = b;
198         i = (i == 43 ? 0 : i + 1); // i = (i + 1) % 44;  
199         j = (j == t ? 0 : j + 1);  // j = (j + 1) % t;
200     }
201
202     return l_key;
203 };
204
205 /* encrypt a block of text  */
206
207 void rc6_encrypt(RC6Context *ctx,
208                  const u4byte in_blk[4], u4byte out_blk[4])
209 {   
210     u4byte  a,b,c,d,t,u;
211     u4byte *l_key = ctx->l_key;
212
213     a = in_blk[0]; b = in_blk[1] + l_key[0];
214     c = in_blk[2]; d = in_blk[3] + l_key[1];
215
216     f_rnd( 2,a,b,c,d); f_rnd( 4,b,c,d,a);
217     f_rnd( 6,c,d,a,b); f_rnd( 8,d,a,b,c);
218     f_rnd(10,a,b,c,d); f_rnd(12,b,c,d,a);
219     f_rnd(14,c,d,a,b); f_rnd(16,d,a,b,c);
220     f_rnd(18,a,b,c,d); f_rnd(20,b,c,d,a);
221     f_rnd(22,c,d,a,b); f_rnd(24,d,a,b,c);
222     f_rnd(26,a,b,c,d); f_rnd(28,b,c,d,a);
223     f_rnd(30,c,d,a,b); f_rnd(32,d,a,b,c);
224     f_rnd(34,a,b,c,d); f_rnd(36,b,c,d,a);
225     f_rnd(38,c,d,a,b); f_rnd(40,d,a,b,c);
226
227     out_blk[0] = a + l_key[42]; out_blk[1] = b;
228     out_blk[2] = c + l_key[43]; out_blk[3] = d;
229 };
230
231 /* decrypt a block of text  */
232
233 void rc6_decrypt(RC6Context *ctx,
234                  const u4byte in_blk[4], u4byte out_blk[4])
235 {   
236     u4byte  a,b,c,d,t,u;
237     u4byte *l_key = ctx->l_key;
238
239     d = in_blk[3]; c = in_blk[2] - l_key[43]; 
240     b = in_blk[1]; a = in_blk[0] - l_key[42];
241
242     i_rnd(40,d,a,b,c); i_rnd(38,c,d,a,b);
243     i_rnd(36,b,c,d,a); i_rnd(34,a,b,c,d);
244     i_rnd(32,d,a,b,c); i_rnd(30,c,d,a,b);
245     i_rnd(28,b,c,d,a); i_rnd(26,a,b,c,d);
246     i_rnd(24,d,a,b,c); i_rnd(22,c,d,a,b);
247     i_rnd(20,b,c,d,a); i_rnd(18,a,b,c,d);
248     i_rnd(16,d,a,b,c); i_rnd(14,c,d,a,b);
249     i_rnd(12,b,c,d,a); i_rnd(10,a,b,c,d);
250     i_rnd( 8,d,a,b,c); i_rnd( 6,c,d,a,b);
251     i_rnd( 4,b,c,d,a); i_rnd( 2,a,b,c,d);
252
253     out_blk[3] = d - l_key[1]; out_blk[2] = c; 
254     out_blk[1] = b - l_key[0]; out_blk[0] = a; 
255 };