/* $Id: nlstest.c 388 2005-04-28 21:04:09Z mwp $ */ /* * Test harness for NLS/Mundja * * Copyright C 2004, Qualcomm Inc. Written by Greg Rose */ /* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND AGAINST INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "nls.h" /* interface definitions */ nls_ctx ctx; /* testing and timing harness */ #include #include #include #include #include "hexlib.h" /* mostly for debugging, print the LFSR contents. */ int v = 0; /* disables debug stuff */ void printLFSR(const char *s, WORD R[]) { register int i; if (!v) return; printf("%s\n", s); for (i = 0; i < N; ++i) { printf("%*s%08lx\n", i*4, "", R[i]); } } /* test vectors */ UCHAR *testkey = (UCHAR *)"test key 128bits"; UCHAR *testframe = (UCHAR *)"\0\0\0\0"; #define TESTSIZE 20 #define INPUTSIZE 100 #define STREAMTEST 1000000 #define ITERATIONS 999999 char *testout = "8a ad 39 fd 4a fa eb de 05 b7 27 8e 4a e3 df a9 66 c2 1c 52"; char *streamout = "94 46 32 50 b1 36 9f a2 7e 63 2b 05 8c dd 13 1a a1 11 ca ad"; char *macout = "52 f7 11 7f 5b 0c 33 de 87 61 ab b6 b5 e4 ea 91 46 f7 78 e0"; char *zeros = "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"; char *iterout = "3a 70 5e 1b 54 36 bc 75 87 29 98 08 be 52 20 22 e9 e5 a3 66"; char *nonceout = "f3 2a b8 1d 75 33 47 37 91 e9 e3 d2 d0 35 4d b0 e4 01 c0 2f"; char *hellmac = "e3 71 a2 a2 46 24 5b 11 3b 90 26 a5 bc f2 d9 e5 0e 46 00 53"; UCHAR testbuf[STREAMTEST + INPUTSIZE]; UCHAR macbuf[INPUTSIZE]; UCHAR mac[TESTSIZE]; UCHAR bigbuf[1024*1024]; void test_sss(int quick) { int i; unsigned char ha, he, hm, hc; /* hell test variables */ extern int keylen; /* basic test */ memset(testbuf, '\0', sizeof testbuf); nls_key(&ctx, testkey, strlen((char *)testkey)); printLFSR("Saved LFSR", ctx.initR); /* check endian-ness */ if (ctx.initR[0] == 0x55bf8df5) printf("It is probable that byte ordering is incorrect.\n"); nls_nonce(&ctx, testframe, 4); nls_stream(&ctx, testbuf, INPUTSIZE); hexprint("one chunk", testbuf, TESTSIZE); hexcheck(testbuf, testout, TESTSIZE); /* now redo that test, byte-at-a-time */ memset(testbuf, '\0', sizeof testbuf); nls_nonce(&ctx, testframe, 4); for (i = 0; i < INPUTSIZE; ++i) nls_stream(&ctx, testbuf+i, 1); hexprint("single bytes", testbuf, TESTSIZE); hexcheck(testbuf, testout, TESTSIZE); /* generate and test more of the same stream */ nls_stream(&ctx, testbuf + INPUTSIZE, STREAMTEST); hexprint("STREAMTEST", testbuf + STREAMTEST, TESTSIZE); hexcheck(testbuf + STREAMTEST, streamout, TESTSIZE); #if !NLS_LONG_OUTPUT printf("Warning. NLS was compiled for short output streams only;\n"); printf("expect the previous stream test to fail.\n"); #endif /*NLS_LONG_OUTPUT*/ /* generate and check a MAC of an empty buffer */ memset(macbuf, '\0', sizeof macbuf); nls_nonce(&ctx, testframe, 4); nls_maconly(&ctx, macbuf, sizeof macbuf); nls_finish(&ctx, mac, sizeof mac); hexprint("MAC test", mac, sizeof mac); hexcheck(mac, macout, sizeof mac); /* now redo that test, byte-at-a-time */ memset(macbuf, '\0', sizeof macbuf); nls_nonce(&ctx, testframe, 4); for (i = 0; i < sizeof macbuf; ++i) nls_maconly(&ctx, macbuf+i, 1); nls_finish(&ctx, mac, sizeof mac); hexprint("MAC bytes", mac, sizeof mac); hexcheck(mac, macout, sizeof mac); /* encrypt and MAC an empty buffer */ memset(macbuf, '\0', sizeof macbuf); nls_nonce(&ctx, testframe, 4); nls_encrypt(&ctx, macbuf, sizeof macbuf); hexprint("MAC+enc test", macbuf, TESTSIZE); hexcheck(macbuf, testout, TESTSIZE); nls_finish(&ctx, mac, sizeof mac); hexprint("final MAC", mac, sizeof mac); hexcheck(mac, macout, sizeof mac); /* now decrypt it and verify the MAC */ nls_nonce(&ctx, testframe, 4); nls_decrypt(&ctx, macbuf, sizeof macbuf); hexprint("MAC+dec test", macbuf, TESTSIZE); hexcheck(macbuf, zeros, TESTSIZE); nls_finish(&ctx, mac, sizeof mac); hexprint("final MAC", mac, sizeof mac); hexcheck(mac, macout, sizeof mac); /* redo those tests, byte-at-a-time */ memset(macbuf, '\0', sizeof macbuf); nls_nonce(&ctx, testframe, 4); for (i = 0; i < sizeof macbuf; ++i) nls_encrypt(&ctx, macbuf+i, 1); hexprint("M+e bytes", macbuf, TESTSIZE); hexcheck(macbuf, testout, TESTSIZE); nls_finish(&ctx, mac, sizeof mac); hexprint("final MAC", mac, sizeof mac); hexcheck(mac, macout, sizeof mac); nls_nonce(&ctx, testframe, 4); for (i = 0; i < sizeof macbuf; ++i) nls_decrypt(&ctx, macbuf+i, 1); hexprint("M+d bytes", macbuf, TESTSIZE); hexcheck(macbuf, zeros, TESTSIZE); nls_finish(&ctx, mac, sizeof mac); hexprint("final MAC", mac, sizeof mac); hexcheck(mac, macout, sizeof mac); if (quick) return; /* test many times iterated */ for (i = 0; i < ITERATIONS; ++i) { if (i % 500 == 0 && !v) printf("%6d\r", i), fflush(stdout); nls_key(&ctx, testbuf, TESTSIZE); nls_stream(&ctx, testbuf, TESTSIZE); } printf("1000000\n"); hexprint("iterated", testbuf, TESTSIZE); hexcheck(testbuf, iterout, TESTSIZE); /* test many times iterated through the nonce */ nls_key(&ctx, testkey, strlen((char *)testkey)); nls_nonce(&ctx, NULL, 0); memset(testbuf, '\0', sizeof testbuf); nls_stream(&ctx, testbuf, TESTSIZE); for (i = 0; i < ITERATIONS; ++i) { if (i % 500 == 0 && !v) printf("%6d\r", i), fflush(stdout); nls_nonce(&ctx, testbuf, 4); nls_stream(&ctx, testbuf, 4); } printf("1000000\n"); hexprint("nonce test", testbuf, TESTSIZE); hexcheck(testbuf, nonceout, TESTSIZE); /* now the test vector from hell -- * Start with a large, zero'd buffer, and a MAC buffer. * Iterate 1000000 times encrypting/decrypting/macing under control * of the output. */ nls_key(&ctx, testkey, strlen((char *)testkey)); memset(testbuf, '\0', sizeof testbuf); memset(mac, '\0', TESTSIZE); for (i = 0; i < ITERATIONS+1; ++i) { if (i % 500 == 0 && !v) printf("%6d\r", i), fflush(stdout); hm = 5 + mac[0] % (TESTSIZE - 4); he = mac[1]; ha = mac[2]; hc = mac[3] & 0x03; switch (hc) { case 0: /* MAC only, then encrypt */ if (v) printf("mac %3d, enc %3d: ", ha, he); nls_maconly(&ctx, testbuf, ha); nls_encrypt(&ctx, testbuf+ha, he); break; case 1: /* Encrypt then MAC */ if (v) printf("enc %3d, mac %3d: ", he, ha); nls_encrypt(&ctx, testbuf, he); nls_maconly(&ctx, testbuf+he, ha); break; case 2: /* MAC only, then decrypt */ if (v) printf("mac %3d, dec %3d: ", ha, he); nls_maconly(&ctx, testbuf, ha); nls_decrypt(&ctx, testbuf+ha, he); break; case 3: /* decrypt then MAC */ if (v) printf("dec %3d, mac %3d: ", he, ha); nls_decrypt(&ctx, testbuf, he); nls_maconly(&ctx, testbuf+he, ha); break; } nls_finish(&ctx, mac, hm); if (v) hexprint("MAC", macbuf, hm); nls_nonce(&ctx, mac, TESTSIZE); } printf("1000000\n"); hexbulk(testbuf, 510); hexprint("hell MAC", mac, TESTSIZE); hexcheck(mac, hellmac, TESTSIZE); } #define BLOCKSIZE 1600 /* for MAC-style tests */ #define MACSIZE 8 /* Perform various timing tests */ void time_sss(void) { long i; clock_t t; WORD k[4] = { 0, 0, 0, 0 }; test_sss(1); nls_key(&ctx, testkey, strlen((char *)testkey)); nls_nonce(&ctx, (unsigned char *)"", 0); /* test stream generation speed */ t = clock(); for (i = 0; i < 200000000; ) { i += sizeof bigbuf; nls_stream(&ctx, bigbuf, sizeof bigbuf); } t = clock() - t; printf("%f Mbyte per second single stream encryption\n", (((double)i/((double)t / (double)CLOCKS_PER_SEC))) / 1000000.0); /* test packet encryption speed */ t = clock(); for (i = 0; i < 200000000; ) { nls_nonce(&ctx, testframe, 4); nls_stream(&ctx, bigbuf, BLOCKSIZE); i += BLOCKSIZE; } t = clock() - t; printf("%f Mbyte per second encrypt %d-byte blocks\n", (((double)i/((double)t / (double)CLOCKS_PER_SEC))) / 1000000.0, BLOCKSIZE, MACSIZE*8); /* test MAC generation speed */ t = clock(); for (i = 0; i < 200000000; ) { nls_nonce(&ctx, testframe, 4); nls_maconly(&ctx, bigbuf, BLOCKSIZE); nls_finish(&ctx, macbuf, MACSIZE); i += BLOCKSIZE; } t = clock() - t; printf("%f Mbyte per second MAC %d-byte blocks %d-bit MAC\n", (((double)i/((double)t / (double)CLOCKS_PER_SEC))) / 1000000.0, BLOCKSIZE, MACSIZE*8); /* test combined encryption speed */ t = clock(); for (i = 0; i < 200000000; ) { nls_nonce(&ctx, testframe, 4); nls_encrypt(&ctx, bigbuf, BLOCKSIZE); nls_finish(&ctx, macbuf, MACSIZE); i += BLOCKSIZE; } t = clock() - t; printf("%f Mbyte per second MAC and encrypt %d-byte blocks %d-bit MAC\n", (((double)i/((double)t / (double)CLOCKS_PER_SEC))) / 1000000.0, BLOCKSIZE, MACSIZE*8); /* test combined decryption speed */ t = clock(); for (i = 0; i < 200000000; ) { nls_nonce(&ctx, testframe, 4); nls_decrypt(&ctx, bigbuf, BLOCKSIZE); nls_finish(&ctx, macbuf, MACSIZE); i += BLOCKSIZE; } t = clock() - t; printf("%f Mbyte per second decrypt and MAC %d-byte blocks %d-bit MAC\n", (((double)i/((double)t / (double)CLOCKS_PER_SEC))) / 1000000.0, BLOCKSIZE, MACSIZE*8); /* test key setup time */ t = clock(); for (i = 0; i < 10000000; ++i) { k[3] = i; nls_key(&ctx, (UCHAR *)k, 16); } t = clock() - t; printf("%f million 128-bit keys per second\n", (((double)i/((double)t / (double)CLOCKS_PER_SEC))) / 1000000.0); /* test nonce setup time */ t = clock(); for (i = 0; i < 10000000; ++i) { k[3] = i; nls_nonce(&ctx, (UCHAR *)k, 16); } t = clock() - t; printf("%f million 128-bit nonces per second\n", (((double)i/((double)t / (double)CLOCKS_PER_SEC))) / 1000000.0); } int main(int ac, char **av) { int n, i; int vflag = 0; UCHAR key[32], nonce[32]; int keysz, noncesz; extern int keylen; extern WORD K[]; if (ac >= 2 && strcmp(av[1], "-verbose") == 0) { vflag = 1; v = vflag; ++av, --ac; } if (ac == 2 && strcmp(av[1], "-test") == 0) { test_sss(0); return nerrors; } if (ac == 2 && strcmp(av[1], "-time") == 0) { time_sss(); return 0; } if (ac >= 2) hexread(key, av[1], keysz = strlen(av[1]) / 2); else hexread(key, "0000000000000000", keysz = 8); if (ac >= 3) hexread(nonce, av[2], noncesz = strlen(av[2]) / 2); else noncesz = 0; sscanf(ac >= 4 ? av[3] : "1000000", "%d", &n); if ((keysz | noncesz) & 0x3) { fprintf(stderr, "Key and nonce must be multiple of 4 bytes\n"); return 1; } nls_key(&ctx, key, keysz); nls_nonce(&ctx, nonce, noncesz); if (vflag) { printLFSR("Initial LFSR", ctx.initR); } while (n > 0) { i = sizeof bigbuf; i = n > i ? i : n; nls_stream(&ctx, bigbuf, i); hexbulk(bigbuf, i); n -= i; } return 0; }