void
test_mifare_application (void)
{
    /* Card publisher part */

    MadAid aid = { 0x22, 0x42 };
    Mad mad = mad_new (2);

    int i;

    cut_assert_not_null (mad, cut_message ("mad_new() failed"));

    MifareClassicSectorNumber *s_alloc = mifare_application_alloc (mad, aid, 3*3*16);
    cut_assert_not_null (s_alloc, cut_message ("mifare_application_alloc() failed"));

    MifareClassicSectorNumber *s_found = mifare_application_find (mad, aid);
    cut_assert_not_null (s_found, cut_message ("mifare_application_alloc() failed"));

    for (i = 0; s_alloc[i]; i++) {
	cut_assert_equal_int (s_alloc[i], s_found[i], cut_message ("Allocated and found blocks don't match at position %d", i));
    }

    cut_assert_equal_int (0, s_alloc[i], cut_message ("Invalid size"));
    cut_assert_equal_int (0, s_found[i], cut_message ("Invalid size"));

    mifare_application_free (mad, aid);

    free (s_alloc);
    free (s_found);

    s_found = mifare_application_find (mad, aid);
    cut_assert_null (s_found, cut_message ("mifare_application_free() failed"));

    s_alloc = mifare_application_alloc (mad, aid, 15*16 + 1*16 + 1);
    cut_assert_not_null (s_alloc, cut_message ("mifare_application_alloc() failed"));

    s_found = mifare_application_find (mad, aid);
    cut_assert_not_null (s_found, cut_message ("mifare_application_alloc() failed"));



    for (i = 0; s_alloc[i]; i++) {
	cut_assert_equal_int (s_alloc[i], s_found[i], cut_message ("Allocated and found blocks don't match at position %d", i));
    }

    cut_assert_equal_int (0, s_alloc[i], cut_message ("Invalid size"));
    cut_assert_equal_int (0, s_found[i], cut_message ("Invalid size"));


    mifare_application_free (mad, aid);

    free (s_alloc);
    free (s_found);

    s_found = mifare_application_find (mad, aid);
    cut_assert_null (s_found, cut_message ("mifare_application_free() failed"));

    mad_free (mad);
}
void
test_mifare_classic_mad (void)
{
    MifareClassicKey key_a_transport = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
    MifareClassicKey key_b_sector_00 = { 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };
    MifareClassicKey key_b_sector_10 = { 0x1a, 0x98, 0x2c, 0x7e, 0x45 ,0x9a };
    MifareClassicBlock tb;
    Mad mad;
    int res;

    /*  __  __   _   ___      _
     * |  \/  | /_\ |   \__ _/ |
     * | |\/| |/ _ \| |) \ V / |
     * |_|  |_/_/ \_\___/ \_/|_|
     */

    mad = mad_new (1);
    cut_assert_not_null (mad, cut_message ("mad_new() failed"));

    // Prepare sector 0x00 for writing a MAD.
    res = mifare_classic_authenticate (tag, 0x00, key_a_transport, MFC_KEY_A);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));

    mifare_classic_trailer_block (&tb, key_a_transport, 00, 00, 00, 06, 0x00, key_b_sector_00);

    res = mifare_classic_write (tag, 0x03, tb);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_write() failed"));

    // Write the empty MAD
    res = mad_write (tag, mad, key_b_sector_00, NULL);
    cut_assert_equal_int (0, res, cut_message ("mad_write() failed"));


    // Check the empty MAD
    MifareClassicBlock ref_01 = {
        0xce, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    MifareClassicBlock ref_02 = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    MifareClassicBlock data;

    res = mifare_classic_authenticate (tag, 0x01, mad_public_key_a, MFC_KEY_A);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));

    res = mifare_classic_read (tag, 0x01, &data);
    cut_assert_equal_int (0, res, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (ref_01, sizeof (ref_01), data, sizeof (data), cut_message ("Wrong data"));

    res = mifare_classic_read (tag, 0x02, &data);
    cut_assert_equal_int (0, res, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (ref_02, sizeof (ref_02), data, sizeof (data), cut_message ("Wrong data"));

    Mad mad2 = mad_read (tag);
    cut_assert_not_null (mad2, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (mad, sizeof (mad), mad2, sizeof (mad2), cut_message ("Wrong MAD"));

    const char application_data[] = "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " \
                                    "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " \
                                    "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " \
                                    "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " \
                                    "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> " \
                                    "APPLICATION DATA >> APPLICATION DATA >> APPLICATION DATA >> ";

    MadAid aid = {
        .function_cluster_code = 0x01,
        .application_code      = 0x12
    };

    // Write some data in the application
    MifareClassicSectorNumber *sectors = mifare_application_alloc (mad, aid, sizeof (application_data));
    cut_assert_not_null (sectors, cut_message ("mifare_application_alloc() failed"));
    free (sectors);

    res = mad_write (tag, mad, key_b_sector_00, NULL);
    cut_assert_equal_int (0, res, cut_message ("mad_write() failed"));

    ssize_t s = mifare_application_write (tag, mad, aid, &application_data, sizeof (application_data), key_a_transport, MFC_KEY_A);
    cut_assert_equal_int (sizeof (application_data), s, cut_message ("mifare_application_write() failed"));

    char read_buf[500];

    // Read it again
    s = mifare_application_read (tag, mad, aid, read_buf, sizeof (application_data), key_a_transport, MFC_KEY_A);
    cut_assert_equal_int (sizeof (application_data), s, cut_message ("mifare_application_read() failed"));
    cut_assert_equal_memory (application_data, sizeof (application_data), read_buf, s, cut_message ("Wrong application data"));

    mad_free (mad);
    mad_free (mad2);

    // Revert to the transport configuration
    res = mifare_classic_authenticate (tag, 0x00, key_b_sector_00, MFC_KEY_B);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));
    res = mifare_classic_format_sector (tag, 0x00);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_format_sector() failed"));

    /*  __  __   _   ___      ___
     * |  \/  | /_\ |   \__ _|_  )
     * | |\/| |/ _ \| |) \ V // /
     * |_|  |_/_/ \_\___/ \_//___|
     */
    if (freefare_get_tag_type (tag) != CLASSIC_4K) {
        cut_omit ("MADv2 requires a MIFARE Classic 4K to be tested");
    }

    mad = mad_new (2);
    cut_assert_not_null (mad, cut_message ("mad_new() failed"));

    // Prepare sector 0x00 for writing a MAD.
    res = mifare_classic_authenticate (tag, 0x00, key_a_transport, MFC_KEY_A);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));

    mifare_classic_trailer_block (&tb, key_a_transport, 00, 00, 00, 06, 0x00, key_b_sector_00);

    res = mifare_classic_write (tag, 0x03, tb);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_write() failed"));

    // Prepare sector 0x10 for writing a MAD.
    res = mifare_classic_authenticate (tag, 0x40, key_a_transport, MFC_KEY_A);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));

    mifare_classic_trailer_block (&tb, key_a_transport, 00, 00, 00, 06, 0x00, key_b_sector_10);

    res = mifare_classic_write (tag, 0x43, tb);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_write() failed"));

    // Write the empty MAD
    res = mad_write (tag, mad, key_b_sector_00, key_b_sector_10);
    cut_assert_equal_int (0, res, cut_message ("mad_write() failed"));

    // Check the empty MAD

    res = mifare_classic_authenticate (tag, 0x01, mad_public_key_a, MFC_KEY_A);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));

    res = mifare_classic_read (tag, 0x01, &data);
    cut_assert_equal_int (0, res, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (ref_01, sizeof (ref_01), data, sizeof (data), cut_message ("Wrong data"));

    res = mifare_classic_read (tag, 0x02, &data);
    cut_assert_equal_int (0, res, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (ref_02, sizeof (ref_02), data, sizeof (data), cut_message ("Wrong data"));

    MifareClassicBlock ref_40 = {
        0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    MifareClassicBlock ref_41 = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    MifareClassicBlock ref_42 = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
    };

    res = mifare_classic_authenticate (tag, 0x40, mad_public_key_a, MFC_KEY_A);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));

    res = mifare_classic_read (tag, 0x40, &data);
    cut_assert_equal_int (0, res, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (ref_40, sizeof (ref_01), data, sizeof (data), cut_message ("Wrong data"));

    res = mifare_classic_read (tag, 0x41, &data);
    cut_assert_equal_int (0, res, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (ref_41, sizeof (ref_02), data, sizeof (data), cut_message ("Wrong data"));

    res = mifare_classic_read (tag, 0x42, &data);
    cut_assert_equal_int (0, res, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (ref_42, sizeof (ref_02), data, sizeof (data), cut_message ("Wrong data"));


    mad2 = mad_read (tag);
    cut_assert_not_null (mad2, cut_message ("mad_read() failed"));
    cut_assert_equal_memory (mad, sizeof (mad), mad2, sizeof (mad2), cut_message ("Wrong MAD"));

    // Write some data in the application
    sectors = mifare_application_alloc (mad, aid, sizeof (application_data));
    cut_assert_not_null (sectors, cut_message ("mifare_application_alloc() failed"));
    free (sectors);

    res = mad_write (tag, mad, key_b_sector_00, key_b_sector_10);
    cut_assert_equal_int (0, res, cut_message ("mad_write() failed"));

    s = mifare_application_write (tag, mad, aid, &application_data, sizeof (application_data), key_a_transport, MFC_KEY_A);
    cut_assert_equal_int (sizeof (application_data), s, cut_message ("mifare_application_write() failed"));

    // Read it again
    s = mifare_application_read (tag, mad, aid, read_buf, sizeof (application_data), key_a_transport, MFC_KEY_A);
    cut_assert_equal_int (sizeof (application_data), s, cut_message ("mifare_application_read() failed"));
    cut_assert_equal_memory (application_data, sizeof (application_data), read_buf, s, cut_message ("Wrong application data"));

    mad_free (mad);
    mad_free (mad2);

    // Revert to the transport configuration
    res = mifare_classic_authenticate (tag, 0x00, key_b_sector_00, MFC_KEY_B);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));
    res = mifare_classic_format_sector (tag, 0x00);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_format_sector() failed"));

    res = mifare_classic_authenticate (tag, 0x40, key_b_sector_10, MFC_KEY_B);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_authenticate() failed"));
    res = mifare_classic_format_sector (tag, 0x10);
    cut_assert_equal_int (0, res, cut_message ("mifare_classic_format_sector() failed"));

}
Example #3
0
int
main(int argc, char *argv[])
{
	
	MYSQL *conn;
	MYSQL_RES *result;
	MYSQL_ROW row;
	int retval;
	
	conn = mysql_init(NULL);
	
	retval = mysql_real_connect(conn, def_host_name, def_user_name, def_password, def_db_name, def_port_num, def_socket_name, def_client_flag);
	if(!retval)
	{
		printf("Error connecting to database: %s\n", mysql_error(conn));
		return -1;
	}
	printf("Connection successful\n");
	
	int error = 0;
    nfc_device_t *device = NULL;
    MifareTag *tags = NULL;
    Mad mad;
    MifareClassicKey transport_key = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
	
	char ndef_input[15] = {'\0'};
	char ID[9] = {'\0'};
	double balance = 0;

	printf("\nID: ");
	scanf("%s", ID);
	while (getchar() != '\n') continue;
	
	printf("\nBalance: ");
	scanf("%lf", &balance);
	while (getchar() != '\n') continue;
	
	ID[0] = toupper(ID[0]);
	ID[1] = toupper(ID[1]);
	
	char balance_char[6] = {'\0'};
	snprintf(balance_char, 6, "%.2f", balance);
	
	//ensure balance always with 4 digit, 4.00 => 04.00
	char final_balance[6] = {'\0'};
	if(strlen(balance_char) != 5)
	{
		strcat(final_balance, "0");
		strcat(final_balance, balance_char);
	}
	else
	{
		strcpy(final_balance, balance_char);
	}

	strcat(ndef_input, ID);
	strcat(ndef_input, final_balance);

	int i = 0;
    if (ndef_input == NULL) {
		printf("Write default message.\n");
		for(i=0; i < sizeof(ndef_default_msg); i++)
		{
			ndef_msg[i] = (uint8_t)ndef_default_msg[i];
		}
			
        ndef_msg_len = sizeof(ndef_default_msg);
    } 
	else {
		for(i=0; i < strlen(ndef_input); i++)
		{
			ndef_msg[i] = (uint8_t)ndef_input[i];
		}
			
		ndef_msg_len = strlen(ndef_input);
    }
    printf ("NDEF message is %zu bytes long.\n", ndef_msg_len);

    struct mifare_classic_key_and_type *card_write_keys;
    if (!(card_write_keys = malloc (40 * sizeof (*card_write_keys)))) {
		err (EXIT_FAILURE, "malloc");
    }

    nfc_device_desc_t devices[8];
    size_t device_count;

    nfc_list_devices (devices, 8, &device_count);
    if (!device_count)
		errx (EXIT_FAILURE, "No NFC device found.");

    for (size_t d = 0; d < device_count; d++) {
		device = nfc_connect (&(devices[d]));
		if (!device) {
			warnx ("nfc_connect() failed.");
			error = EXIT_FAILURE;
			continue;
		}

		tags = freefare_get_tags (device);
		if (!tags) {
			nfc_disconnect (device);
			errx (EXIT_FAILURE, "Error listing MIFARE classic tag.");
		}

		for (int i = 0; (!error) && tags[i]; i++) 
		{
			switch (freefare_get_tag_type (tags[i])) {
				case CLASSIC_1K:
				case CLASSIC_4K:
					break;
				default:
					continue;
			}

			char *tag_uid = freefare_get_tag_uid (tags[i]);
			char buffer[BUFSIZ];

			printf ("Found %s with UID %s.\n", freefare_get_tag_friendly_name (tags[i]), tag_uid);
			bool write_ndef = true;
				
			for (int n = 0; n < 40; n++) {
				memcpy(card_write_keys[n].key, transport_key, sizeof (transport_key));
				card_write_keys[n].type = MFC_KEY_A;
			}

			if (write_ndef) 
			{
				switch (freefare_get_tag_type (tags[i])) {
					case CLASSIC_4K:
						if (!search_sector_key (tags[i], 0x10, &(card_write_keys[0x10].key), &(card_write_keys[0x10].type))) {
							error = 1;
							goto error;
						}
						/* fallthrough */
					case CLASSIC_1K:
						if (!search_sector_key (tags[i], 0x00, &(card_write_keys[0x00].key), &(card_write_keys[0x00].type))) {
							error = 1;
							goto error;
						}
						break;
					default:
						/* Keep compiler quiet */
						break;
				}

				if (!error) {
					/* Ensure the auth key is always a B one. If not, change it! */
					switch (freefare_get_tag_type (tags[i])) {
						case CLASSIC_4K:
						if (card_write_keys[0x10].type != MFC_KEY_B) {
							if( 0 != fix_mad_trailer_block (device, tags[i], 0x10, card_write_keys[0x10].key, card_write_keys[0x10].type)) {
								error = 1;
								goto error;
							}
							memcpy (&(card_write_keys[0x10].key), &default_keyb, sizeof (MifareClassicKey));
							card_write_keys[0x10].type = MFC_KEY_B;
						}
						/* fallthrough */
						case CLASSIC_1K:
						if (card_write_keys[0x00].type != MFC_KEY_B) {
							if( 0 != fix_mad_trailer_block (device, tags[i], 0x00, card_write_keys[0x00].key, card_write_keys[0x00].type)) {
								error = 1;
								goto error;
							}
							memcpy (&(card_write_keys[0x00].key), &default_keyb, sizeof (MifareClassicKey));
							card_write_keys[0x00].type = MFC_KEY_B;
							}
							break;
						default:
							/* Keep compiler quiet */
							break;
					}
				}

				size_t encoded_size;
				uint8_t *tlv_data = tlv_encode (3, ndef_msg, ndef_msg_len, &encoded_size);

				/*
				 * At his point, we should have collected all information needed to
				 * succeed.
				 */

				// If the card already has a MAD, load it.
				if ((mad = mad_read (tags[i]))) {
					// If our application already exists, erase it.
					MifareClassicSectorNumber *sectors, *p;
					sectors = p = mifare_application_find (mad, mad_nfcforum_aid);
					if (sectors) {
						while (*p) {
							if (mifare_classic_authenticate (tags[i], mifare_classic_sector_last_block(*p), default_keyb, MFC_KEY_B) < 0) {
								nfc_perror (device, "mifare_classic_authenticate");
								error = 1;
								goto error;
							}
							if (mifare_classic_format_sector (tags[i], *p) < 0) {
								nfc_perror (device, "mifare_classic_format_sector");
								error = 1;
								goto error;
							}
							p++;
						}
					}
					free (sectors);
					mifare_application_free (mad, mad_nfcforum_aid);
				} else {

					// Create a MAD and mark unaccessible sectors in the card
					if (!(mad = mad_new ((freefare_get_tag_type (tags[i]) == CLASSIC_4K) ? 2 : 1))) {
						perror ("mad_new");
						error = 1;
						goto error;
					}

					MifareClassicSectorNumber max_s;
					switch (freefare_get_tag_type (tags[i])) {
						case CLASSIC_1K:
							max_s = 15;
							break;
						case CLASSIC_4K:
							max_s = 39;
							break;
						default:
							/* Keep compiler quiet */
							break;
					}

					// Mark unusable sectors as so
					for (size_t s = max_s; s; s--) {
						if (s == 0x10) 
							continue;
						if (!search_sector_key (tags[i], s, &(card_write_keys[s].key), &(card_write_keys[s].type))) {
							mad_set_aid (mad, s, mad_defect_aid);
						} else if ((memcmp (card_write_keys[s].key, transport_key, sizeof (transport_key)) != 0) &&
							   (card_write_keys[s].type != MFC_KEY_A)) {
									// Revert to transport configuration
									if (mifare_classic_format_sector (tags[i], s) < 0) {
										nfc_perror (device, "mifare_classic_format_sector");
										error = 1;
										goto error;
									}
						}
					}
				}

				MifareClassicSectorNumber *sectors = mifare_application_alloc (mad, mad_nfcforum_aid, encoded_size);
				if (!sectors) {
					nfc_perror (device, "mifare_application_alloc");
					error = EXIT_FAILURE;
					goto error;
				}

				if (mad_write (tags[i], mad, card_write_keys[0x00].key, card_write_keys[0x10].key) < 0) {
					nfc_perror (device, "mad_write");
					error = EXIT_FAILURE;
					goto error;
				}

				int s = 0;
				while (sectors[s]) {
					MifareClassicBlockNumber block = mifare_classic_sector_last_block (sectors[s]);
					MifareClassicBlock block_data;
					mifare_classic_trailer_block (&block_data, mifare_classic_nfcforum_public_key_a, 0x0, 0x0, 0x0, 0x6, 0x40, default_keyb);
					if (mifare_classic_authenticate (tags[i], block, card_write_keys[sectors[s]].key, card_write_keys[sectors[s]].type) < 0) {
						nfc_perror (device, "mifare_classic_authenticate");
						error = EXIT_FAILURE;
						goto error;
					}
					if (mifare_classic_write (tags[i], block, block_data) < 0) {
						nfc_perror (device, "mifare_classic_write");
						error = EXIT_FAILURE;
						goto error;
					}
					s++;
				}

				if ((ssize_t) encoded_size != mifare_application_write (tags[i], mad, mad_nfcforum_aid, tlv_data, encoded_size, default_keyb, MCAB_WRITE_KEYB)) {
					nfc_perror (device, "mifare_application_write");
					error = EXIT_FAILURE;
					goto error;
				}


				//create new student record in database
				char sql_stmnt[57] = {'\0'};
				int n = 0;
				
				//filter tag_uid
				ulong uid_length = strlen(tag_uid);
				char uid_esc[(2 * uid_length)+1];
				mysql_real_escape_string(conn, uid_esc, tag_uid, uid_length);

				//filter ID
				ulong id_length = strlen(ID);
				char id_esc[(2 * id_length)+1];
				mysql_real_escape_string(conn, id_esc, ID, id_length);
				
				n = snprintf(sql_stmnt, 57, "INSERT INTO student VALUES('%s', '%s', %.1f)", uid_esc, id_esc, balance);
				retval = mysql_real_query(conn, sql_stmnt, n);
				if(retval)
				{
					printf("Inserting data from DB Failed\n");
					return -1;
				}
				printf("Insert to DB successful\n");
				
				free (sectors);

				free (tlv_data);

				free (mad);
			
			}
			error:
			free (tag_uid);
			
		}
		//should at the line 412, but the compiler keep on complaining
		//jump into scope of identifier with variably modified type
		//no idea why that happens, goto is always call inside any {} to outside error:
		//even at 412, still not outside enough
		

		freefare_free_tags (tags);
		nfc_disconnect (device);
    }

    free (card_write_keys);
	mysql_free_result(result);
	mysql_close(conn);

		exit (error);
}