| Cryptome DVDs. Donate $25 for two DVDs of the Cryptome collection of 47,000 files from June 1996 to January 2009 (~6.9 GB). Click Paypal or mail check/MO made out to John Young, 251 West 89th Street, New York, NY 10024. The collection includes all files of cryptome.org, cryptome.info, jya.com, cartome.org, eyeball-series.org and iraq-kill-maim.org, and 23,100 (updated) pages of counter-intelligence dossiers declassified by the US Army Information and Security Command, dating from 1945 to 1985.The DVDs will be sent anywhere worldwide without extra cost.

24 June 1998

    To: jya@pipeline.com, mpj@ebible.org
    Subject: can you find this a good home?
    From: "Perry E. Metzger" <perry@piermont.com>
    Date: 24 Jun 1998 20:21:51 -0400

    ----------------------------------------------------------------------
    /*
      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 <stdio.h>
    #include <sys/types.h>

    #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);
    }