// // Created by robin on 7/22/16. // #include "libnfc_cpptools/FreeFareTag.h" #include "libnfc_cpptools/StringUtils.h" #include "FreeFareTagInternal.h" namespace LibNfc { namespace FreeFare { std::string FreeFareTag::getTagTypeString(FreeFareTag::FreeFareTagType type) { if (type == FreeFareTagType::FELICA) { return "FELICA"; } if (type == FreeFareTagType::MIFARE_MINI) { return "MIFARE_MINI"; } if (type == FreeFareTagType::MIFARE_CLASSIC_1K) { return "MIFARE_CLASSIC_1K"; } if (type == FreeFareTagType::MIFARE_CLASSIC_4K) { return "MIFARE_CLASSIC_4K"; } if (type == FreeFareTagType::MIFARE_DESFIRE) { return "MIFARE_DESFIRE"; } if (type == FreeFareTagType::MIFARE_ULTRALIGHT) { return "MIFARE_ULTRALIGHT"; } if (type == FreeFareTagType::MIFARE_ULTRALIGHT_C) { return "MIFARE_ULTRALIGHT_C"; } return "UNKNOWN"; } FreeFareTag::FreeFareTag(std::shared_ptr tag) : _tag(tag) { } LibNfc::Utils::ResultBool FreeFareTag::authenticate(int sector, std::string key, int keyType) { return _tag->authenticate(sector, key, keyType); } LibNfc::Utils::Result FreeFareTag::mapKeys(std::vector keys, std::function cb) { MappedKeys mappedKeys; int done = 0; int total = 16 * keys.size(); for (int i = 0; i < 16; ++i) { std::pair blockKeys; for (int k = 0; k < keys.size(); ++k) { auto key = keys[k]; if (authenticate(i, key, MFC_KEY_A)) { blockKeys.first = key; } if (authenticate(i, key, MFC_KEY_B)) { blockKeys.second = key; } if (cb != 0) { cb(++done, total); } if (!blockKeys.first.empty() && !blockKeys.second.empty()) { break; } } mappedKeys.push_back(blockKeys); } if (cb != 0 && done < total) { cb(total, total); } return LibNfc::Utils::Result::ok(mappedKeys); } LibNfc::Utils::ResultString FreeFareTag::readBlock(int sector, int block, std::string key, int keyType) { return _tag->readBlock(sector, block, key, keyType); } LibNfc::Utils::Result FreeFareTag::readSector(int sector, std::string key, int keyType) { std::string res; int lastBlock = _tag->getSectorBlockCount(sector); for (int i = 0; i < lastBlock; ++i) { auto data = readBlock(sector, i, key, keyType); if (data) { res += data.getData(); } else { return LibNfc::Utils::Result::error(data); } } return LibNfc::Utils::Result::ok(FreeFareSector(res)); } LibNfc::Utils::Result> FreeFareTag::read(MappedKeys keys, std::function cb) { if (keys.size() != 16) { return LibNfc::Utils::Result>::error("Must have 16 sectors keys"); } int done = 0; int total = 4 * keys.size(); std::vector sectors; for (int s = 0; s < keys.size(); ++s) { auto sectorKey = keys[s]; FreeFareSector sector; bool keyA = false; bool keyB = false; for (int b = 0; b < 3; ++b) { std::string data = ""; if (!sectorKey.first.empty()) { auto blockResult = readBlock(s, b, sectorKey.first, MFC_KEY_A); if (blockResult) { data = blockResult.getData(); keyA = true; } } if (!sectorKey.second.empty()) { auto blockResult = readBlock(s, b, sectorKey.second, MFC_KEY_B); if (blockResult) { if (data.empty()) { data = blockResult.getData(); } keyB = true; } } sector.setBlock(b, data); if (cb != 0) { cb(++done, total); } } int b = 3; std::string dataA = ""; std::string dataB = ""; if (!sectorKey.first.empty()) { auto blockResult = readBlock(s, b, sectorKey.first, MFC_KEY_A); if (blockResult) { dataA = blockResult.getData(); keyA = true; } } if (!sectorKey.second.empty()) { auto blockResult = readBlock(s, b, sectorKey.second, MFC_KEY_B); if (blockResult) { dataB = blockResult.getData(); keyB = true; } } if (cb != 0) { cb(++done, total); } sector.setBlock(b, dataA); FreeFareAccessBits accessBitsDboA = sector.getAccessBitsDbo(); sector.setBlock(b, dataB); FreeFareAccessBits accessBitsDboB = sector.getAccessBitsDbo(); sector.setKeyA(keyA ? sectorKey.first : ""); sector.setKeyB(keyB ? sectorKey.second : ""); std::string accessBits; if (keyA && accessBitsDboA.canKeyAReadAccessBitsTrailer()) { accessBits = accessBitsDboA.getBits(); } else if (keyB && accessBitsDboB.canKeyBReadAccessBitsTrailer()) { accessBits = accessBitsDboB.getBits(); } sector.setAccessBits(accessBits); sectors.push_back(sector); } if (cb != 0 && done < total) { cb(total, total); } return LibNfc::Utils::Result>::ok(sectors); } LibNfc::Utils::Result> FreeFareTag::read(std::vector keys, std::function mapCb, std::function readCb) { auto mappedKeysResult = mapKeys(keys, mapCb); if (!mappedKeysResult) { return LibNfc::Utils::Result>::error(mappedKeysResult); } return read(mappedKeysResult.getData(), readCb); } LibNfc::Utils::ResultBool FreeFareTag::writeBlock(int sector, int block, std::string key, int keyType, const std::string &data) { return _tag->writeBlock(sector, block, key, keyType, LibNfc::Utils::StringUtils::ensureSize(data, 16)); } LibNfc::Utils::ResultBool FreeFareTag::writeSector(int sector, std::string key, int keyType, const std::string &data) { std::string d = LibNfc::Utils::StringUtils::ensureSize(data, 64); std::string errors; for (int b = 0; b < 4; ++b) { auto result = writeBlock(sector, b, key, keyType, d.substr(b * 16, 16)); if (!result) { errors += std::string(errors.empty() ? "" : "\n") + "Failed to write sector " + std::to_string(sector) + " block " + std::to_string(b) + " with key " + (keyType == MFC_KEY_A ? "A" : "B") + ": " + result.getError(); } } if (errors.empty()) { return LibNfc::Utils::ResultBool::ok(true); } return LibNfc::Utils::ResultBool::error(errors); } LibNfc::Utils::ResultBool FreeFareTag::write(MappedKeys keys, const std::string &data, bool writeSector0, std::function cb) { if (keys.size() != 16) { return LibNfc::Utils::ResultBool::error("Must have 16 sectors keys"); } std::string d = LibNfc::Utils::StringUtils::ensureSize(data, 1024); std::string errors; int done = 0; int total = 4 * keys.size(); for (int s = 0; s < keys.size(); ++s) { auto sectorKey = keys[s]; for (int b = 0; b < 4; ++b) { if (s == 0 && b == 0 && !writeSector0) { continue; } std::string blockData = d.substr((s * 64) + (b * 16), 16); if (cb != 0 && done < total) { bool keyA = false; bool keyB = false; std::string sectorErrors; if (!sectorKey.first.empty()) { auto resultA = writeBlock(s, b, sectorKey.first, MFC_KEY_A, blockData); if (resultA) { keyA = true; } else { sectorErrors = "Failed to write sector " + std::to_string(s) + " block " + std::to_string(b) + " with key A: " + resultA.getError(); } } if (!keyA && !sectorKey.second.empty()) { auto resultB = writeBlock(s, b, sectorKey.first, MFC_KEY_A, blockData); if (resultB) { keyB = true; } else { sectorErrors = std::string(sectorErrors.empty() ? "" : "\n") + "Failed to write sector " + std::to_string(s) + " block " + std::to_string(b) + " with key B: " + resultB.getError(); } } if (!keyA && !keyB) { errors += std::string(errors.empty() ? "" : "\n") + sectorErrors; } cb(++done, total); } } } if (cb != 0 && done < total) { cb(total, total); } if (errors.empty()) { return LibNfc::Utils::ResultBool::ok(true); } return LibNfc::Utils::ResultBool::error(errors); } LibNfc::Utils::ResultBool FreeFareTag::write(std::vector keys, const std::string &data, bool writeSector0, std::function mapCb, std::function writeCb) { auto mappedKeysResult = mapKeys(keys, mapCb); if (!mappedKeysResult) { return LibNfc::Utils::ResultBool::error(mappedKeysResult); } return write(mappedKeysResult.getData(), data, writeSector0, writeCb); } const std::string &FreeFareTag::getUid() const { return _tag->getUid(); } FreeFareTag::FreeFareTagType FreeFareTag::getType() const { auto type = _tag->getType(); if (type == freefare_tag_type::FELICA) { return FreeFareTagType::FELICA; } if (type == freefare_tag_type::MIFARE_MINI) { return FreeFareTagType::MIFARE_MINI; } if (type == freefare_tag_type::MIFARE_CLASSIC_1K) { return FreeFareTagType::MIFARE_CLASSIC_1K; } if (type == freefare_tag_type::MIFARE_CLASSIC_4K) { return FreeFareTagType::MIFARE_CLASSIC_4K; } if (type == freefare_tag_type::MIFARE_DESFIRE) { return FreeFareTagType::MIFARE_DESFIRE; } if (type == freefare_tag_type::MIFARE_ULTRALIGHT) { return FreeFareTagType::MIFARE_ULTRALIGHT; } if (type == freefare_tag_type::MIFARE_ULTRALIGHT_C) { return FreeFareTagType::MIFARE_ULTRALIGHT_C; } return FreeFareTagType::UNKNOWN; } std::shared_ptr FreeFareTag::getTag() const { return _tag; } }; // FreeFare }; // LibNfc