#include #include #include #include #include #include #include #include #include #include #include //inet_addr #include //hostent /****************************************************************************/ /*************************** OpenSocketClient *******************************/ /****************************************************************************/ // Open the socket to the server. void OpenSocketClient(int str_length, char server_IP[str_length], int port_number, int *server_socket_desc_ptr) { struct sockaddr_in server_addr; printf("OpenSocketClient(): Creating a socket\n"); fflush(stdout); if ( (*server_socket_desc_ptr = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { printf("OpenSocketClient(): ERROR: Could not create socket"); fflush(stdout); } server_addr.sin_addr.s_addr = inet_addr(server_IP); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(port_number); memset(server_addr.sin_zero, 0, 8); // Connect to it. if ( connect(*server_socket_desc_ptr, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0 ) { printf("OpenSocketClient: Connect\n"); fflush(stdout); exit(EXIT_FAILURE); } printf("OpenSocketClient(): Connected\n"); fflush(stdout); } /****************************************************************************/ /******************************** SockGetB **********************************/ /****************************************************************************/ // This function is designed to buffer data but in kernel space. It allows // binary data to be transmitted. To accomplish this, the first two bytes are // interpreted as the length of the binary byte stream that follows. int SockGetB(unsigned char *buffer, int buffer_size, int socket_desc) { int tot_bytes_received, target_num_bytes; char buffer_num_bytes[3]; // Call until two bytes are returned. The 2-byte buffer represents a number that is to be interpreted as the exact // number of binary bytes that will follow in the socket. target_num_bytes = 2; tot_bytes_received = 0; while ( tot_bytes_received < target_num_bytes ) if ( (tot_bytes_received += recv(socket_desc, &buffer_num_bytes[tot_bytes_received], target_num_bytes - tot_bytes_received, 0)) < 0 ) { printf("ERROR: SockGetB(): Error in receiving two byte cnt!\n"); fflush(stdout); return -1; } // Translate the two binary bytes into an integer. target_num_bytes = (int)(buffer_num_bytes[1] << 8) + (int)buffer_num_bytes[0]; // DEBUG //printf("SockGetB(): fetching %d bytes from socket\n", target_num_bytes); fflush(stdout); // Sanity check. if ( target_num_bytes > buffer_size ) { printf("ERROR: SockGetB(): 'target_num_bytes' %d is larger than buffer input size %d\n", target_num_bytes, buffer_size); fflush(stdout); return -1; } // Now start reading binary bytes from the socket tot_bytes_received = 0; while ( tot_bytes_received < target_num_bytes ) if ( (tot_bytes_received += recv(socket_desc, &buffer[tot_bytes_received], target_num_bytes - tot_bytes_received, 0)) < 0 ) { printf("ERROR: SockGetB(): Error in receiving transmitted data!\n"); fflush(stdout); return -1; } // Sanity check if ( tot_bytes_received != target_num_bytes ) { printf("ERROR: SockGetB(): Read more bytes then requested -- 'tot_bytes_received' %d is larger than target %d\n", tot_bytes_received, target_num_bytes); fflush(stdout); return -1; } // DEBUG //printf("SockGetB(): received %d bytes\n", tot_bytes_received); fflush(stdout); return tot_bytes_received; } /****************************************************************************/ /******************************* SockSendB **********************************/ /****************************************************************************/ // This function sends binary or ASCII data of 'buffer_size' unsigned characters // through the socket. It first sends two binary bytes that represent the length // of the binary or ASCII byte stream that follows. int SockSendB(unsigned char *buffer, int buffer_size, int socket_desc) { unsigned char num_bytes[2]; // Sanity check. Don't yet support transfers larger than 65,536 bytes. if ( buffer_size > 65535 ) { printf("ERROR: SockSendB(): Size of buffer %d larger than max (65536)!\n", buffer_size); fflush(stdout); return -1; } num_bytes[1] = (unsigned char)((buffer_size & 0x0000FF00) >> 8); num_bytes[0] = (unsigned char)(buffer_size & 0x000000FF); if ( send(socket_desc, num_bytes, 2, 0) < 0 ) { printf("ERROR: SockSendB(): Send 'num_bytes' %d failed\n", buffer_size); fflush(stdout); return -1; } if ( send(socket_desc, buffer, buffer_size, 0) < 0 ) { printf("ERROR: SockSendB(): Send failed\n"); fflush(stdout); return -1; } return 0; } /****************************************************************************/ /************************** ReadVectorPairFile ******************************/ /****************************************************************************/ // Reads in the vector file. Format is first vector/second vector on two separate // lines, followed by a blank line, then repeat. Space for first_vecs and // second_vecs is allocated in the caller. int ReadVectorPairFile(int str_length, char *vec_pair_path, int max_vecs, int vec_len_bits, int *num_rise_vecs_ptr, unsigned char *first_vecs_b[max_vecs], unsigned char *second_vecs_b[max_vecs]) { int first_second_vec, vc, is_rising, is_falling, rise_or_fall; char first_vec[vec_len_bits+1], second_vec[vec_len_bits+1]; int byte_cnter, bit_cnter, mod_8_val; char line[str_length], *char_ptr; unsigned char *vec_ptr; int vec_pair_cnt; FILE *INFILE; if ( (INFILE = fopen(vec_pair_path, "r")) == NULL ) { printf("ERROR: ReadVectorPairFile(): Could not open VectorPair file %s\n", vec_pair_path); fflush(stdout); exit(EXIT_FAILURE); } // Sanity check. Make sure 'vec_len_bits' is evenly divisible by 8 otherwise the binary conversion routine below will NOT work. if ( (vec_len_bits % 8) != 0 ) { printf("ERROR: ReadVectorPairFile(): 'vec_len_bits %d MUST be divisible by 8!\n", vec_len_bits); fflush(stdout); exit(EXIT_FAILURE); } vec_pair_cnt = 0; first_second_vec = 0; *num_rise_vecs_ptr = 0; rise_or_fall = -1; while ( fgets(line, str_length, INFILE) != NULL ) { /* Find the newline and eliminate it. */ if ((char_ptr = strrchr(line, '\n')) != NULL) *char_ptr = '\0'; // Assume there is NO blank line as the first line in the file, and assume the last line is present but blank if ( strlen(line) == 0 ) { vec_pair_cnt++; continue; } // Sanity check if ( vec_pair_cnt >= max_vecs ) { printf("ERROR: ReadVectorPairFile(): Exceeded maximum number of vectors %d!\n", max_vecs); fflush(stdout); exit(EXIT_FAILURE); } // Sanity checks if ( strlen(line) != vec_len_bits ) { printf("ERROR: ReadVectorPairFile(): Unexpected vector size %d -- expected %d!\n", (int)strlen(line), vec_len_bits); fflush(stdout); exit(EXIT_FAILURE); } // Copy the first ASCII version of the vector into the stack allocated space + 1 (for NULL termination). if ( first_second_vec == 0 ) strcpy(first_vec, line); else { strcpy(second_vec, line); // Assume the vectors are constructed to be rising only or falling only. Find a transition in the vector pair that indicates rising, i.e., // 0 in first vector and 1 in second vector at that same position. vc = 0; is_rising = 0; is_falling = 0; while ( first_vec[vc] != '\0' ) { // Sanity check. if ( second_vec[vc] == '\0' ) { printf("ERROR: ReadVectorPairFile(): Vector pair at %d NOT the same length!\n", vec_pair_cnt); fflush(stdout); exit(EXIT_FAILURE); } // Count 1 for rising on the first rising transition. if ( first_vec[vc] == '0' && second_vec[vc] == '1' ) { // Check that we are not intermixing rising and falling vectors. If this is ever 1, then we processed a falling vector on a previous iteration, // which is an error. This requires rising vectors to preceed falling vectors. if ( rise_or_fall == 1 ) { printf("ERROR: ReadVectorPairFile(): Intermixing of rising and falling vectors illegal!\n"); fflush(stdout); exit(EXIT_FAILURE); } rise_or_fall = 0; // Error if both transitions are present. if ( is_falling == 1 ) { printf("ERROR: ReadVectorPairFile(): Found vector %d with BOTH rising and falling transitions!\n", vec_pair_cnt); fflush(stdout); exit(EXIT_FAILURE); } // Only count this vector as rising on the first occurance of a rising edge. if ( is_rising == 0 ) (*num_rise_vecs_ptr)++; is_rising = 1; } // Same check for falling transitions if ( first_vec[vc] == '1' && second_vec[vc] == '0' ) { // Indicate that we are processing falling vectors. if ( rise_or_fall == -1 ) { printf("ERROR: ReadVectorPairFile(): Expected rising vectors to be first in vector file!\n"); fflush(stdout); exit(EXIT_FAILURE); } rise_or_fall = 1; // Error if both transitions are present. if ( is_rising == 1 ) { printf("ERROR: ReadVectorPairFile(): Found vector %d with BOTH rising and falling transitions!\n", vec_pair_cnt); fflush(stdout); exit(EXIT_FAILURE); } is_falling = 1; } vc++; } } // Allocate space for binary unsigned char version of vectors. if ( first_second_vec == 0 ) { first_vecs_b[vec_pair_cnt] = (unsigned char *)malloc(sizeof(char)*vec_len_bits/8); vec_ptr = first_vecs_b[vec_pair_cnt]; } else { second_vecs_b[vec_pair_cnt] = (unsigned char *)malloc(sizeof(char)*vec_len_bits/8); vec_ptr = second_vecs_b[vec_pair_cnt]; } // DEBUG //printf("ReadVectorPairFile(): Binary vec for vec_pair_cnt %d\n\t", vec_pair_cnt); fflush(stdout); // Convert from ASCII to binary. ASCII version of vector processed from 0 to 'vec_len_bits' is high order to low order. Preserve // this characteristics in the unsigned char binary byte array by starting the load at the highest byte. NOTE: 'vec_len_bits' // MUST BE DIVISIBLE BY 8 otherwise this code does not work properly -- checked above. byte_cnter = vec_len_bits/8 - 1; for ( bit_cnter = 0; bit_cnter < vec_len_bits; ) { // Sanity check if ( byte_cnter < 0 ) { printf("ERROR: ReadVectorPairFile(): Program error: 'byte_cnter' %d is LESS THAN 0!\n", byte_cnter); fflush(stdout); exit(EXIT_FAILURE); } mod_8_val = bit_cnter % 8; if ( mod_8_val == 0 ) vec_ptr[byte_cnter] = 0; // Keep adding in bits to the current byte at the appropriate bit position in the byte. Left to right processing of // the line needs to make the first (left-most) ASCII bit n the line, the high order bit in the binary byte, i.e., // preserve the high-order to low-order property of the vector ASCII line. if ( line[bit_cnter] == '1' ) vec_ptr[byte_cnter] += (unsigned char)(1 << (7 - mod_8_val)); bit_cnter++; if ( (bit_cnter % 8) == 0 ) { // DEBUG //printf("%02X ", vec_ptr[byte_cnter]); fflush(stdout); byte_cnter--; } } // DEBUG //printf("\n"); fflush(stdout); // Each non-zero line has a vector, invert first or second vector indicator and add 1 to vec_pair_cnt first_second_vec = !first_second_vec; } printf("Number of rising vectors %d\n", *num_rise_vecs_ptr); fflush(stdout); return vec_pair_cnt; } /****************************************************************************/ /******************************* SendVectors ********************************/ /****************************************************************************/ // Send num_vecs and vector pairs to the token for ID phase enrollment. void SendVectors(int str_length, int num_vecs, int max_vecs, int token_socket_desc, int num_rise_vecs, int vec_len_bits, unsigned char *first_vecs_b[max_vecs], unsigned char *second_vecs_b[max_vecs]) { char num_vecs_str[str_length]; int i; // Send num_vecs first. sprintf(num_vecs_str, "%d %d", num_vecs, num_rise_vecs); // Send num_bytes of string as two-binary bytes. When sending ASCII character strings, be sure to add one to include // the NULL termination character (+ 1) so the receiver can treat this as a string. if ( SockSendB((unsigned char *)num_vecs_str, strlen(num_vecs_str) + 1, token_socket_desc) < 0 ) { fprintf(stderr, "ERROR: SendVectors(): Send '%s' failed\n", num_vecs_str); fflush(stderr); exit(EXIT_FAILURE); } // Send first_vecs and second_vecs to remote server for ( i = 0; i < num_vecs; i++ ) { if ( SockSendB(first_vecs_b[i], vec_len_bits/8, token_socket_desc) < 0 ) { fprintf(stderr, "ERROR: SendVectors(): Send 'first_vecs_b[%d]' failed\n", i); fflush(stderr); exit(EXIT_FAILURE); } if ( SockSendB(second_vecs_b[i], vec_len_bits/8, token_socket_desc) < 0 ) { fprintf(stderr, "ERROR: SendVectors(): Send 'second_vecs_b[%d]' failed\n", i); fflush(stderr); exit(EXIT_FAILURE); } } // DEBUG printf("SendVectors(): Sent %d vector pairs!\n", num_vecs); fflush(stdout); return; } /****************************************************************************/ /*************************** ReceiveTimingVals ******************************/ /****************************************************************************/ // Receive timing values and write them to an outfile. void ReceiveTimingVals(int str_length, int token_socket_desc) { char outfile_name[str_length]; char buffer[str_length]; FILE *OUTFILE; // Received outfile_name. if ( SockGetB((unsigned char *)outfile_name, str_length, token_socket_desc) < 0 ) { printf("ERROR: ReceiveTimingVals(): Error receiving outfile_name '%s'\n", outfile_name); fflush(stdout); exit(EXIT_FAILURE); } printf("ReceiveTimingVals(): Saving values to '%s'\n", outfile_name); fflush(stdout); // Open output file and write the outfile_name info into it. if ( (OUTFILE = fopen(outfile_name, "w")) == NULL ) { printf("ERROR: ReceiveTimingVals(): Could NOT open output filename '%s'\n", outfile_name); fflush(stdout); exit(EXIT_FAILURE); } // Receive timing values and write them into the OUTFILE. while (1) { if ( SockGetB((unsigned char *)buffer, str_length, token_socket_desc) < 0 ) { printf("ERROR: ReceiveTimingVals(): Error receiving timing value line\n"); fflush(stdout); exit(EXIT_FAILURE); } if ( strcmp(buffer, "DONE") == 0 ) { // Write a final in output file. fprintf(OUTFILE, "\n"); break; } fprintf(OUTFILE, "%s\n", buffer); } fclose(OUTFILE); return; } /************************************************************************************/ /************************************** Main ****************************************/ /************************************************************************************/ // For enrollment, the token is the 'server' while the verifier is the 'client' #define MAX_STRING_LEN 2000 #define MAX_VECS 1500 #define VEC_LEN_BITS 416 #define MAX_TIMING_VALS 100000 unsigned char *first_vecs_b[MAX_VECS]; unsigned char *second_vecs_b[MAX_VECS]; int main(int argc , char *argv[]) { char token_IP[MAX_STRING_LEN]; char vec_file_name[MAX_STRING_LEN]; int num_vecs, num_rise_vecs; // Prepare the sockaddr_in structure for the server; int token_socket_desc = 0; int port_number; // =============================================================================== // COMMAND LINE. if ( argc != 3 ) { printf("ERROR: client_socket_bind.c: token_IP ---- vec_file_name (keccak_.....) \n"); fflush(stdout); exit(EXIT_FAILURE); } strcpy(token_IP, argv[1]); strcpy(vec_file_name, argv[2]); // ============================================ PARAMETERS ===================================================== port_number = 8888; // ============================================ PARAMETERS ===================================================== // ReadVectorPairFile and store them in the first_vecs[MAX_VECS] and second_vecs[MAX_VECS] num_vecs = ReadVectorPairFile(MAX_STRING_LEN, vec_file_name, MAX_VECS, VEC_LEN_BITS, &num_rise_vecs, first_vecs_b, second_vecs_b); // Connect to the socket that is created by the token. OpenSocketClient(MAX_STRING_LEN, token_IP, port_number, &token_socket_desc); // Send num_vecs and vector pairs to the token. SendVectors(MAX_STRING_LEN, num_vecs, MAX_VECS, token_socket_desc, num_rise_vecs, VEC_LEN_BITS, first_vecs_b, second_vecs_b); // Receive timing values from token write to an output file. ReceiveTimingVals(MAX_STRING_LEN, token_socket_desc); close(token_socket_desc); return 0; }