68dcb3c02a3d1ca9c3c0456325a42d7bd172e45c
[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   uint32 k[8];
51
52   SILC_GET_WORD_KEY(key, k, keylen);
53   rc6_set_key((RC6Context *)context, k, keylen);
54
55   return TRUE;
56 }
57
58 /* Sets the string as a new key for the cipher. The string is first
59    hashed and then used as a new key. */
60
61 SILC_CIPHER_API_SET_KEY_WITH_STRING(rc6)
62 {
63   return FALSE;
64 }
65
66 /* Encrypts with the cipher in CBC mode. Source and destination buffers
67    maybe one and same. */
68
69 SILC_CIPHER_API_ENCRYPT_CBC(rc6)
70 {
71   uint32 tiv[4];
72   int i;
73
74   SILC_CBC_GET_IV(tiv, iv);
75
76   SILC_CBC_ENC_PRE(tiv, src);
77   rc6_encrypt((RC6Context *)context, tiv, tiv);
78   SILC_CBC_ENC_POST(tiv, dst, src);
79
80   for (i = 16; i < len; i += 16) {
81     SILC_CBC_ENC_PRE(tiv, src);
82     rc6_encrypt((RC6Context *)context, tiv, tiv);
83     SILC_CBC_ENC_POST(tiv, dst, src);
84   }
85
86   SILC_CBC_PUT_IV(tiv, iv);
87
88   return TRUE;
89 }
90
91 /* Decrypts with the cipher in CBC mode. Source and destination buffers
92    maybe one and same. */
93
94 SILC_CIPHER_API_DECRYPT_CBC(rc6)
95 {
96   uint32 tmp[4], tmp2[4], tiv[4];
97   int i;
98
99   SILC_CBC_GET_IV(tiv, iv);
100
101   SILC_CBC_DEC_PRE(tmp, src);
102   rc6_decrypt((RC6Context *)context, tmp, tmp2);
103   SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
104
105   for (i = 16; i < len; i += 16) {
106     SILC_CBC_DEC_PRE(tmp, src);
107     rc6_decrypt((RC6Context *)context, tmp, tmp2);
108     SILC_CBC_DEC_POST(tmp2, dst, src, tmp, tiv);
109   }
110   
111   SILC_CBC_PUT_IV(tiv, iv);
112
113   return TRUE;
114 }
115
116 /* Returns the size of the cipher context. */
117
118 SILC_CIPHER_API_CONTEXT_LEN(rc6)
119 {
120   return sizeof(RC6Context);
121 }
122
123
124 #define f_rnd(i,a,b,c,d)                    \
125         u = rotl(d * (d + d + 1), 5);       \
126         t = rotl(b * (b + b + 1), 5);       \
127         a = rotl(a ^ t, u) + l_key[i];      \
128         c = rotl(c ^ u, t) + l_key[i + 1]
129
130 #define i_rnd(i,a,b,c,d)                    \
131         u = rotl(d * (d + d + 1), 5);       \
132         t = rotl(b * (b + b + 1), 5);       \
133         c = rotr(c - l_key[i + 1], t) ^ u;  \
134         a = rotr(a - l_key[i], u) ^ t
135
136 /* initialise the key schedule from the user supplied key   */
137
138 u4byte *rc6_set_key(RC6Context *ctx, 
139                     const u4byte in_key[], const u4byte key_len)
140 {   
141     u4byte  i, j, k, a, b, l[8], t;
142     u4byte *l_key = ctx->l_key;
143
144     l_key[0] = 0xb7e15163;
145
146     for(k = 1; k < 44; ++k)
147         
148         l_key[k] = l_key[k - 1] + 0x9e3779b9;
149
150     for(k = 0; k < key_len / 32; ++k)
151
152         l[k] = in_key[k];
153
154     t = (key_len / 32) - 1; /* t = (key_len / 32); */
155
156     a = b = i = j = 0;
157
158     for(k = 0; k < 132; ++k)
159     {   a = rotl(l_key[i] + a + b, 3); b += a;
160         b = rotl(l[j] + b, b);
161         l_key[i] = a; l[j] = b;
162         i = (i == 43 ? 0 : i + 1); /* i = (i + 1) % 44; */
163         j = (j == t ? 0 : j + 1);  /* j = (j + 1) % t; */
164     }
165
166     return l_key;
167 };
168
169 /* encrypt a block of text  */
170
171 void rc6_encrypt(RC6Context *ctx,
172                  const u4byte in_blk[4], u4byte out_blk[4])
173 {   
174     u4byte  a,b,c,d,t,u;
175     u4byte *l_key = ctx->l_key;
176
177     a = in_blk[0]; b = in_blk[1] + l_key[0];
178     c = in_blk[2]; d = in_blk[3] + l_key[1];
179
180     f_rnd( 2,a,b,c,d); f_rnd( 4,b,c,d,a);
181     f_rnd( 6,c,d,a,b); f_rnd( 8,d,a,b,c);
182     f_rnd(10,a,b,c,d); f_rnd(12,b,c,d,a);
183     f_rnd(14,c,d,a,b); f_rnd(16,d,a,b,c);
184     f_rnd(18,a,b,c,d); f_rnd(20,b,c,d,a);
185     f_rnd(22,c,d,a,b); f_rnd(24,d,a,b,c);
186     f_rnd(26,a,b,c,d); f_rnd(28,b,c,d,a);
187     f_rnd(30,c,d,a,b); f_rnd(32,d,a,b,c);
188     f_rnd(34,a,b,c,d); f_rnd(36,b,c,d,a);
189     f_rnd(38,c,d,a,b); f_rnd(40,d,a,b,c);
190
191     out_blk[0] = a + l_key[42]; out_blk[1] = b;
192     out_blk[2] = c + l_key[43]; out_blk[3] = d;
193 };
194
195 /* decrypt a block of text  */
196
197 void rc6_decrypt(RC6Context *ctx,
198                  const u4byte in_blk[4], u4byte out_blk[4])
199 {   
200     u4byte  a,b,c,d,t,u;
201     u4byte *l_key = ctx->l_key;
202
203     d = in_blk[3]; c = in_blk[2] - l_key[43]; 
204     b = in_blk[1]; a = in_blk[0] - l_key[42];
205
206     i_rnd(40,d,a,b,c); i_rnd(38,c,d,a,b);
207     i_rnd(36,b,c,d,a); i_rnd(34,a,b,c,d);
208     i_rnd(32,d,a,b,c); i_rnd(30,c,d,a,b);
209     i_rnd(28,b,c,d,a); i_rnd(26,a,b,c,d);
210     i_rnd(24,d,a,b,c); i_rnd(22,c,d,a,b);
211     i_rnd(20,b,c,d,a); i_rnd(18,a,b,c,d);
212     i_rnd(16,d,a,b,c); i_rnd(14,c,d,a,b);
213     i_rnd(12,b,c,d,a); i_rnd(10,a,b,c,d);
214     i_rnd( 8,d,a,b,c); i_rnd( 6,c,d,a,b);
215     i_rnd( 4,b,c,d,a); i_rnd( 2,a,b,c,d);
216
217     out_blk[3] = d - l_key[1]; out_blk[2] = c; 
218     out_blk[1] = b - l_key[0]; out_blk[0] = a; 
219 };