/* * MBC1 optimised implementation. * * Algorithm developed by Michael W. Bombardieri * * Version 0.0.2 (2006.09.21) * * The following code is released into the public domain by its author. */ /* rotate 32-bit integers */ #define rotr32(a,b) ((((a) >> (b)) | ((a) << (32 - (b)))) & 0xffffffff) #define rotl32(a,b) ((((a) << (b)) | ((a) >> (32 - (b)))) & 0xffffffff) /* add b to a */ #define add32(a,b) (((a) + (b)) & 0xffffffff) /* subtract b from a */ #define sub32(a,b) (((a) - (b)) & 0xffffffff) #define whiten(a,b,c,d,i) \ blk[a] ^= key[(i + 16) % 32]; \ blk[b] ^= key[(i + 19) % 32]; \ blk[c] ^= key[(i + 21) % 32]; \ blk[d] ^= key[(i + 23) % 32] #define GF_ENC(a,b,c,d,i) \ whiten(a, b, c, d, i); \ blk[a] = add32(blk[a], key[i]); \ blk[b] = add32(blk[b], rotl32(blk[a], 1)); \ blk[c] = add32(blk[c], rotl32(blk[b], 2)); \ blk[d] = add32(blk[d], rotl32(blk[c], 3)); \ fbk = add32(rotl32(blk[d], 5), key[i]) ^ key[i + 1]; \ blk[a] ^= fbk; \ blk[b] ^= rotl32(fbk, 1); \ blk[c] ^= rotl32(fbk, 2); \ blk[d] ^= rotl32(key[i], 1) #define GF_DEC(a,b,c,d,i) \ blk[d] ^= rotl32(key[i], 1); \ fbk = add32(rotl32(blk[d], 5), key[i]) ^ key[i + 1]; \ blk[a] ^= fbk; \ blk[b] ^= rotl32(fbk, 1); \ blk[c] ^= rotl32(fbk, 2); \ blk[d] = sub32(blk[d], rotl32(blk[c], 3)); \ blk[c] = sub32(blk[c], rotl32(blk[b], 2)); \ blk[b] = sub32(blk[b], rotl32(blk[a], 1)); \ blk[a] = sub32(blk[a], key[i]); \ whiten(a, b, c, d, i) #define k1(a,b,c,d,i) \ blk[a] = add32(blk[a], iv_tbl[(i) % 64]); \ blk[b] = add32(blk[b], iv_tbl[((i) + 1) % 64]); \ blk[c] = add32(blk[c], iv_tbl[((i) + 2) % 64]); \ blk[d] = add32(blk[d], iv_tbl[((i) + 3) % 64]) #define key_blk(a,b,c,d,i) \ key[i] = rotl32(blk[a], 5); \ key[i + 1] = rotl32(blk[b], 9); \ key[i + 2] = rotl32(blk[c], 13); \ key[i + 3] = rotl32(blk[d], 17) typedef unsigned char u1byte; typedef unsigned long u4byte; /* may be wider than 32-bit */ /* initialisation vector for the key schedule */ static u4byte iv_tbl[64] = { 0xFA5D7CEC, 0x734533F8, 0x484EA4B2, 0x2BF0E46B, 0xA853884B, 0xCBE7DEE0, 0x976DF92A, 0xE2B17575, 0xF9BC1EFD, 0xF8ADC573, 0x2E5B6EA9, 0x1C5A4FFD, 0x3DF27762, 0x2D7BF0BD, 0x039D26D6, 0x0A937D09, 0x01052BC2, 0x8AEEEA1C, 0xFB7D3EBE, 0x2449A182, 0x17B71BA3, 0xC6E68955, 0x74C7A0CD, 0xE1B88745, 0x4D71958C, 0x149CEB88, 0x5344E0B9, 0xC3F0A21F, 0xA348429B, 0xF672C8CD, 0xD01FA55C, 0x4C6FD3DF, 0xC05B564E, 0xE0D81861, 0xA3B3EAAC, 0x17AE4A08, 0x9D8DF3BF, 0x1353CBFE, 0x25C0F1C8, 0xD52818EC, 0x1BA102B0, 0xC2FDC394, 0x9AB0505E, 0xF8D5F8CB, 0x708749DA, 0x34C5D60B, 0xD1C046B0, 0x4C8E4672, 0x0E236A84, 0x5A36C5AB, 0xDC9B9EB5, 0x0ADB5718, 0x57D27CC5, 0xC4ECAEFD, 0xB57C0D9E, 0x764E92EA, 0x4CA01ED6, 0xA7314405, 0xEE5E6B4B, 0xF9560189, 0xC50CD4D5, 0xBFE0AFD8, 0x8322F984, 0x65601B60 }; static u4byte key[32]; void set_key(const u4byte in_key[4]) /* prepare key schedule */ { u4byte blk[4]; u4byte fbk = 0x19860719; /* scheduler constant */ u4byte t; u1byte key_exp[64]; int x; int i; blk[0] = add32(in_key[0], rotl32(fbk, 3)); blk[1] = add32(in_key[1], rotl32(blk[0], 5)); blk[2] = add32(in_key[2], rotl32(blk[1], 7)); blk[3] = add32(in_key[3], rotl32(blk[2], 11)); x = rotl32(blk[3], 1) % 64; fbk ^= add32(rotl32(blk[3], 2), iv_tbl[x]); blk[0] ^= rotl32(fbk, 1); blk[1] ^= rotl32(blk[0], 2); blk[2] ^= rotl32(blk[1], 3); blk[3] ^= rotl32(blk[2], 4); x = (x + (blk[0] & 0xff)) % 64; k1(2, 1, 0, 3, x); k1(1, 2, 0, 3, x); k1(2, 0, 1, 3, x); k1(0, 2, 1, 3, x); key_blk(0, 1, 2, 3, 0); k1(3, 0, 1, 2, x); key_blk(3, 0, 1, 2, 4); k1(3, 0, 2, 1, x + 4); key_blk(3, 0, 2, 1, 8); k1(3, 1, 0, 2, x + 8); key_blk(3, 1, 0, 2, 12); k1(3, 1, 2, 0, x + 12); key_blk(3, 1, 2, 0, 16); k1(3, 2, 0, 1, x + 16); key_blk(3, 2, 0, 1, 20); k1(3, 2, 1, 0, x + 20); key_blk(3, 2, 1, 0, 24); k1(1, 0, 2, 3, x + 24); key_blk(1, 0, 2, 3, 28); for (i = 0; i < 32; i++) { key_exp[i] = key[i] & 0xff; key_exp[i + 32] = (key[i] & 0xff00) >> 8; } for (i = 0; i < 64; i++) { x = key_exp[i] % 32; t = key[i % 32]; key[i % 32] = key[x]; key[x] = t; } } void encrypt(u4byte blk[4]) /* encrypt a block of text */ { u4byte fbk; GF_ENC(3, 0, 1, 2, 0); GF_ENC(3, 0, 2, 1, 1); GF_ENC(3, 1, 0, 2, 2); GF_ENC(3, 1, 2, 0, 3); GF_ENC(3, 2, 0, 1, 4); GF_ENC(3, 2, 1, 0, 5); GF_ENC(1, 0, 2, 3, 6); GF_ENC(1, 0, 3, 2, 7); GF_ENC(1, 2, 0, 3, 8); GF_ENC(1, 2, 3, 0, 9); GF_ENC(0, 1, 2, 3, 10); GF_ENC(0, 1, 3, 2, 11); GF_ENC(0, 2, 1, 3, 12); GF_ENC(0, 2, 3, 1, 13); GF_ENC(0, 3, 1, 2, 14); GF_ENC(0, 3, 2, 1, 15); } void decrypt(u4byte blk[4]) /* decrypt a block of text */ { u4byte fbk; GF_DEC(0, 3, 2, 1, 15); GF_DEC(0, 3, 1, 2, 14); GF_DEC(0, 2, 3, 1, 13); GF_DEC(0, 2, 1, 3, 12); GF_DEC(0, 1, 3, 2, 11); GF_DEC(0, 1, 2, 3, 10); GF_DEC(1, 2, 3, 0, 9); GF_DEC(1, 2, 0, 3, 8); GF_DEC(1, 0, 3, 2, 7); GF_DEC(1, 0, 2, 3, 6); GF_DEC(3, 2, 1, 0, 5); GF_DEC(3, 2, 0, 1, 4); GF_DEC(3, 1, 2, 0, 3); GF_DEC(3, 1, 0, 2, 2); GF_DEC(3, 0, 2, 1, 1); GF_DEC(3, 0, 1, 2, 0); } #if defined DEBUG #include int main(void) /* demonstrate algorithm usage */ { u4byte in_key[4] = {0x11111111, 0x22222222, 0x33333333, 0x44444444}; u4byte blk[4] = {0x00000000, 0x11111111, 0x22222222, 0x33333333}; printf("%08lx%08lx%08lx%08lx = %s\n", in_key[0], in_key[1], in_key[2], in_key[3], "User key"); printf("%08lx%08lx%08lx%08lx = %s\n", blk[0], blk[1], blk[2], blk[3], "Plaintext"); set_key(&in_key[0]); encrypt(&blk[0]); printf("%08lx%08lx%08lx%08lx = %s\n", blk[0], blk[1], blk[2], blk[3], "Ciphertext"); decrypt(&blk[0]); printf("%08lx%08lx%08lx%08lx = %s\n", blk[0], blk[1], blk[2], blk[3], "Plaintext"); return 0; } #endif