123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463 |
- /*
- Package:
- MiFare Classic Universal toolKit (MFCUK)
-
- Package version:
- 0.1
-
- Filename:
- mfcuk_mifare.c
-
- Description:
- MFCUK defines and function implementation file extending
- mainly libnfc's "mifare.h" interface/functionality.
-
- Contact, bug-reports:
- http://andreicostin.com/
- mailto:zveriu@gmail.com
-
- License:
- GPL2 (see below), Copyright (C) 2009, Andrei Costin
-
- * @file mfcuk_mifare.c
- * @brief
- */
-
- /*
- VERSION HISTORY
- --------------------------------------------------------------------------------
- | Number : 0.1
- | dd/mm/yyyy : 23/11/2009
- | Author : zveriu@gmail.com, http://andreicostin.com
- | Description: Moved bulk of defines and functions from "mfcuk_keyrecovery_darkside.c"
- --------------------------------------------------------------------------------
- */
-
- /*
- LICENSE
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
- #include "mfcuk_mifare.h"
-
- // Default keys used as a *BIG* mistake in many applications - especially System Integrators should pay attention!
- uint8_t mfcuk_default_keys[][MIFARE_CLASSIC_KEY_BYTELENGTH] = {
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Place-holder for current key to verify
- {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
- {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5},
- {0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5},
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
- {0x4d, 0x3a, 0x99, 0xc3, 0x51, 0xdd},
- {0x1a, 0x98, 0x2c, 0x7e, 0x45, 0x9a},
- {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7},
- {0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
- };
-
- int mfcuk_default_keys_num = sizeof(mfcuk_default_keys) / sizeof(mfcuk_default_keys[0]);
-
- bool is_valid_block(uint8_t bTagType, uint32_t uiBlock)
- {
- if (IS_MIFARE_CLASSIC_1K(bTagType) && (uiBlock < MIFARE_CLASSIC_1K_MAX_BLOCKS)) {
- return true;
- }
-
- if (IS_MIFARE_CLASSIC_4K(bTagType) && (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS)) {
- return true;
- }
-
- return false;
- }
-
- bool is_valid_sector(uint8_t bTagType, uint32_t uiSector)
- {
- if (IS_MIFARE_CLASSIC_1K(bTagType) && (uiSector < MIFARE_CLASSIC_1K_MAX_SECTORS)) {
- return true;
- }
-
- if (IS_MIFARE_CLASSIC_4K(bTagType) && (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS)) {
- return true;
- }
-
- return false;
- }
-
- bool is_first_block(uint8_t bTagType, uint32_t uiBlock)
- {
- if (!is_valid_block(bTagType, uiBlock)) {
- return false;
- }
-
- // Test if we are in the small or big sectors
- if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
- // For Mifare Classic 1K, it will enter always here
- return ((uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0);
- } else {
- // This branch will enter only for Mifare Classic 4K big sectors
- return ((uiBlock) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0);
- }
-
- // Should not reach here, but... never know
- return false;
- }
-
- bool is_trailer_block(uint8_t bTagType, uint32_t uiBlock)
- {
- if (!is_valid_block(bTagType, uiBlock)) {
- return false;
- }
-
- // Test if we are in the small or big sectors
- if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
- // For Mifare Classic 1K, it will enter always here
- return ((uiBlock + 1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) == 0);
- } else {
- // This branch will enter only for Mifare Classic 4K big sectors
- return ((uiBlock + 1) % (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) == 0);
- }
-
- // Should not reach here, but... never know
- return false;
- }
-
- uint32_t get_first_block(uint8_t bTagType, uint32_t uiBlock)
- {
- if (!is_valid_block(bTagType, uiBlock)) {
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- // Test if we are in the small or big sectors
- if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
- // Integer divide, then integer multiply
- return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1;
- } else {
- uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
- return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2;
- }
-
- // Should not reach here, but... never know
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- uint32_t get_trailer_block(uint8_t bTagType, uint32_t uiBlock)
- {
- if (!is_valid_block(bTagType, uiBlock)) {
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- // Test if we are in the small or big sectors
- if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
- // Integer divide, then integer multiply
- return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 - 1);
- } else {
- uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
- return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 - 1);
- }
-
- // Should not reach here, but... never know
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- bool is_big_sector(uint8_t bTagType, uint32_t uiSector)
- {
- if (!is_valid_sector(bTagType, uiSector)) {
- return false;
- }
-
- if (uiSector >= MIFARE_CLASSIC_4K_MAX_SECTORS1) {
- return true;
- }
-
- return false;
- }
-
- uint32_t get_first_block_for_sector(uint8_t bTagType, uint32_t uiSector)
- {
- if (!is_valid_sector(bTagType, uiSector)) {
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1) {
- // For Mifare Classic 1K, it will enter always here
- return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
- } else {
- // For Mifare Classic 4K big sectors it will enter always here
- uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
- return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
- }
-
- // Should not reach here, but... never know
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- uint32_t get_trailer_block_for_sector(uint8_t bTagType, uint32_t uiSector)
- {
- if (!is_valid_sector(bTagType, uiSector)) {
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- if (uiSector < MIFARE_CLASSIC_4K_MAX_SECTORS1) {
- // For Mifare Classic 1K, it will enter always here
- return (uiSector * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1 - 1);
- } else {
- // For Mifare Classic 4K big sectors it will enter always here
- uint32_t tmp = uiSector - MIFARE_CLASSIC_4K_MAX_SECTORS1;
- return MIFARE_CLASSIC_4K_MAX_BLOCKS1 + (tmp * MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2) + (MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2 - 1);
- }
-
- // Should not reach here, but... never know
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- uint32_t get_sector_for_block(uint8_t bTagType, uint32_t uiBlock)
- {
- if (!is_valid_block(bTagType, uiBlock)) {
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- // Test if we are in the small or big sectors
- if (uiBlock < MIFARE_CLASSIC_4K_MAX_BLOCKS1) {
- // For Mifare Classic 1K, it will enter always here
- return (uiBlock / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR1);
- } else {
- uint32_t tmp = uiBlock - MIFARE_CLASSIC_4K_MAX_BLOCKS1;
- return MIFARE_CLASSIC_4K_MAX_SECTORS1 + (tmp / MIFARE_CLASSIC_4K_BLOCKS_PER_SECTOR2);
- }
-
- // Should not reach here, but... never know
- return MIFARE_CLASSIC_INVALID_BLOCK;
- }
-
- // Test case function for checking correct functionality of the block/sector is_ ang get_ functions
- void test_mifare_classic_blocks_sectors_functions(uint8_t bTagType)
- {
- uint32_t i;
- uint32_t max_blocks, max_sectors;
-
- if (IS_MIFARE_CLASSIC_1K(bTagType)) {
- printf("\nMIFARE CLASSIC 1K\n");
- max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
- max_sectors = MIFARE_CLASSIC_1K_MAX_SECTORS;
- } else if (IS_MIFARE_CLASSIC_4K(bTagType)) {
- printf("\nMIFARE CLASSIC 4K\n");
- max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
- max_sectors = MIFARE_CLASSIC_4K_MAX_SECTORS;
- } else {
- return;
- }
-
- // Include one invalid block, that is why we add +1
- for (i = 0; i < max_blocks + 1; i++) {
- printf("BLOCK %d\n", i);
- printf("\t is_valid_block: %c\n", (is_valid_block(bTagType, i) ? 'Y' : 'N'));
- printf("\t is_first_block: %c\n", (is_first_block(bTagType, i) ? 'Y' : 'N'));
- printf("\t is_trailer_block: %c\n", (is_trailer_block(bTagType, i) ? 'Y' : 'N'));
- printf("\t get_first_block: %d\n", get_first_block(bTagType, i));
- printf("\t get_trailer_block: %d\n", get_trailer_block(bTagType, i));
- printf("\t get_sector_for_block: %d\n", get_sector_for_block(bTagType, i));
- }
-
- // Include one invalid sector, that is why we add +1
- for (i = 0; i < max_sectors + 1; i++) {
- printf("SECTOR %d\n", i);
- printf("\t is_valid_sector: %c\n", (is_valid_sector(bTagType, i) ? 'Y' : 'N'));
- printf("\t is_big_sector: %c\n", (is_big_sector(bTagType, i) ? 'Y' : 'N'));
- printf("\t get_first_block_for_sector: %d\n", get_first_block_for_sector(bTagType, i));
- printf("\t get_trailer_block_for_sector: %d\n", get_trailer_block_for_sector(bTagType, i));
- }
-
- }
-
- bool mfcuk_save_tag_dump(const char *filename, mifare_classic_tag *tag)
- {
- FILE *fp;
- size_t result;
-
- fp = fopen(filename, "wb");
- if (!fp) {
- return false;
- }
-
- // Expect to write 1 record
- result = fwrite((void *) tag, sizeof(*tag), 1, fp);
-
- // If not written exactly 1 record, something is wrong
- if (result != 1) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
- return true;
- }
-
- bool mfcuk_save_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext)
- {
- FILE *fp;
- size_t result;
-
- fp = fopen(filename, "wb");
- if (!fp) {
- return false;
- }
-
- // Expect to write 1 record
- result = fwrite((void *) tag_ext, sizeof(*tag_ext), 1, fp);
-
- // If not written exactly 1 record, something is wrong
- if (result != 1) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
- return true;
- }
-
- bool mfcuk_load_tag_dump(const char *filename, mifare_classic_tag *tag)
- {
- FILE *fp;
- size_t result;
-
- fp = fopen(filename, "rb");
- if (!fp) {
- return false;
- }
-
- // Expect to read 1 record
- result = fread((void *) tag, sizeof(*tag), 1, fp);
-
- // If not read exactly 1 record, something is wrong
- if (result != 1) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
- return true;
- }
-
- bool mfcuk_load_tag_dump_ext(const char *filename, mifare_classic_tag_ext *tag_ext)
- {
- FILE *fp;
- size_t result;
-
- fp = fopen(filename, "rb");
- if (!fp) {
- return false;
- }
-
- // Expect to read 1 record
- result = fread((void *) tag_ext, sizeof(*tag_ext), 1, fp);
-
- // If not read exactly 1 record, something is wrong
- if (result != sizeof(*tag_ext)) {
- fclose(fp);
- return false;
- }
-
- fclose(fp);
- return true;
- }
-
- void print_mifare_classic_tag_keys(const char *title, mifare_classic_tag *tag)
- {
- uint32_t i, max_blocks, trailer_block;
- uint8_t bTagType;
- mifare_classic_block_trailer *ptr_trailer = NULL;
-
- if (!tag) {
- return;
- }
-
- bTagType = tag->amb->mbm.btUnknown;
-
- if (!IS_MIFARE_CLASSIC_1K(bTagType) && !IS_MIFARE_CLASSIC_4K(bTagType)) {
- return;
- }
-
- printf("%s - UID %02x %02x %02x %02x - TYPE 0x%02x (%s)\n",
- title, tag->amb->mbm.abtUID[0], tag->amb->mbm.abtUID[1], tag->amb->mbm.abtUID[2], tag->amb->mbm.abtUID[3], bTagType,
- (IS_MIFARE_CLASSIC_1K(bTagType) ? (MIFARE_CLASSIC_1K_NAME) : (IS_MIFARE_CLASSIC_4K(bTagType) ? (MIFARE_CLASSIC_4K_NAME) : (MIFARE_CLASSIC_UNKN_NAME)))
- );
- printf("-------------------------------------------------------\n");
- printf("Sector\t| Key A\t| AC bits\t| Key B\n");
- printf("-------------------------------------------------------\n");
-
- if (IS_MIFARE_CLASSIC_1K(tag->amb->mbm.btUnknown)) {
- max_blocks = MIFARE_CLASSIC_1K_MAX_BLOCKS;
- } else {
- max_blocks = MIFARE_CLASSIC_4K_MAX_BLOCKS;
- }
-
- for (i = 0; i < max_blocks; i++) {
- trailer_block = get_trailer_block(bTagType, i);
-
- if (!is_valid_block(bTagType, trailer_block)) {
- break;
- }
-
- ptr_trailer = (mifare_classic_block_trailer *)((char *)tag + (trailer_block * MIFARE_CLASSIC_BYTES_PER_BLOCK));
-
- printf("%d\t| %02x%02x%02x%02x%02x%02x\t| %02x%02x%02x%02x\t| %02x%02x%02x%02x%02x%02x\n",
- get_sector_for_block(bTagType, trailer_block),
- ptr_trailer->abtKeyA[0], ptr_trailer->abtKeyA[1], ptr_trailer->abtKeyA[2],
- ptr_trailer->abtKeyA[3], ptr_trailer->abtKeyA[4], ptr_trailer->abtKeyA[5],
- ptr_trailer->abtAccessBits[0], ptr_trailer->abtAccessBits[1], ptr_trailer->abtAccessBits[2], ptr_trailer->abtAccessBits[3],
- ptr_trailer->abtKeyB[0], ptr_trailer->abtKeyB[1], ptr_trailer->abtKeyB[2],
- ptr_trailer->abtKeyB[3], ptr_trailer->abtKeyB[4], ptr_trailer->abtKeyB[5]
- );
-
- // Go beyond current trailer block, i.e. go to next sector
- i = trailer_block;
- }
-
- printf("\n");
-
- return;
- }
-
- bool mfcuk_key_uint64_to_arr(const uint64_t *ui64Key, uint8_t *arr6Key)
- {
- int i;
-
- if (!ui64Key || !arr6Key) {
- return false;
- }
-
- for (i = 0; i < MIFARE_CLASSIC_KEY_BYTELENGTH; i++) {
- arr6Key[i] = (uint8_t)(((*ui64Key) >> 8 * (MIFARE_CLASSIC_KEY_BYTELENGTH - i - 1)) & 0xFF);
- }
-
- return true;
- }
-
- bool mfcuk_key_arr_to_uint64(const uint8_t *arr6Key, uint64_t *ui64Key)
- {
- uint64_t key = 0;
- int i;
-
- if (!ui64Key || !arr6Key) {
- return false;
- }
-
- for (i = 0; i < MIFARE_CLASSIC_KEY_BYTELENGTH; i++, key <<= 8) {
- key |= arr6Key[i];
- }
- key >>= 8;
-
- *ui64Key = key;
-
- return true;
- }
|