Mercurial > dropbear
comparison libtomcrypt/src/ciphers/rc5.c @ 285:1b9e69c058d2
propagate from branch 'au.asn.ucc.matt.ltc.dropbear' (head 20dccfc09627970a312d77fb41dc2970b62689c3)
to branch 'au.asn.ucc.matt.dropbear' (head fdf4a7a3b97ae5046139915de7e40399cceb2c01)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 08 Mar 2006 13:23:58 +0000 |
parents | |
children | 0cbe8f6dbf9e |
comparison
equal
deleted
inserted
replaced
281:997e6f7dc01e | 285:1b9e69c058d2 |
---|---|
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis | |
2 * | |
3 * LibTomCrypt is a library that provides various cryptographic | |
4 * algorithms in a highly modular and flexible manner. | |
5 * | |
6 * The library is free for all purposes without any express | |
7 * guarantee it works. | |
8 * | |
9 * Tom St Denis, [email protected], http://libtomcrypt.org | |
10 */ | |
11 | |
12 /** | |
13 @file rc5.c | |
14 RC5 code by Tom St Denis | |
15 */ | |
16 | |
17 #include "tomcrypt.h" | |
18 | |
19 #ifdef RC5 | |
20 | |
21 const struct ltc_cipher_descriptor rc5_desc = | |
22 { | |
23 "rc5", | |
24 2, | |
25 8, 128, 8, 12, | |
26 &rc5_setup, | |
27 &rc5_ecb_encrypt, | |
28 &rc5_ecb_decrypt, | |
29 &rc5_test, | |
30 &rc5_done, | |
31 &rc5_keysize, | |
32 NULL, NULL, NULL, NULL, NULL, NULL, NULL | |
33 }; | |
34 | |
35 static const ulong32 stab[50] = { | |
36 0xb7e15163UL, 0x5618cb1cUL, 0xf45044d5UL, 0x9287be8eUL, 0x30bf3847UL, 0xcef6b200UL, 0x6d2e2bb9UL, 0x0b65a572UL, | |
37 0xa99d1f2bUL, 0x47d498e4UL, 0xe60c129dUL, 0x84438c56UL, 0x227b060fUL, 0xc0b27fc8UL, 0x5ee9f981UL, 0xfd21733aUL, | |
38 0x9b58ecf3UL, 0x399066acUL, 0xd7c7e065UL, 0x75ff5a1eUL, 0x1436d3d7UL, 0xb26e4d90UL, 0x50a5c749UL, 0xeedd4102UL, | |
39 0x8d14babbUL, 0x2b4c3474UL, 0xc983ae2dUL, 0x67bb27e6UL, 0x05f2a19fUL, 0xa42a1b58UL, 0x42619511UL, 0xe0990ecaUL, | |
40 0x7ed08883UL, 0x1d08023cUL, 0xbb3f7bf5UL, 0x5976f5aeUL, 0xf7ae6f67UL, 0x95e5e920UL, 0x341d62d9UL, 0xd254dc92UL, | |
41 0x708c564bUL, 0x0ec3d004UL, 0xacfb49bdUL, 0x4b32c376UL, 0xe96a3d2fUL, 0x87a1b6e8UL, 0x25d930a1UL, 0xc410aa5aUL, | |
42 0x62482413UL, 0x007f9dccUL | |
43 }; | |
44 | |
45 /** | |
46 Initialize the RC5 block cipher | |
47 @param key The symmetric key you wish to pass | |
48 @param keylen The key length in bytes | |
49 @param num_rounds The number of rounds desired (0 for default) | |
50 @param skey The key in as scheduled by this function. | |
51 @return CRYPT_OK if successful | |
52 */ | |
53 #ifdef LTC_CLEAN_STACK | |
54 static int _rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) | |
55 #else | |
56 int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) | |
57 #endif | |
58 { | |
59 ulong32 L[64], *S, A, B, i, j, v, s, t, l; | |
60 | |
61 LTC_ARGCHK(skey != NULL); | |
62 LTC_ARGCHK(key != NULL); | |
63 | |
64 /* test parameters */ | |
65 if (num_rounds == 0) { | |
66 num_rounds = rc5_desc.default_rounds; | |
67 } | |
68 | |
69 if (num_rounds < 12 || num_rounds > 24) { | |
70 return CRYPT_INVALID_ROUNDS; | |
71 } | |
72 | |
73 /* key must be between 64 and 1024 bits */ | |
74 if (keylen < 8 || keylen > 128) { | |
75 return CRYPT_INVALID_KEYSIZE; | |
76 } | |
77 | |
78 skey->rc5.rounds = num_rounds; | |
79 S = skey->rc5.K; | |
80 | |
81 /* copy the key into the L array */ | |
82 for (A = i = j = 0; i < (ulong32)keylen; ) { | |
83 A = (A << 8) | ((ulong32)(key[i++] & 255)); | |
84 if ((i & 3) == 0) { | |
85 L[j++] = BSWAP(A); | |
86 A = 0; | |
87 } | |
88 } | |
89 | |
90 if ((keylen & 3) != 0) { | |
91 A <<= (ulong32)((8 * (4 - (keylen&3)))); | |
92 L[j++] = BSWAP(A); | |
93 } | |
94 | |
95 /* setup the S array */ | |
96 t = (ulong32)(2 * (num_rounds + 1)); | |
97 XMEMCPY(S, stab, t * sizeof(*S)); | |
98 | |
99 /* mix buffer */ | |
100 s = 3 * MAX(t, j); | |
101 l = j; | |
102 for (A = B = i = j = v = 0; v < s; v++) { | |
103 A = S[i] = ROLc(S[i] + A + B, 3); | |
104 B = L[j] = ROL(L[j] + A + B, (A+B)); | |
105 if (++i == t) { i = 0; } | |
106 if (++j == l) { j = 0; } | |
107 } | |
108 return CRYPT_OK; | |
109 } | |
110 | |
111 #ifdef LTC_CLEAN_STACK | |
112 int rc5_setup(const unsigned char *key, int keylen, int num_rounds, symmetric_key *skey) | |
113 { | |
114 int x; | |
115 x = _rc5_setup(key, keylen, num_rounds, skey); | |
116 burn_stack(sizeof(ulong32) * 122 + sizeof(int)); | |
117 return x; | |
118 } | |
119 #endif | |
120 | |
121 /** | |
122 Encrypts a block of text with RC5 | |
123 @param pt The input plaintext (8 bytes) | |
124 @param ct The output ciphertext (8 bytes) | |
125 @param skey The key as scheduled | |
126 */ | |
127 #ifdef LTC_CLEAN_STACK | |
128 static void _rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) | |
129 #else | |
130 void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) | |
131 #endif | |
132 { | |
133 ulong32 A, B, *K; | |
134 int r; | |
135 LTC_ARGCHK(skey != NULL); | |
136 LTC_ARGCHK(pt != NULL); | |
137 LTC_ARGCHK(ct != NULL); | |
138 | |
139 LOAD32L(A, &pt[0]); | |
140 LOAD32L(B, &pt[4]); | |
141 A += skey->rc5.K[0]; | |
142 B += skey->rc5.K[1]; | |
143 K = skey->rc5.K + 2; | |
144 | |
145 if ((skey->rc5.rounds & 1) == 0) { | |
146 for (r = 0; r < skey->rc5.rounds; r += 2) { | |
147 A = ROL(A ^ B, B) + K[0]; | |
148 B = ROL(B ^ A, A) + K[1]; | |
149 A = ROL(A ^ B, B) + K[2]; | |
150 B = ROL(B ^ A, A) + K[3]; | |
151 K += 4; | |
152 } | |
153 } else { | |
154 for (r = 0; r < skey->rc5.rounds; r++) { | |
155 A = ROL(A ^ B, B) + K[0]; | |
156 B = ROL(B ^ A, A) + K[1]; | |
157 K += 2; | |
158 } | |
159 } | |
160 STORE32L(A, &ct[0]); | |
161 STORE32L(B, &ct[4]); | |
162 } | |
163 | |
164 #ifdef LTC_CLEAN_STACK | |
165 void rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) | |
166 { | |
167 _rc5_ecb_encrypt(pt, ct, skey); | |
168 burn_stack(sizeof(ulong32) * 2 + sizeof(int)); | |
169 } | |
170 #endif | |
171 | |
172 /** | |
173 Decrypts a block of text with RC5 | |
174 @param ct The input ciphertext (8 bytes) | |
175 @param pt The output plaintext (8 bytes) | |
176 @param skey The key as scheduled | |
177 */ | |
178 #ifdef LTC_CLEAN_STACK | |
179 static void _rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) | |
180 #else | |
181 void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) | |
182 #endif | |
183 { | |
184 ulong32 A, B, *K; | |
185 int r; | |
186 LTC_ARGCHK(skey != NULL); | |
187 LTC_ARGCHK(pt != NULL); | |
188 LTC_ARGCHK(ct != NULL); | |
189 | |
190 LOAD32L(A, &ct[0]); | |
191 LOAD32L(B, &ct[4]); | |
192 K = skey->rc5.K + (skey->rc5.rounds << 1); | |
193 | |
194 if ((skey->rc5.rounds & 1) == 0) { | |
195 K -= 2; | |
196 for (r = skey->rc5.rounds - 1; r >= 0; r -= 2) { | |
197 B = ROR(B - K[3], A) ^ A; | |
198 A = ROR(A - K[2], B) ^ B; | |
199 B = ROR(B - K[1], A) ^ A; | |
200 A = ROR(A - K[0], B) ^ B; | |
201 K -= 4; | |
202 } | |
203 } else { | |
204 for (r = skey->rc5.rounds - 1; r >= 0; r--) { | |
205 B = ROR(B - K[1], A) ^ A; | |
206 A = ROR(A - K[0], B) ^ B; | |
207 K -= 2; | |
208 } | |
209 } | |
210 A -= skey->rc5.K[0]; | |
211 B -= skey->rc5.K[1]; | |
212 STORE32L(A, &pt[0]); | |
213 STORE32L(B, &pt[4]); | |
214 } | |
215 | |
216 #ifdef LTC_CLEAN_STACK | |
217 void rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) | |
218 { | |
219 _rc5_ecb_decrypt(ct, pt, skey); | |
220 burn_stack(sizeof(ulong32) * 2 + sizeof(int)); | |
221 } | |
222 #endif | |
223 | |
224 /** | |
225 Performs a self-test of the RC5 block cipher | |
226 @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled | |
227 */ | |
228 int rc5_test(void) | |
229 { | |
230 #ifndef LTC_TEST | |
231 return CRYPT_NOP; | |
232 #else | |
233 static const struct { | |
234 unsigned char key[16], pt[8], ct[8]; | |
235 } tests[] = { | |
236 { | |
237 { 0x91, 0x5f, 0x46, 0x19, 0xbe, 0x41, 0xb2, 0x51, | |
238 0x63, 0x55, 0xa5, 0x01, 0x10, 0xa9, 0xce, 0x91 }, | |
239 { 0x21, 0xa5, 0xdb, 0xee, 0x15, 0x4b, 0x8f, 0x6d }, | |
240 { 0xf7, 0xc0, 0x13, 0xac, 0x5b, 0x2b, 0x89, 0x52 } | |
241 }, | |
242 { | |
243 { 0x78, 0x33, 0x48, 0xe7, 0x5a, 0xeb, 0x0f, 0x2f, | |
244 0xd7, 0xb1, 0x69, 0xbb, 0x8d, 0xc1, 0x67, 0x87 }, | |
245 { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 }, | |
246 { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 } | |
247 }, | |
248 { | |
249 { 0xDC, 0x49, 0xdb, 0x13, 0x75, 0xa5, 0x58, 0x4f, | |
250 0x64, 0x85, 0xb4, 0x13, 0xb5, 0xf1, 0x2b, 0xaf }, | |
251 { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 }, | |
252 { 0x65, 0xc1, 0x78, 0xb2, 0x84, 0xd1, 0x97, 0xcc } | |
253 } | |
254 }; | |
255 unsigned char tmp[2][8]; | |
256 int x, y, err; | |
257 symmetric_key key; | |
258 | |
259 for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { | |
260 /* setup key */ | |
261 if ((err = rc5_setup(tests[x].key, 16, 12, &key)) != CRYPT_OK) { | |
262 return err; | |
263 } | |
264 | |
265 /* encrypt and decrypt */ | |
266 rc5_ecb_encrypt(tests[x].pt, tmp[0], &key); | |
267 rc5_ecb_decrypt(tmp[0], tmp[1], &key); | |
268 | |
269 /* compare */ | |
270 if (memcmp(tmp[0], tests[x].ct, 8) != 0 || memcmp(tmp[1], tests[x].pt, 8) != 0) { | |
271 return CRYPT_FAIL_TESTVECTOR; | |
272 } | |
273 | |
274 /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ | |
275 for (y = 0; y < 8; y++) tmp[0][y] = 0; | |
276 for (y = 0; y < 1000; y++) rc5_ecb_encrypt(tmp[0], tmp[0], &key); | |
277 for (y = 0; y < 1000; y++) rc5_ecb_decrypt(tmp[0], tmp[0], &key); | |
278 for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; | |
279 } | |
280 return CRYPT_OK; | |
281 #endif | |
282 } | |
283 | |
284 /** Terminate the context | |
285 @param skey The scheduled key | |
286 */ | |
287 void rc5_done(symmetric_key *skey) | |
288 { | |
289 } | |
290 | |
291 /** | |
292 Gets suitable key size | |
293 @param keysize [in/out] The length of the recommended key (in bytes). This function will store the suitable size back in this variable. | |
294 @return CRYPT_OK if the input key size is acceptable. | |
295 */ | |
296 int rc5_keysize(int *keysize) | |
297 { | |
298 LTC_ARGCHK(keysize != NULL); | |
299 if (*keysize < 8) { | |
300 return CRYPT_INVALID_KEYSIZE; | |
301 } else if (*keysize > 128) { | |
302 *keysize = 128; | |
303 } | |
304 return CRYPT_OK; | |
305 } | |
306 | |
307 #endif | |
308 | |
309 | |
310 | |
311 | |
312 /* $Source: /cvs/libtom/libtomcrypt/src/ciphers/rc5.c,v $ */ | |
313 /* $Revision: 1.7 $ */ | |
314 /* $Date: 2005/05/05 14:35:58 $ */ |