/* RC6 (RC6 16/20/32) Encrypt/Decrypt RC6 was written as a submission for AES by: Ronald L. Rivest, M.J.B Robshaw, R. Sidney, and Y.L Yin Written for Micro-C (portable) by Tom St Denis. The ammount of rounds and bytes per key are changeable at compile time, but are defaulted to 20/32. So it uses 20 rounds to encrypt 64-bits per block using a 32 byte key (256 bits). Notes: 1. Currently if you call encrypt/decrypt seperately, it uses ECB. You may want to use another method such as CFB, CBC or PCBC, all of which can be used on top of encrypt/decrypt. 2. The key you pass to schedule must be at least BKEY bytes long, and have NULL padding if it's not that size. 3. The ammount of ROUNDS effects the effective strength of cipher. Anything between 10 and 40 is ok. 40 is a conservative high-end, and 20 is the default. You can also change the key length. Keys anywhere from 128bits (16 bytes) to 512bits (64 bytes) are ok, but they must be a multiple of 2 bytes. Also you can change the word size. I think 16/32 are the only really valid options, however you can use 64 too. 4. The memory required per scheduled key is: size = 4r + 8 where r is the number of rounds. Default is 88 bytes. 5. If you plan to use this with other compilers change all unsigned variables to unsigned short (make them 16 bits). 6. RC6 is a block cipher. The default is 64-bit blocks. 7. Read Ronald's paper on RC6 for more detailed information. Micro-C is copyrighted Dave Dunfield. Tom St Denis, 1999 */ #define ROUNDS 20 /* rounds per packet */ #define BKEY 32 /* bytes per key */ #define BITS 16 /* bits per word */ #define WORD unsigned /* must be unsigned and hold BITS bits */ #define P 0xB7E1 /* upper BITS of 0xB7E151628AED2A6B */ #define Q 0x9E37 /* upper BITS of 0x9E3779B97F4A7C15 */ #define FACTOR ((ROUNDS * 2) + 4) /* utility functions */ /* rotate left */ WORD rol(WORD v, WORD cnt) { cnt &= (BITS - 1); while (cnt--) v = (v << 1) | (v >> (BITS - 1)); return v; } /* rotate right */ WORD ror(WORD v, WORD cnt) { cnt &= (BITS - 1); while (cnt--) v = (v >> 1) | (v << (BITS - 1)); return v; } /* encrypt, works on 4 BITS-bit blocks at once. The input is overwritten with the output */ void encrypt(WORD packet[4], WORD skey[]) { WORD A, B, C, D, i, t, u, temp; /* load registers with packet */ A = packet[0]; B = packet[1]; C = packet[2]; D = packet[3]; /* start outside */ B += skey[0]; D += skey[1]; /* loop */ for (i = 1; i <= ROUNDS; i++) { t = rol(B * ((B << 1) + 1), 2); u = rol(D * ((D << 1) + 1), 2); A = rol(A ^ t, u) + skey[i << 1]; C = rol(C ^ u, t) + skey[(i << 1) + 1]; /* swap */ temp = A; A = B; B = C; C = D; D = temp; } /* finish */ A += skey[(ROUNDS * 2) + 2]; C += skey[(ROUNDS * 2) + 3]; /* store packet */ packet[0] = A; packet[1] = B; packet[2] = C; packet[3] = D; } /* decrypt, 4 BITS-bit words. The output overwrites the input */ void decrypt(WORD packet[4], WORD skey[]) { WORD A, B, C, D, i, u, t, temp; /* load registers with packets */ A = packet[0]; B = packet[1]; C = packet[2]; D = packet[3]; /* start */ C -= skey[(ROUNDS * 2) + 3]; A -= skey[(ROUNDS * 2) + 2]; /* loop */ for (i = ROUNDS; i >= 1; i--) { /* un-swap */ temp = D; D = C; C = B; B = A; A = temp; u = rol(D * ((D << 1) + 1), 2); t = rol(B * ((B << 1) + 1), 2); C = ror(C - skey[(i << 1) + 1], t) ^ u; A = ror(A - skey[i << 1], u) ^ t; } /* finish */ D -= skey[1]; B -= skey[0]; /* store packet */ packet[0] = A; packet[1] = B; packet[2] = C; packet[3] = D; } /* setup the scheduled key, you must provide a buffer (the user key) with at least BKEY bytes in it. Fill all unused bytes with 0. */ void schedule(unsigned char key[], WORD skey[]) { WORD A, B, i, s, v, j, L[BKEY]; /* setup local copy of key */ for (i = 0; i < BKEY; i++) L[i] = (WORD) key[i]; /* standard starting values */ skey[0] = P; for (i = 1; i <= ((ROUNDS * 2) + 3); i++) skey[i] = skey[i - 1] + Q; /* now setup key */ A = B = i = j = 0; v = 3 * (BKEY > FACTOR ? BKEY : FACTOR); for (s = 1; s <= v; s++) { A = skey[i] = rol(skey[i] + A + B, 3); B = L[j] = rol(L[j] + A + B, A + B); i = (i + 1) % FACTOR; j = (j + 1) % BKEY; } } /* test */ #include #ifndef _MICROC_ #include #endif WORD in[4], out[4], out2[4]; /* test vectors */ WORD skey[FACTOR]; /* scheduled key */ unsigned char key[BKEY]; /* input key */ main() { /* use empty test vectors */ memset(in, 0, sizeof(in)); /* test encrypt */ memset(key, 0, sizeof(key)); /* empty key */ schedule(key, skey); /* schedule the key */ memcpy(out, in, sizeof(in)); encrypt(out, skey); /* test decrypt */ memset(key, 0, sizeof(key)); /* empty key */ schedule(key, skey); /* schedule the key */ memcpy(out2, out, sizeof(out)); decrypt(out2, skey); /* print results */ printf("Normal : %4x %4x %4x %4x\n", in[0], in[1], in[2], in[3]); printf("Encoded: %4x %4x %4x %4x\n", out[0], out[1], out[2], out[3]); printf("Decoded: %4x %4x %4x %4x\n", out2[0], out2[1], out2[2], out2[3]); }