void atm_process_command(ATM *atm, char *command) { unsigned char recvline[1025 + 16 + EVP_MAX_BLOCK_LENGTH], sendline[1025 + 16 + EVP_MAX_BLOCK_LENGTH]; unsigned char enc_in[1024], dec_in[1025 + EVP_MAX_BLOCK_LENGTH]; unsigned char *digest, rec_digest[129], *outbuf, iv[16]; char username[251], *cmd_arg, *arg, user_card_filename[256], pin_in[10], message[1025]; char cardkey[33], username_cardkey[33]; int input_error = 1, username_pin, pin, ret, cmd_pos = 0, pos = 0, amt, int_arg, n=0; int crypt_len, in_len, digest_len; User *current_user; FILE *card; time_t t, start; cmd_arg = malloc(251); arg = malloc(251); outbuf = malloc(1025 + EVP_MAX_BLOCK_LENGTH); digest = malloc(129); //clear strings sendline[0] = 0; outbuf[0] = 0; enc_in[0] = 0; ret = get_ascii_arg(command, pos, &cmd_arg); cmd_pos += ret + 1; if (strcmp(cmd_arg, "begin-session") == 0){ //get username if(atm->logged_in){ printf("A user is already logged in\n"); return; } pos = cmd_pos; ret = get_letter_arg(command, pos, &arg); if (ret > 0 && ret <= 250){ pos += ret + 1; memcpy(username, arg, ret); username[ret] = 0; //should be no more args if(get_ascii_arg(command, pos, &arg) != 0){ printf("Usage: begin-session <user-name>\n"); return; } //send request to bank for User username // Write message sprintf(message, "%lu authenticate-user %s",atm->counter++, username); // Compute Digest digest_len = do_digest(message, &digest); // To encrypt: digest_len digest message sprintf(enc_in, "%s %s", digest, message); //null bytes seem to screw things up so try until no null bytes do{ do{ RAND_bytes(iv, sizeof(iv)); } while(strlen(iv) < 16); crypt_len = do_crypt(enc_in, strlen(enc_in), 1, atm->key, iv, &outbuf); } while (strlen(outbuf) != crypt_len || crypt_len == 0); //concat iv and outbuf strncat(sendline, iv, sizeof(iv)); strncat(sendline, outbuf, crypt_len); atm_send(atm, sendline, crypt_len + sizeof(iv)); //process response from bank n = atm_recv(atm,recvline, 1024 + EVP_MAX_BLOCK_LENGTH); if(n < 0 ){ printf("Communication error occurred. Please try again.\n"); return; } recvline[n]=0; //clear strings outbuf[0] = 0; dec_in[0] = 0; //first 16 bytes are iv, rest is cipher to decrypt memcpy(iv, recvline, sizeof(iv)); in_len = n - sizeof(iv); memcpy(dec_in, recvline + sizeof(iv), in_len); dec_in[in_len] = 0; //decrypt cipher crypt_len = do_crypt(dec_in, in_len, 0, atm->key, iv, &outbuf); //first 64 characters are digest, rest is message memcpy(rec_digest, outbuf, 128); rec_digest[128]=0; memcpy(message, outbuf+129, crypt_len - 129); message[crypt_len - 129] = 0; //do_digest on message and verify it matches sent digest digest_len = do_digest(message, &digest); digest[128]=0; if(strcmp(digest, rec_digest) != 0){ printf("Digests don't match, message was tampered with. Ignorning...\n"); return; } //check counter pos = 0; ret = get_digit_arg(message, pos, &int_arg); pos += ret + 1; if(int_arg < atm->counter){ //Atm got message with an invalid counter. Ignoring... return; } atm->counter = int_arg + 1; //process response ret = get_ascii_arg(message, pos, &arg); if(ret<= 0 ){ //shouldn't happen bc verifying digest return; } else{ if(strcmp("found", arg) == 0){ pos += ret + 1; //username atm->current_username = malloc(251); ret = get_letter_arg(message, pos, &arg); pos += ret + 1; strncpy(atm->current_username, arg, strlen(arg)); atm->current_username[strlen(arg)]=0; //pin ret = get_digit_arg(message, pos, &int_arg); pos += ret + 1; username_pin = int_arg; //card memcpy(username_cardkey, message+pos, 32); username_cardkey[32]=0; //look for the card file and check can read sprintf(user_card_filename,"%s.card", atm->current_username); card = fopen(user_card_filename, "r"); if(card == NULL){ printf("Unable to access %s's card - null card\n", atm->current_username); return; } ret = fread(cardkey, 1, sizeof(cardkey), card); cardkey[32]=0; if(strncmp(cardkey, username_cardkey, sizeof(username_cardkey)) != 0){ printf("Unable to access %s's card - cardkey mismatch\n", atm->current_username); return; } //prompt for pin printf("PIN? "); fgets(pin_in, 10, stdin); pos = 0; ret = get_digit_arg(pin_in, pos, &int_arg); pin = int_arg; pos += ret + 1; if(pin != username_pin || get_ascii_arg(pin_in, pos, &arg)){ printf("Not Authorized\n"); //If 3 failed attempts in 30 seconds, shut down if((time(&t) - atm->fail_time1) <= 30){ printf("There have been 3 failed login attempts in the past 30 seconds.\nPlease wait 2 minutes before trying again.\n"); sleep(120); } else{ atm->fail_time1 = atm->fail_time2; atm->fail_time2 = time(&t); } return; } else{ printf("Authorized\n"); atm->logged_in=1; atm->current_user = current_user; return; } } else if(strcmp("not-found", arg) == 0){ printf("No such user\n"); return; } } } else{ printf("Usage: begin-sesion <user-name>\n"); } } //Withdraw else if (strcmp(cmd_arg, "withdraw") == 0){ if(!atm->logged_in){ printf("No user logged in\n"); return; } //get amt from user input pos = cmd_pos; ret = get_digit_arg(command, pos, &int_arg); if (ret > 0){ amt = int_arg; pos += ret + 1; //should be no more args if(get_ascii_arg(command, pos, &arg) == 0){ // Write message sprintf(message, "%lu withdraw %s %d",atm->counter++, atm->current_username, amt); // Compute Digest digest_len = do_digest(message, &digest); // To encrypt: digest_len digest message sprintf(enc_in, "%s %s", digest, message); //null bytes seem to screw things up so try until no null bytes do{ do{ RAND_bytes(iv, sizeof(iv)); } while(strlen(iv) < 16); crypt_len = do_crypt(enc_in, strlen(enc_in), 1, atm->key, iv, &outbuf); } while (strlen(outbuf) != crypt_len || crypt_len == 0); //concat iv and outbuf strncat(sendline, iv, sizeof(iv)); strncat(sendline, outbuf, crypt_len); atm_send(atm, sendline, crypt_len + sizeof(iv)); //process response from bank n = atm_recv(atm,recvline, 1024 + EVP_MAX_BLOCK_LENGTH); if(n < 0 ){ printf("Communication error occurred. Please try again.\n"); return; } recvline[n]=0; //clear sendline and outbuf outbuf[0] = 0; dec_in[0] = 0; //first 16 bytes are iv, rest is cipher to decrypt memcpy(iv, recvline, sizeof(iv)); in_len = n - sizeof(iv); memcpy(dec_in, recvline + sizeof(iv), in_len); dec_in[in_len] = 0; //decrypt cipher crypt_len = do_crypt(dec_in, in_len, 0, atm->key, iv, &outbuf); //first 64 characters are digest, rest is message memcpy(rec_digest, outbuf, 128); rec_digest[128]=0; memcpy(message, outbuf+129, crypt_len - 129); message[crypt_len - 129] = 0; //do_digest on message and verify it matches sent digest digest_len = do_digest(message, &digest); digest[128]=0; if(strcmp(digest, rec_digest) != 0){ printf("Digests don't match, message was tampered with. Ignorning...\n"); return; } //check counter pos = 0; ret = get_digit_arg(message, pos, &int_arg); pos += ret + 1; if(int_arg < atm->counter){ //ATM got message with an invalid counter. Ignoring... return; } atm->counter = int_arg + 1; //process response ret = get_ascii_arg(message, pos, &arg); if(strcmp(arg, "success") == 0) printf("$%d dispensed\n", amt); else if (strcmp(arg, "insufficient-funds") == 0) printf("Insufficient funds\n"); return; } } printf("Usage: withdraw <amt>\n"); return; } else if (strcmp(cmd_arg, "balance") == 0){ if(!atm->logged_in){ printf("No user logged in\n"); return; } pos = cmd_pos; if (get_ascii_arg(command, pos, &arg) != 0){ printf("Usage: balance\n"); return; } // Write message sprintf(message, "%lu balance %s",atm->counter++, atm->current_username); // Compute Digest digest_len = do_digest(message, &digest); // To encrypt: digest_len digest message sprintf(enc_in, "%s %s", digest, message); //null bytes seem to screw things up so try until no null bytes do{ do{ RAND_bytes(iv, sizeof(iv)); } while(strlen(iv) < 16); crypt_len = do_crypt(enc_in, strlen(enc_in), 1, atm->key, iv, &outbuf); } while (strlen(outbuf) != crypt_len || crypt_len == 0); //concat iv and outbuf strncat(sendline, iv, sizeof(iv)); strncat(sendline, outbuf, crypt_len); atm_send(atm, sendline, crypt_len + sizeof(iv)); //process response from bank n = atm_recv(atm,recvline, 1024 + EVP_MAX_BLOCK_LENGTH); if(n < 0 ){ printf("Communication error occurred. Please try again.\n"); return; } recvline[n]=0; //clear sendline and outbuf outbuf[0] = 0; dec_in[0] = 0; //first 16 bytes are iv, rest is cipher to decrypt memcpy(iv, recvline, sizeof(iv)); in_len = n - sizeof(iv); memcpy(dec_in, recvline + sizeof(iv), in_len); dec_in[in_len] = 0; //decrypt cipher crypt_len = do_crypt(dec_in, in_len, 0, atm->key, iv, &outbuf); //first 64 characters are digest, rest is message memcpy(rec_digest, outbuf, 128); rec_digest[128]=0; memcpy(message, outbuf+129, crypt_len - 129); message[crypt_len - 129] = 0; //do_digest on message and verify it matches sent digest digest_len = do_digest(message, &digest); digest[128]=0; if(strcmp(digest, rec_digest) != 0){ printf("Digests don't match, message was tampered with. Ignorning...\n"); return; } //check counter pos = 0; ret = get_digit_arg(message, pos, &int_arg); pos += ret + 1; if(int_arg < atm->counter){ //ATM got message with an invalid counter. Ignoring... return; } atm->counter = int_arg + 1; //process response ret = get_digit_arg(message, pos, &int_arg); printf("$%d\n", int_arg); return; } // log user out - set logged-in to false and username to null else if (strcmp(cmd_arg, "end-session") == 0){ if(!atm->logged_in){ printf("No user logged in\n"); return; } free(atm->current_username); atm->current_username = NULL; atm->logged_in = 0; printf("User logged out\n"); return; } else{ printf("Invalid command\n"); return; } }
void atm_process_command(ATM *atm, char *command) { // TODO: Implement the ATM's side of the ATM-bank protocol /* * The following is a toy example that simply sends the * user's command to the bank, receives a message from the * bank, and then prints it to stdout. */ char head[300]; strncpy(head, command, 300); char *getting = malloc(sizeof(char) * 5); memcpy(getting, "cont",4); getting[4] = '\0'; char *token; if((strcmp(getting,"cont")==0) && strncmp(head,"begin-session", 13) == 0){ if(atm->Session == 0){ token = strtok(head, " "); token = strtok(NULL," "); if(strlen(token) <= 250 && (strcmp(getting,"cont")==0)){ char *theName = malloc(sizeof(char) * strlen(token)); memcpy(theName,token,strlen(token)); theName[strlen(token)-1] = '\0'; char *user = malloc(sizeof(char) * strlen(token) + 5); memcpy(user,"user ", 5); user[5]='\0'; int len = strlen(token)-1; memcpy(user+5,token, len); user[len+5]='\0'; token = strtok(NULL," "); if(token == NULL && (strcmp(getting,"cont")==0)){ char recvline[5]; int n; atm_send(atm, user, strlen(user)); n = atm_recv(atm,recvline,5); recvline[n]=0; char com[257]; sprintf(com,"./%s.card",theName); if(strncmp(recvline,"yes", 3) == 0 && (strcmp(getting,"cont")==0)){ FILE *fp; if((fp = fopen(com,"r")) != NULL) { int myPin; printf("PIN? "); scanf("%d", &myPin); char sendPin[300]; sprintf(sendPin, "pin|%d|%s|", myPin, theName); sendPin[strlen(sendPin)]='\0'; char recievePin[5]; int x; atm_send(atm, sendPin, strlen(sendPin)); x = atm_recv(atm,recievePin,4); recievePin[x]=0; if(strncmp(recievePin,"good",4) == 0 && (strcmp(getting,"cont")==0)){ printf("Authorized\n"); atm->Session=1; atm->name = malloc(sizeof(char) * strlen(theName)); memcpy(atm->name,theName,strlen(theName)); atm->name[strlen(theName)] = '\0'; } else{ printf("Not authorized\n"); } fclose(fp); sendPin[0] = '\0'; recievePin[0] = '\0'; } else{ printf("Unable to access %s's card\n", user); } } else{ printf("No such user\n"); } recvline[0] = '\0'; com[0] = '\0'; } else{ printf("Usage: begin-session <user-name>\n"); } free(user); free(theName); }else{ printf("Usage: begin-session <user-name>\n"); } } else{ printf("A user is already logged in\n"); } } else if((strcmp(getting,"cont")==0) && strncmp(head,"withdraw", 8) == 0){ if(atm->Session == 1){ token = strtok(head, " "); token = strtok(NULL," "); if(token != NULL && (strcmp(getting,"cont")==0)){ char *balanceStr = malloc(sizeof(char) * strlen(token)); unsigned int howMuch; memcpy(balanceStr, token, strlen(token)); balanceStr[strlen(token)-1] = '\0'; token = strtok(NULL," "); if(((token == NULL) && (balanceStr[0] != '-')) && (strcmp(getting,"cont")==0)){ char *ptr; howMuch = strtoul(balanceStr, &ptr,10); char sendPin[300]; sprintf(sendPin, "getMoney|%u|%s|", howMuch, atm->name); sendPin[strlen(sendPin)]='\0'; char recievePin[5]; int x; atm_send(atm, sendPin, strlen(sendPin)); x = atm_recv(atm,recievePin,4); recievePin[x]=0; if((strncmp(recievePin,"good",4) == 0) && (strcmp(getting,"cont")==0)){ printf("$%u dispensed\n",howMuch); } else{ printf("Insufficient funds\n"); } sendPin[0] = '\0'; recievePin[0] = '\0'; }else{ printf("Usage: withdraw <amt>\n"); } free(balanceStr); } else{ printf("Usage: withdraw <amt>\n"); } } else{ printf("No user logged in\n"); } } else if((strcmp(getting,"cont")==0) && (strncmp(head,"balance", 7) == 0)){ if(atm->Session == 1){ if(strlen(head) == 8 && (strcmp(getting,"cont")==0)){ char sendPin[300]; sprintf(sendPin, "getBalance|%s|", atm->name); sendPin[strlen(sendPin)]='\0'; char recievePin[15]; int x; atm_send(atm, sendPin, strlen(sendPin)); x = atm_recv(atm,recievePin,17); recievePin[x]=0; if((strncmp(recievePin,"good",4) == 0) && (strcmp(getting,"cont")==0)){ token = strtok(recievePin, "|"); token = strtok(NULL,"|"); printf("$%s\n",token); } sendPin[0] = '\0'; recievePin[0] = '\0'; } else{ printf("Usage: balance\n"); } } else{ printf("No user logged in\n"); } } else if((strcmp(getting,"cont")==0) && ((strncmp(head,"end-session", 11) == 0) && (strlen(head) == 12))){ if(atm->Session == 1 && (strcmp(getting,"cont")==0)){ atm->Session = 0; free(atm->name); printf("User logged out\n"); } else{ printf("No user logged in\n"); } } else{ printf("Invalid command\n"); } head[0] = '\0'; }