/* Copyright 2001,2002 Roger Dingledine, Matej Pfajfar. */ /* See LICENSE for licensing information */ /* $Id$ */ #include #include #include "or.h" #include "../common/test.h" void setup_directory() { char buf[256]; sprintf(buf, "/tmp/tor_test"); if (mkdir(buf, 0700) && errno != EEXIST) fprintf(stderr, "Can't create directory %s", buf); } void test_buffers() { char str[256]; char str2[256]; char *buf; int buflen, buf_datalen; char *buf2; int buf2len, buf2_datalen; int s, i, j, eof; z_compression *comp; z_decompression *decomp; /**** * buf_new ****/ if (buf_new(&buf, &buflen, &buf_datalen)) test_fail(); test_eq(buflen, MAX_BUF_SIZE); test_eq(buf_datalen, 0); /**** * read_to_buf ****/ s = open("/tmp/tor_test/data", O_WRONLY|O_CREAT|O_TRUNC, 0600); for (j=0;j<256;++j) { str[j] = (char)j; } write(s, str, 256); close(s); s = open("/tmp/tor_test/data", O_RDONLY, 0); eof = 0; i = read_to_buf(s, 10, &buf, &buflen, &buf_datalen, &eof); test_eq(buflen, MAX_BUF_SIZE); test_eq(buf_datalen, 10); test_eq(eof, 0); test_eq(i, 10); test_memeq(str, buf, 10); /* Test reading 0 bytes. */ i = read_to_buf(s, 0, &buf, &buflen, &buf_datalen, &eof); test_eq(buflen, MAX_BUF_SIZE); test_eq(buf_datalen, 10); test_eq(eof, 0); test_eq(i, 0); /* Now test when buffer is filled exactly. */ buflen = 16; i = read_to_buf(s, 6, &buf, &buflen, &buf_datalen, &eof); test_eq(buflen, 16); test_eq(buf_datalen, 16); test_eq(eof, 0); test_eq(i, 6); test_memeq(str, buf, 16); /* Now test when buffer is filled with more data to read. */ buflen = 32; i = read_to_buf(s, 128, &buf, &buflen, &buf_datalen, &eof); test_eq(buflen, 32); test_eq(buf_datalen, 32); test_eq(eof, 0); test_eq(i, 16); test_memeq(str, buf, 32); /* Now read to eof. */ buflen = MAX_BUF_SIZE; test_assert(buflen > 256); i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof); test_eq(i, (256-32)); test_eq(buflen, MAX_BUF_SIZE); test_eq(buf_datalen, 256); test_memeq(str, buf, 256); test_eq(eof, 0); i = read_to_buf(s, 1024, &buf, &buflen, &buf_datalen, &eof); test_eq(i, 0); test_eq(buflen, MAX_BUF_SIZE); test_eq(buf_datalen, 256); test_eq(eof, 1); close(s); /**** * find_on_inbuf ****/ test_eq(((int)'d') + 1, find_on_inbuf("abcd", 4, buf, buf_datalen)); test_eq(-1, find_on_inbuf("xyzzy", 5, buf, buf_datalen)); /* Make sure we don't look off the end of the buffef */ buf[256] = 'A'; buf[257] = 'X'; test_eq(-1, find_on_inbuf("\xff" "A", 2, buf, buf_datalen)); test_eq(-1, find_on_inbuf("AX", 2, buf, buf_datalen)); /* Make sure we use the string length */ test_eq(((int)'d')+1, find_on_inbuf("abcdX", 4, buf, buf_datalen)); /**** * fetch_from_buf ****/ memset(str2, 255, 256); test_eq(246, fetch_from_buf(str2, 10, &buf, &buflen, &buf_datalen)); test_memeq(str2, str, 10); test_memeq(str+10,buf,246); test_eq(buf_datalen,246); test_eq(-1, fetch_from_buf(str2, 247, &buf, &buflen, &buf_datalen)); test_memeq(str+10,buf,246); test_eq(buf_datalen, 246); test_eq(0, fetch_from_buf(str2, 246, &buf, &buflen, &buf_datalen)); test_memeq(str2, str+10, 246); test_eq(buflen,MAX_BUF_SIZE); test_eq(buf_datalen,0); /**** * write_to_buf ****/ memset(buf, (int)'-', 256); i = write_to_buf("Hello world", 11, &buf, &buflen, &buf_datalen); test_eq(i, 11); test_eq(buf_datalen, 11); test_memeq(buf, "Hello world", 11); i = write_to_buf("XYZZY", 5, &buf, &buflen, &buf_datalen); test_eq(i, 16); test_eq(buf_datalen, 16); test_memeq(buf, "Hello worldXYZZY", 16); /* Test when buffer is overfull. */ buflen = 18; test_eq(-1, write_to_buf("This string will not fit.", 25, &buf, &buflen, &buf_datalen)); test_eq(buf_datalen, 16); test_memeq(buf, "Hello worldXYZZY--", 18); buflen = MAX_BUF_SIZE; /**** * flush_buf ****/ /* XXXX Needs tests. */ /*** * compress_from_buf (simple) ***/ buf_datalen = 0; comp = compression_new(); for (i = 0; i < 20; ++i) { write_to_buf("Hello world. ", 14, &buf, &buflen, &buf_datalen); } i = compress_from_buf(str, 256, &buf, &buflen, &buf_datalen, comp, Z_SYNC_FLUSH); test_eq(buf_datalen, 0); /* for (j = 0; j 0; i -= 35) strncat(data1, "Now is the time for all good onions", i); for(i=0; str_ciphers[i] >= 0; ++i) { /* For each cipher... */ memset(data2, 0, 1024); memset(data3, 0, 1024); env1 = crypto_new_cipher_env(str_ciphers[i]); test_neq(env1, 0); env2 = crypto_new_cipher_env(str_ciphers[i]); test_neq(env2, 0); j = crypto_cipher_generate_key(env1); if (str_ciphers[i] != CRYPTO_CIPHER_IDENTITY) { crypto_cipher_set_key(env2, env1->key); } crypto_cipher_set_iv(env1, "12345678901234567890"); crypto_cipher_set_iv(env2, "12345678901234567890"); crypto_cipher_encrypt_init_cipher(env1); crypto_cipher_decrypt_init_cipher(env2); /* Try encrypting 512 chars. */ crypto_cipher_encrypt(env1, data1, 512, data2); crypto_cipher_decrypt(env2, data2, 512, data3); test_memeq(data1, data3, 512); if (str_ciphers[i] == CRYPTO_CIPHER_IDENTITY) { test_memeq(data1, data2, 512); } else { test_memneq(data1, data2, 512); } /* Now encrypt 1 at a time, and get 1 at a time. */ for (j = 512; j < 560; ++j) { crypto_cipher_encrypt(env1, data1+j, 1, data2+j); } for (j = 512; j < 560; ++j) { crypto_cipher_decrypt(env2, data2+j, 1, data3+j); } test_memeq(data1, data3, 560); /* Now encrypt 3 at a time, and get 5 at a time. */ for (j = 560; j < 1024; j += 3) { crypto_cipher_encrypt(env1, data1+j, 3, data2+j); } for (j = 560; j < 1024; j += 5) { crypto_cipher_decrypt(env2, data2+j, 5, data3+j); } test_memeq(data1, data3, 1024-4); /* Now make sure that when we encrypt with different chunk sizes, we get the same results. */ crypto_free_cipher_env(env2); memset(data3, 0, 1024); env2 = crypto_new_cipher_env(str_ciphers[i]); test_neq(env2, 0); if (str_ciphers[i] != CRYPTO_CIPHER_IDENTITY) { crypto_cipher_set_key(env2, env1->key); } crypto_cipher_set_iv(env2, "12345678901234567890"); crypto_cipher_encrypt_init_cipher(env2); for (j = 0; j < 1024-16; j += 17) { crypto_cipher_encrypt(env2, data1+j, 17, data3+j); } for (j= 0; j < 1024-16; ++j) { if (data2[j] != data3[j]) { printf("%d: %d\t%d\n", j, (int) data2[j], (int) data3[j]); } } test_memeq(data2, data3, 1024-16); crypto_free_cipher_env(env1); crypto_free_cipher_env(env2); } /* Test vectors for stream ciphers. */ /* XXXX Look up some test vectors for the ciphers and make sure we match. */ /* Test SHA-1 with a test vector from the specification. */ i = crypto_SHA_digest("abc", 3, data1); test_memeq(data1, "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78" "\x50\xC2\x6C\x9C\xD0\xD8\x9D", 20); /* Public-key ciphers */ pk1 = crypto_new_pk_env(CRYPTO_PK_RSA); pk2 = crypto_new_pk_env(CRYPTO_PK_RSA); test_assert(pk1 && pk2); test_assert(! crypto_pk_generate_key(pk1)); test_assert(! crypto_pk_write_public_key_to_string(pk1, &cp, &i)); test_assert(! crypto_pk_read_public_key_from_string(pk2, cp, i)); test_eq(0, crypto_pk_cmp_keys(pk1, pk2)); test_eq(128, crypto_pk_keysize(pk1)); test_eq(128, crypto_pk_keysize(pk2)); test_eq(128, crypto_pk_public_encrypt(pk2, "Hello whirled.", 15, data1, RSA_PKCS1_OAEP_PADDING)); test_eq(128, crypto_pk_public_encrypt(pk1, "Hello whirled.", 15, data2, RSA_PKCS1_OAEP_PADDING)); /* oaep padding should make encryption not match */ test_memneq(data1, data2, 128); test_eq(15, crypto_pk_private_decrypt(pk1, data1, 128, data3, RSA_PKCS1_OAEP_PADDING)); test_streq(data3, "Hello whirled."); memset(data3, 0, 1024); test_eq(15, crypto_pk_private_decrypt(pk1, data2, 128, data3, RSA_PKCS1_OAEP_PADDING)); test_streq(data3, "Hello whirled."); /* Can't decrypt with public key. */ test_eq(-1, crypto_pk_private_decrypt(pk2, data2, 128, data3, RSA_PKCS1_OAEP_PADDING)); /* Try again with bad padding */ memcpy(data2+1, "XYZZY", 5); /* This has fails ~ once-in-2^40 */ test_eq(-1, crypto_pk_private_decrypt(pk1, data2, 128, data3, RSA_PKCS1_OAEP_PADDING)); /* File operations: save and load private key */ f = fopen("/tmp/tor_test/pkey1", "wb"); test_assert(! crypto_pk_write_private_key_to_file(pk1, f)); fclose(f); f = fopen("/tmp/tor_test/pkey1", "rb"); test_assert(! crypto_pk_read_private_key_from_file(pk2, f)); fclose(f); test_eq(15, crypto_pk_private_decrypt(pk2, data1, 128, data3, RSA_PKCS1_OAEP_PADDING)); test_assert(! crypto_pk_read_private_key_from_filename(pk2, "/tmp/tor_test/pkey1")); test_eq(15, crypto_pk_private_decrypt(pk2, data1, 128, data3, RSA_PKCS1_OAEP_PADDING)); crypto_free_pk_env(pk1); crypto_free_pk_env(pk2); free(data1); free(data2); free(data3); } void test_util() { struct timeval start, end; start.tv_sec = 5; start.tv_usec = 5000; end.tv_sec = 5; end.tv_usec = 5000; test_eq(0L, tv_udiff(&start, &end)); end.tv_usec = 7000; test_eq(2000L, tv_udiff(&start, &end)); end.tv_sec = 6; test_eq(1002000L, tv_udiff(&start, &end)); end.tv_usec = 0; test_eq(995000L, tv_udiff(&start, &end)); end.tv_sec = 4; test_eq(0L, tv_udiff(&start, &end)); } void test_onion_handshake() { int i; /* client-side */ crypto_dh_env_t *c_dh = NULL; char c_buf[DH_ONIONSKIN_LEN]; char c_keys[40]; /* server-side */ char s_buf[DH_KEY_LEN]; char s_keys[40]; /* shared */ crypto_pk_env_t *pk = NULL; pk = crypto_new_pk_env(CRYPTO_PK_RSA); test_assert(! crypto_pk_generate_key(pk)); /* client handshake 1. */ memset(c_buf, 0, DH_ONIONSKIN_LEN); test_assert(! onion_skin_create(pk, &c_dh, c_buf)); /* server handshake */ memset(s_buf, 0, DH_KEY_LEN); memset(s_keys, 0, 40); test_assert(! onion_skin_server_handshake(c_buf, pk, s_buf, s_keys, 40)); /* client handshake 2 */ memset(c_keys, 0, 40); test_assert(! onion_skin_client_handshake(c_dh, s_buf, c_keys, 40)); crypto_dh_free(c_dh); crypto_free_pk_env(pk); test_memeq(c_keys, s_keys, 40); memset(s_buf, 0, 40); test_memneq(c_keys, s_buf, 40); } int main(int c, char**v) { #if 0 or_options_t options; /* command-line and config-file options */ if(getconfig(c,v,&options)) exit(1); #endif log(LOG_ERR,NULL); /* make logging quieter */ setup_directory(); puts("========================== Buffers ========================="); test_buffers(); puts("========================== Crypto =========================="); test_crypto_dh(); test_crypto(); puts("\n========================= Util ============================"); test_util(); puts("\n========================= Onion Skins======================"); test_onion_handshake(); puts(""); return 0; } /* Local Variables: mode:c indent-tabs-mode:nil c-basic-offset:2 End: */