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, tomstdenis (at) gmail.com, http://libtomcrypt.com 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, 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 @return CRYPT_OK if successful 127 */ 128 #ifdef LTC_CLEAN_STACK 129 static int _rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) 130 #else 131 int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) 132 #endif 133 { 134 ulong32 A, B, *K; 135 int r; 136 LTC_ARGCHK(skey != NULL); 137 LTC_ARGCHK(pt != NULL); 138 LTC_ARGCHK(ct != NULL); 139 140 LOAD32L(A, &pt[0]); 141 LOAD32L(B, &pt[4]); 142 A += skey->rc5.K[0]; 143 B += skey->rc5.K[1]; 144 K = skey->rc5.K + 2; 145 146 if ((skey->rc5.rounds & 1) == 0) { 147 for (r = 0; r < skey->rc5.rounds; r += 2) { 148 A = ROL(A ^ B, B) + K[0]; 149 B = ROL(B ^ A, A) + K[1]; 150 A = ROL(A ^ B, B) + K[2]; 151 B = ROL(B ^ A, A) + K[3]; 152 K += 4; 153 } 154 } else { 155 for (r = 0; r < skey->rc5.rounds; r++) { 156 A = ROL(A ^ B, B) + K[0]; 157 B = ROL(B ^ A, A) + K[1]; 158 K += 2; 159 } 160 } 161 STORE32L(A, &ct[0]); 162 STORE32L(B, &ct[4]); 163 164 return CRYPT_OK; 165 } 166 167 #ifdef LTC_CLEAN_STACK 168 int rc5_ecb_encrypt(const unsigned char *pt, unsigned char *ct, symmetric_key *skey) 169 { 170 int err = _rc5_ecb_encrypt(pt, ct, skey); 171 burn_stack(sizeof(ulong32) * 2 + sizeof(int)); 172 return err; 173 } 174 #endif 175 176 /** 177 Decrypts a block of text with RC5 178 @param ct The input ciphertext (8 bytes) 179 @param pt The output plaintext (8 bytes) 180 @param skey The key as scheduled 181 @return CRYPT_OK if successful 182 */ 183 #ifdef LTC_CLEAN_STACK 184 static int _rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) 185 #else 186 int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) 187 #endif 188 { 189 ulong32 A, B, *K; 190 int r; 191 LTC_ARGCHK(skey != NULL); 192 LTC_ARGCHK(pt != NULL); 193 LTC_ARGCHK(ct != NULL); 194 195 LOAD32L(A, &ct[0]); 196 LOAD32L(B, &ct[4]); 197 K = skey->rc5.K + (skey->rc5.rounds << 1); 198 199 if ((skey->rc5.rounds & 1) == 0) { 200 K -= 2; 201 for (r = skey->rc5.rounds - 1; r >= 0; r -= 2) { 202 B = ROR(B - K[3], A) ^ A; 203 A = ROR(A - K[2], B) ^ B; 204 B = ROR(B - K[1], A) ^ A; 205 A = ROR(A - K[0], B) ^ B; 206 K -= 4; 207 } 208 } else { 209 for (r = skey->rc5.rounds - 1; r >= 0; r--) { 210 B = ROR(B - K[1], A) ^ A; 211 A = ROR(A - K[0], B) ^ B; 212 K -= 2; 213 } 214 } 215 A -= skey->rc5.K[0]; 216 B -= skey->rc5.K[1]; 217 STORE32L(A, &pt[0]); 218 STORE32L(B, &pt[4]); 219 220 return CRYPT_OK; 221 } 222 223 #ifdef LTC_CLEAN_STACK 224 int rc5_ecb_decrypt(const unsigned char *ct, unsigned char *pt, symmetric_key *skey) 225 { 226 int err = _rc5_ecb_decrypt(ct, pt, skey); 227 burn_stack(sizeof(ulong32) * 2 + sizeof(int)); 228 return err; 229 } 230 #endif 231 232 /** 233 Performs a self-test of the RC5 block cipher 234 @return CRYPT_OK if functional, CRYPT_NOP if self-test has been disabled 235 */ 236 int rc5_test(void) 237 { 238 #ifndef LTC_TEST 239 return CRYPT_NOP; 240 #else 241 static const struct { 242 unsigned char key[16], pt[8], ct[8]; 243 } tests[] = { 244 { 245 { 0x91, 0x5f, 0x46, 0x19, 0xbe, 0x41, 0xb2, 0x51, 246 0x63, 0x55, 0xa5, 0x01, 0x10, 0xa9, 0xce, 0x91 }, 247 { 0x21, 0xa5, 0xdb, 0xee, 0x15, 0x4b, 0x8f, 0x6d }, 248 { 0xf7, 0xc0, 0x13, 0xac, 0x5b, 0x2b, 0x89, 0x52 } 249 }, 250 { 251 { 0x78, 0x33, 0x48, 0xe7, 0x5a, 0xeb, 0x0f, 0x2f, 252 0xd7, 0xb1, 0x69, 0xbb, 0x8d, 0xc1, 0x67, 0x87 }, 253 { 0xF7, 0xC0, 0x13, 0xAC, 0x5B, 0x2B, 0x89, 0x52 }, 254 { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 } 255 }, 256 { 257 { 0xDC, 0x49, 0xdb, 0x13, 0x75, 0xa5, 0x58, 0x4f, 258 0x64, 0x85, 0xb4, 0x13, 0xb5, 0xf1, 0x2b, 0xaf }, 259 { 0x2F, 0x42, 0xB3, 0xB7, 0x03, 0x69, 0xFC, 0x92 }, 260 { 0x65, 0xc1, 0x78, 0xb2, 0x84, 0xd1, 0x97, 0xcc } 261 } 262 }; 263 unsigned char tmp[2][8]; 264 int x, y, err; 265 symmetric_key key; 266 267 for (x = 0; x < (int)(sizeof(tests) / sizeof(tests[0])); x++) { 268 /* setup key */ 269 if ((err = rc5_setup(tests[x].key, 16, 12, &key)) != CRYPT_OK) { 270 return err; 271 } 272 273 /* encrypt and decrypt */ 274 rc5_ecb_encrypt(tests[x].pt, tmp[0], &key); 275 rc5_ecb_decrypt(tmp[0], tmp[1], &key); 276 277 /* compare */ 278 if (XMEMCMP(tmp[0], tests[x].ct, 8) != 0 || XMEMCMP(tmp[1], tests[x].pt, 8) != 0) { 279 return CRYPT_FAIL_TESTVECTOR; 280 } 281 282 /* now see if we can encrypt all zero bytes 1000 times, decrypt and come back where we started */ 283 for (y = 0; y < 8; y++) tmp[0][y] = 0; 284 for (y = 0; y < 1000; y++) rc5_ecb_encrypt(tmp[0], tmp[0], &key); 285 for (y = 0; y < 1000; y++) rc5_ecb_decrypt(tmp[0], tmp[0], &key); 286 for (y = 0; y < 8; y++) if (tmp[0][y] != 0) return CRYPT_FAIL_TESTVECTOR; 287 } 288 return CRYPT_OK; 289 #endif 290 } 291 292 /** Terminate the context 293 @param skey The scheduled key 294 */ 295 void rc5_done(symmetric_key *skey) 296 { 297 } 298 299 /** 300 Gets suitable key size 301 @param keysize [in/out] The length of the recommended key (in bytes). This function will store the suitable size back in this variable. 302 @return CRYPT_OK if the input key size is acceptable. 303 */ 304 int rc5_keysize(int *keysize) 305 { 306 LTC_ARGCHK(keysize != NULL); 307 if (*keysize < 8) { 308 return CRYPT_INVALID_KEYSIZE; 309 } else if (*keysize > 128) { 310 *keysize = 128; 311 } 312 return CRYPT_OK; 313 } 314 315 #endif 316 317 318 319 320 /* $Source: /cvs/libtom/libtomcrypt/src/ciphers/rc5.c,v $ */ 321 /* $Revision: 1.12 $ */ 322 /* $Date: 2006/11/08 23:01:06 $ */ 323