24 June 1998 ---------------------------------------------------------------------- /* Skipjack, as defined in the document "Skipjack and KEA Algorithm dated 29 May 1998, and located at http://csrc.nist.gov/encryption/skipjack-1.pdf http://csrc.nist.gov/encryption/skipjack-2.pdf Note that there is no author, copyright, or other attribution on the PDF file. This implementation seems to successfully fit the test vectors listed in the documents. In fact, this version of the code simply prints the test vector out. The code is not optimized at all. It is written to be obvious, not necessarily to be fast. This code is hereby placed in the public domain. I would _like_ it if you gave me some credit, but you are under no obligation to do so. Perry E. Metzger, Piermont Information Systems Inc., 24 June 1998 You can reach me via email at perry@piermont.com */ #include #include #define PRINTDUMP /* #define TIMING */ typedef u_int8_t byte; typedef u_int16_t word; byte key[10]; const byte ftable[256] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF*/ /* 0x */ 0xa3, 0xd7, 0x09, 0x83, 0xf8, 0x48, 0xf6, 0xf4, 0xb3, 0x21, 0x15, 0x78, 0x99, 0xb1, 0xaf, 0xf9, /* 1x */ 0xe7, 0x2d, 0x4d, 0x8a, 0xce, 0x4c, 0xca, 0x2e, 0x52, 0x95, 0xd9, 0x1e, 0x4e, 0x38, 0x44, 0x28, /* 2x */ 0x0a, 0xdf, 0x02, 0xa0, 0x17, 0xf1, 0x60, 0x68, 0x12, 0xb7, 0x7a, 0xc3, 0xe9, 0xfa, 0x3d, 0x53, /* 3x */ 0x96, 0x84, 0x6b, 0xba, 0xf2, 0x63, 0x9a, 0x19, 0x7c, 0xae, 0xe5, 0xf5, 0xf7, 0x16, 0x6a, 0xa2, /* 4x */ 0x39, 0xb6, 0x7b, 0x0f, 0xc1, 0x93, 0x81, 0x1b, 0xee, 0xb4, 0x1a, 0xea, 0xd0, 0x91, 0x2f, 0xb8, /* 5x */ 0x55, 0xb9, 0xda, 0x85, 0x3f, 0x41, 0xbf, 0xe0, 0x5a, 0x58, 0x80, 0x5f, 0x66, 0x0b, 0xd8, 0x90, /* 6x */ 0x35, 0xd5, 0xc0, 0xa7, 0x33, 0x06, 0x65, 0x69, 0x45, 0x00, 0x94, 0x56, 0x6d, 0x98, 0x9b, 0x76, /* 7x */ 0x97, 0xfc, 0xb2, 0xc2, 0xb0, 0xfe, 0xdb, 0x20, 0xe1, 0xeb, 0xd6, 0xe4, 0xdd, 0x47, 0x4a, 0x1d, /* 8x */ 0x42, 0xed, 0x9e, 0x6e, 0x49, 0x3c, 0xcd, 0x43, 0x27, 0xd2, 0x07, 0xd4, 0xde, 0xc7, 0x67, 0x18, /* 9x */ 0x89, 0xcb, 0x30, 0x1f, 0x8d, 0xc6, 0x8f, 0xaa, 0xc8, 0x74, 0xdc, 0xc9, 0x5d, 0x5c, 0x31, 0xa4, /* Ax */ 0x70, 0x88, 0x61, 0x2c, 0x9f, 0x0d, 0x2b, 0x87, 0x50, 0x82, 0x54, 0x64, 0x26, 0x7d, 0x03, 0x40, /* Bx */ 0x34, 0x4b, 0x1c, 0x73, 0xd1, 0xc4, 0xfd, 0x3b, 0xcc, 0xfb, 0x7f, 0xab, 0xe6, 0x3e, 0x5b, 0xa5, /* Cx */ 0xad, 0x04, 0x23, 0x9c, 0x14, 0x51, 0x22, 0xf0, 0x29, 0x79, 0x71, 0x7e, 0xff, 0x8c, 0x0e, 0xe2, /* Dx */ 0x0c, 0xef, 0xbc, 0x72, 0x75, 0x6f, 0x37, 0xa1, 0xec, 0xd3, 0x8e, 0x62, 0x8b, 0x86, 0x10, 0xe8, /* Ex */ 0x08, 0x77, 0x11, 0xbe, 0x92, 0x4f, 0x24, 0xc5, 0x32, 0x36, 0x9d, 0xcf, 0xf3, 0xa6, 0xbb, 0xac, /* Fx */ 0x5e, 0x6c, 0xa9, 0x13, 0x57, 0x25, 0xb5, 0xe3, 0xbd, 0xa8, 0x3a, 0x01, 0x05, 0x59, 0x2a, 0x46 }; #define HIGH(x) (((x) >> 8) & 0xff) #define LOW(x) ((x) & 0xff) #define CONCAT(h, l) ((((word)(h)) << 8) | ((word)(l))) #define CV(x) (key[((x) % 10)]) #define f(x) (ftable[(x)]) static word g(int k, word w) { byte g1, g2, g3, g4, g5, g6; word ret; g1 = HIGH(w); g2 = LOW(w); g3 = f(g2 ^ CV(4*k )) ^ g1; g4 = f(g3 ^ CV(4*k+1)) ^ g2; g5 = f(g4 ^ CV(4*k+2)) ^ g3; g6 = f(g5 ^ CV(4*k+3)) ^ g4; ret = CONCAT(g5, g6); return(ret); } static word inv_g(int k, word w) { byte g1, g2, g3, g4, g5, g6; word ret; g6 = LOW(w); g5 = HIGH(w); g4 = f(g5 ^ CV(4*k+3)) ^ g6; g3 = f(g4 ^ CV(4*k+2)) ^ g5; g2 = f(g3 ^ CV(4*k+1)) ^ g4; g1 = f(g2 ^ CV(4*k )) ^ g3; ret = CONCAT(g1, g2); return(ret); } static void dump(int i, word w1, word w2, word w3, word w4) { printf("round %2d: %4.4x %4.4x %4.4x %4.4x\n", i, w1, w2, w3, w4); } static void ruleA(word *w1, word *w2, word *w3, word *w4, int k) { word c, t1, t2, t3, t4, tmp; c = k + 1; t1 = *w1; t2 = *w2; t3 = *w3; t4 = *w4; tmp = g(k, t1); *w1 = tmp ^ t4 ^ c; *w2 = tmp; *w3 = t2; *w4 = t3; } static void ruleB(word *w1, word *w2, word *w3, word *w4, int k) { word c, t1, t2, t3, t4; c = k + 1; t1 = *w1; t2 = *w2; t3 = *w3; t4 = *w4; *w1 = t4; *w2 = g(k, t1); *w3 = t1 ^ t2 ^ c; *w4 = t3; } static void inv_ruleA(word *w1, word *w2, word *w3, word *w4, int k) { word c, t1, t2, t3, t4; c = k; t1 = *w1; t2 = *w2; t3 = *w3; t4 = *w4; *w1 = inv_g((k-1), t2); *w2 = t3; *w3 = t4; *w4 = t1 ^ t2 ^ c; } static void inv_ruleB(word *w1, word *w2, word *w3, word *w4, int k) { word c, t1, t2, t3, t4, tmp; c = k; t1 = *w1; t2 = *w2; t3 = *w3; t4 = *w4; tmp = inv_g((k-1), t2); *w1 = tmp; *w2 = tmp ^ t3 ^ c; *w3 = t4; *w4 = t1; } void encrypt(word *w1, word *w2, word *w3, word *w4) { int i, k; k = 0; for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif ruleA(w1, w2, w3, w4, k++); } for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif ruleB(w1, w2, w3, w4, k++); } for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif ruleA(w1, w2, w3, w4, k++); } for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif ruleB(w1, w2, w3, w4, k++); } } void decrypt(word *w1, word *w2, word *w3, word *w4) { int i, k; k = 32; for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif inv_ruleB(w1, w2, w3, w4, k--); } for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif inv_ruleA(w1, w2, w3, w4, k--); } for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif inv_ruleB(w1, w2, w3, w4, k--); } for (i = 0; i < 8; i++) { #ifdef PRINTDUMP dump(k, *w1, *w2, *w3, *w4); #endif inv_ruleA(w1, w2, w3, w4, k--); } } int main(int argc, char **argv) { int i; word w1, w2, w3, w4; /* plaintext 33221100ddccbbaa */ w1=0x3322; w2=0x1100; w3=0xddcc; w4=0xbbaa; /* key 00998877665544332211 */ key[0] = 0x00; key[1] = 0x99; key[2] = 0x88; key[3] = 0x77; key[4] = 0x66; key[5] = 0x55; key[6] = 0x44; key[7] = 0x33; key[8] = 0x22; key[9] = 0x11; #ifdef TIMING for (i = 0; i < 65536; i++) #endif encrypt(&w1, &w2, &w3, &w4); dump(32, w1, w2, w3, w4); #ifdef TIMING for (i = 0; i < 65536; i++) #endif decrypt(&w1, &w2, &w3, &w4); dump(00, w1, w2, w3, w4); }