diff --git a/output/ezlic_eovosv0_jjacdgpdxpb.lic b/output/ezlic_eovosv0_jjacdgpdxpb.lic index 4efdd87..f2eee96 100644 Binary files a/output/ezlic_eovosv0_jjacdgpdxpb.lic and b/output/ezlic_eovosv0_jjacdgpdxpb.lic differ diff --git a/output/ezlic_eovosv0_wqxcyjpdxji.lic b/output/ezlic_eovosv0_wqxcyjpdxji.lic index 6731e88..3d0a18f 100644 Binary files a/output/ezlic_eovosv0_wqxcyjpdxji.lic and b/output/ezlic_eovosv0_wqxcyjpdxji.lic differ diff --git a/output/licData.xml b/output/licData.xml index 47acd9a..1cfdec3 100644 --- a/output/licData.xml +++ b/output/licData.xml @@ -1,27 +1,29 @@ -EOV_OSV -WAGO +EOV_OSV +wago Licence pro EOV_OSV -odb.zaluzi.drt.cz -POZ8 -Projekt XXX stanice YYY - - - Položka licence 1 - 111 - 40000 - - - Položka licence 2 - 222 - 51000 - - - Položka licence 3 - 333 - 62000 - - - +testovaci projekt + + +pt_Ez_iec104c +5 +2500 + + +pt_Ez_iec104s +6 +15000 + + +pt_Ez_mdbipc +9 +250 + + +pt_Ez_mdbips +10 +400 + + \ No newline at end of file diff --git a/output/licDataOld.xml b/output/licDataOld.xml new file mode 100644 index 0000000..47acd9a --- /dev/null +++ b/output/licDataOld.xml @@ -0,0 +1,27 @@ + + +EOV_OSV +WAGO +Licence pro EOV_OSV +odb.zaluzi.drt.cz +POZ8 +Projekt XXX stanice YYY + + + Položka licence 1 + 111 + 40000 + + + Položka licence 2 + 222 + 51000 + + + Položka licence 3 + 333 + 62000 + + + + \ No newline at end of file diff --git a/output/licenceGenerator b/output/licenceGenerator index fba0e59..9bd0a56 100644 Binary files a/output/licenceGenerator and b/output/licenceGenerator differ diff --git a/output/temp/generate/licenceGenerator b/output/temp/generate/licenceGenerator new file mode 100644 index 0000000..74d7d1c Binary files /dev/null and b/output/temp/generate/licenceGenerator differ diff --git a/output/temp/read/licenceGenerator b/output/temp/read/licenceGenerator new file mode 100644 index 0000000..9bd0a56 Binary files /dev/null and b/output/temp/read/licenceGenerator differ diff --git a/src/CreateLicence.cpp b/src/CreateLicence.cpp index 4ce2ca9..9e7a44a 100644 --- a/src/CreateLicence.cpp +++ b/src/CreateLicence.cpp @@ -8,7 +8,7 @@ /// @param argc /// @param argv parametry pro generování licence /// @return -int main6(int argc, char *argv[]) +int main(int argc, char *argv[]) { unordered_map arguments = getArguments(argc, argv); try diff --git a/src/ReadLicence.cpp b/src/ReadLicence.cpp index 775895a..99a8e68 100644 --- a/src/ReadLicence.cpp +++ b/src/ReadLicence.cpp @@ -7,7 +7,7 @@ /// @param argc /// @param argv parametry pro generování licence /// @return -int main() +int main6() { try @@ -18,8 +18,8 @@ int main() initStructure.licenceIndex = 0; initStructure.licenceFilePath = ""; // cesta k licenčnímu souboru // initStructure.compatibility = 0; v případě kompatibility 0 či nezadané je výstup defaultní. - // pro ELC 1 LicenceELC1Info s výstupem isValid, pro ELC 2 strukura { int protocolId = -1; int dataPointsCount = 0; } - initStructure.cid_csd_filePath = ""; // cesta k cidu/csd pro načtení a kontorlu licence + // pro ELC 1 LicenceELC1Info je to isValid, pro ELC 2 strukura { int protocolId = -1; int dataPointsCount = 0; } + initStructure.cid_csd_filePath = ""; // cesta k cidu/csd pro načtení a kontrolu licence //verze původní ELC 1 LicenceReader licenceReaderELC1{}; @@ -46,7 +46,8 @@ int main() if (licenceReaderELC2.initread(2, initStructure)) // iniciacni nacteni { // v případě kompatibility 0, či nezadané výstup nativně je defaultní. - // v případně nenulové kompatibility, třeba 1, přidáme číslo kompatibility. Tedy pro ELC1 to bude LicenceELC1_1, pro ELC LicenceELC2_1 + // v případně nenulové kompatibility, třeba 1, přidáme číslo kompatibility. + //Tedy pro ELC1 to bude LicenceELC1_1, pro ELC LicenceELC2_1 LicenceELC2Item info; // podle ELC a kompatibility určit strukuru (LicenceInfo11, LicenceInfo21, LicenceInfo31) // if () int protocolId = 333; @@ -77,7 +78,7 @@ int main() //verze ELC 2 kompletní načtení if (licenceReaderCompleteELC2.init(2, initStructure)) // iniciacni nacteni { - LicenceELC2Info info; // podle ELC a kompatibility určit strukuru (LicenceInfo11, LicenceInfo21, LicenceInfo31) + LicenceELC2Info info; int protocolId = 333; if (licenceReaderCompleteELC2.getLicenceInfo(&info)) @@ -106,17 +107,6 @@ int main() { cout << "Obecna chyba\n"; } - // system("pause"); return SUCCES; } -/* -CRC public size: 353 -CRC gen public: 27885 - -CRC private size: 285 -CRC gen private: 18500 - -CRC complete size: 638 -CRC gen complete: 42051 -*/ \ No newline at end of file diff --git a/src/generator/LicenceGenerator.cpp b/src/generator/LicenceGenerator.cpp index 3b1f27d..aca47d7 100644 --- a/src/generator/LicenceGenerator.cpp +++ b/src/generator/LicenceGenerator.cpp @@ -83,6 +83,7 @@ bool LicenceGenerator::processInputConfiguration() } else { + cout << "file: " << fileName << "\n"; throw LicenceException((int)GeneralError::FileOpenError, "Unable to open the config file."); } @@ -118,15 +119,15 @@ void LicenceGenerator::createLicenceELC2() switch (this->licIdentification.licCompatibility) { case 1: + { Generator::Licence2 licence = Generator::Licence2(licData.cid,licData.csd,licData.doc); licence.createLicence(); - /* - licence.createLicence(); - // LicenceELC21 licence = LicenceELC21(this->licData); - // licence.createLicence(); - */ - break; + break; } + default: throw LicenceException((int)GeneralError::CompatibilityTypeNotImplemented, "Compatibility not implemented."); + + } + } void LicenceGenerator::createLicenceELC3() diff --git a/src/generator/LicenceGenerator.o b/src/generator/LicenceGenerator.o index 06b6f48..912fb08 100644 Binary files a/src/generator/LicenceGenerator.o and b/src/generator/LicenceGenerator.o differ diff --git a/src/generator/licGenELC2.cpp b/src/generator/licGenELC2.cpp index 1801bda..8f5701f 100644 --- a/src/generator/licGenELC2.cpp +++ b/src/generator/licGenELC2.cpp @@ -23,7 +23,7 @@ namespace Generator void Licence2::getHeader() { PublicHeader publicHeader; - publicHeader.version = getVersion(7); + publicHeader.version = getVersion(lIdentification.revision); publicHeader.projectDescription = projectDescription; publicHeader.date = getDate(); publicHeader.licenceType = lIdentification.licTypeName; @@ -98,7 +98,7 @@ namespace Generator result.append("."); result.append(to_string(middleVersion)); result.append("."); - string tempLicenceCount = "3"; // TODO + string tempLicenceCount = "1"; // TODO result.append(tempLicenceCount); return result; } @@ -121,7 +121,7 @@ namespace Generator } this->lIdentification.licenceVersion = atoi(&xmlDoc->child(dataRootName).child("licenceType").attribute("licenceVersion").value()[0]); - this->lIdentification.revision = xmlDoc->child(dataRootName).attribute("revision").value()[0]; + this->lIdentification.revision = atoi(&xmlDoc->child(dataRootName).attribute("revision").value()[0]); this->lIdentification.licenceIndex = atoi(&xmlDoc->child(dataRootName).child("licenceType").attribute("licenceIndex").value()[0]); this->lIdentification.licElcType = (ELCType)atoi(&xmlDoc->child(dataRootName).attribute("elc").value()[0]); diff --git a/src/generator/licGenELC2.o b/src/generator/licGenELC2.o index a41ba6a..40a68ef 100644 Binary files a/src/generator/licGenELC2.o and b/src/generator/licGenELC2.o differ diff --git a/src/reader/LicenceReader.cpp b/src/reader/LicenceReader.cpp index c86ab44..21cecfd 100644 --- a/src/reader/LicenceReader.cpp +++ b/src/reader/LicenceReader.cpp @@ -64,7 +64,7 @@ bool LicenceReader::initread(int elcType, InitStructure &initStructure) switch (this->licIdentification.licElcType) { case ELCType::ELC1: - { // old eoseov + { Reader::Licence1 licenceELC1 = Reader::Licence1(this->licIdentification); this->licence1 = &licenceELC1; licenceELC1.cid_cdsPath = initStructure.cid_csd_filePath; @@ -143,7 +143,7 @@ bool LicenceReader::getLicenceItemInfo(int protocolId, void *returnItemStructure if (!this->licIdentification.licCompatibility) // defaultní kompatibilita { LicenceELC2Item *resultPtr = static_cast(returnItemStructure); - resultPtr->protocolId = protocolId; // protocolId; + resultPtr->protocolId = protocolId; if (this->licenceInfo.licences.count(protocolId)) resultPtr->dataPointsCount = this->licenceInfo.licences.at(protocolId); else diff --git a/src/reader/licReaderELC2.cpp b/src/reader/licReaderELC2.cpp index 7ba21a6..1920220 100644 --- a/src/reader/licReaderELC2.cpp +++ b/src/reader/licReaderELC2.cpp @@ -62,10 +62,6 @@ namespace Reader vector encryptedPart(content.begin() + licBody.licenceIdentHeader.publicHeaderLength + 18, content.begin() + content.size()); - // cout << "encryptedPart content length: " << encryptedPart.size() << "\n"; - // for (auto x : encryptedPart) cout << (int)x << "-"; - // cout << "\n"; - vector privateContentDecrypted; privateContentDecrypted = decryptPrivateContent(encryptedPart); diff --git a/src/reader/licReaderELC2.o b/src/reader/licReaderELC2.o index b532ae4..dcd1f62 100644 Binary files a/src/reader/licReaderELC2.o and b/src/reader/licReaderELC2.o differ diff --git a/zdenda/Makefile b/zdenda/Makefile new file mode 100644 index 0000000..1dffacf --- /dev/null +++ b/zdenda/Makefile @@ -0,0 +1,100 @@ +# +# 'make' build executable file 'main' +# 'make clean' removes all .o and executable files +# + +# define the Cpp compiler to use +CXX = g++ + +# define any compile-time flags +# CXXFLAGS := -std=c++17 -Wall -Wextra -g -lssl -lcrypto -w +CXXFLAGS := -Wall -Wextra -g -lssl -lcrypto + +# define library paths in addition to /usr/lib +# if I wanted to include libraries not in /usr/lib I'd specify +# their path using -Lpath, something like: +LFLAGS = + +# define output directory +OUTPUT := output + +# define source directory +SRC := src src/common src/reader + +# define include directory +INCLUDE := include include/common include/reader + +# define lib directory +LIB := lib + +ifeq ($(OS),Windows_NT) +MAIN := licenceGenerator.exe +SOURCEDIRS := $(SRC) +INCLUDEDIRS := $(INCLUDE) +LIBDIRS := $(LIB) +FIXPATH = $(subst /,\,$1) +RM := del /q /f +MD := mkdir +else +MAIN := licenceGenerator +SOURCEDIRS := $(shell find $(SRC) -type d) +INCLUDEDIRS := $(shell find $(INCLUDE) -type d) +LIBDIRS := $(shell find $(LIB) -type d) +FIXPATH = $1 +RM = rm -f +MD := mkdir -p +endif + +# define any directories containing header files other than /usr/include +INCLUDES := $(patsubst %,-I%, $(INCLUDEDIRS:%/=%)) + +# define the C libs +LIBS := $(patsubst %,-L%, $(LIBDIRS:%/=%)) + +# define the C source files +SOURCES := $(wildcard $(patsubst %,%/*.cpp, $(SOURCEDIRS))) + +# define the C object files +OBJECTS := $(SOURCES:.cpp=.o) + +# define the dependency output files +DEPS := $(OBJECTS:.o=.d) + +# +# The following part of the makefile is generic; it can be used to +# build any executable just by changing the definitions above and by +# deleting dependencies appended to the file from 'make depend' +# + +OUTPUTMAIN := $(call FIXPATH,$(OUTPUT)/$(MAIN)) + +all: $(OUTPUT) $(MAIN) + @echo Executing 'all' complete! + +$(OUTPUT): + $(MD) $(OUTPUT) + +$(MAIN): $(OBJECTS) + $(CXX) $(CXXFLAGS) $(INCLUDES) -o $(OUTPUTMAIN) $(OBJECTS) $(LFLAGS) $(LIBS) + +# include all .d files +-include $(DEPS) + +# this is a suffix replacement rule for building .o's and .d's from .c's +# it uses automatic variables $<: the name of the prerequisite of +# the rule(a .c file) and $@: the name of the target of the rule (a .o file) +# -MMD generates dependency output files same name as the .o file +# (see the gnu make manual section about automatic variables) +.cpp.o: + $(CXX) $(CXXFLAGS) $(INCLUDES) -c -MMD $< -o $@ + +.PHONY: clean +clean: + $(RM) $(OUTPUTMAIN) + $(RM) $(call FIXPATH,$(OBJECTS)) + $(RM) $(call FIXPATH,$(DEPS)) + @echo Cleanup complete! + +run: all + ./$(OUTPUTMAIN) + @echo Executing 'run: all' complete! diff --git a/zdenda/src/ReadLicence.cpp b/zdenda/src/ReadLicence.cpp new file mode 100644 index 0000000..9eea4bf --- /dev/null +++ b/zdenda/src/ReadLicence.cpp @@ -0,0 +1,112 @@ +#define LINUX 1 +// #define WINDOWS 1 + +#include "licenceReader.h" + +/// @brief hlavní funkce +/// @param argc +/// @param argv parametry pro generování licence +/// @return +int main() +{ + + try + { + InitStructure initStructure; + initStructure.licenceType = (int)LicenceType::EOS_EOV; + initStructure.licenceVersion = 1; + initStructure.licenceIndex = 0; + initStructure.licenceFilePath = ""; // cesta k licenčnímu souboru + // initStructure.compatibility = 0; v případě kompatibility 0 či nezadané je výstup defaultní. + // pro ELC 1 LicenceELC1Info je to isValid, pro ELC 2 strukura { int protocolId = -1; int dataPointsCount = 0; } + initStructure.cid_csd_filePath = ""; // cesta k cidu/csd pro načtení a kontrolu licence + + //verze původní ELC 1 + LicenceReader licenceReaderELC1{}; + if (licenceReaderELC1.initread(1, initStructure)) // iniciacni nacteni + { + LicenceELC1Info info; // struktura pro ELC1. Nemá tam asi nic jiného smysl nez true/false + if (licenceReaderELC1.getLicenceInfo(&info)) + { + if (info.isValid) + cout << "Platna licence ELC1 \n"; + else + cout << "Neplatna licence ELC1\n"; + } + else + cout << "CHYBA: " << licenceReaderELC1.error.message; + } + else + { + cout << "CHYBA: " << licenceReaderELC1.error.message; + } + + // verze ELC 2 pro jeden protokol + LicenceReader licenceReaderELC2{}; + if (licenceReaderELC2.initread(2, initStructure)) // iniciacni nacteni + { + // v případě kompatibility 0, či nezadané výstup nativně je defaultní. + // v případně nenulové kompatibility, třeba 1, přidáme číslo kompatibility. + //Tedy pro ELC1 to bude LicenceELC1_1, pro ELC LicenceELC2_1 + LicenceELC2Item info; // podle ELC a kompatibility určit strukuru (LicenceInfo11, LicenceInfo21, LicenceInfo31) + // if () + int protocolId = 333; + + // if (initStructure.compatibility == 1) //ukazka kompatibilita 1 + // { + // LicenceELC2Item_1 info; //jiná struktura, zbytek stejný + // if (licenceReaderELC2.getLicenceItemInfo(protocolId, &info)) + // { + // cout << "Pocet licencních bodu pro " << info.protocolId << ": " << info.dataPointsCount << std::endl; + // } + //........... + // } + + if (licenceReaderELC2.getLicenceItemInfo(protocolId, &info)) + { + cout << "Pocet licencních bodu pro " << info.protocolId << ": " << info.dataPointsCount << std::endl; + } + else + cout << "CHYBA: " << licenceReaderELC2.error.message; + } + else + { + cout << "CHYBA: " << licenceReaderELC2.error.message; + } + + LicenceReader licenceReaderCompleteELC2{}; + //verze ELC 2 kompletní načtení + if (licenceReaderCompleteELC2.init(2, initStructure)) // iniciacni nacteni + { + LicenceELC2Info info; + int protocolId = 333; + + if (licenceReaderCompleteELC2.getLicenceInfo(&info)) + { + if (info.licences.count(protocolId) > 0) + cout << "Pocet bodu z vectoru pro protokol : " << protocolId << ": " << info.licences.at(protocolId) << "\n"; + else + cout << "Pro tento protokol nejsou definovay licencni body\n"; + cout << "Vypis vsech licencnich bodu: " << endl; + for (const auto &pair : info.licences) + { + std::cout << "<" << pair.first << ", " << pair.second << ">" << endl; + } + } + else + cout << "CHYBA: " << licenceReaderCompleteELC2.error.message; + + } + else + { + cout << "CHYBA: " << licenceReaderCompleteELC2.error.message; + } + + } + catch (...) + { + cout << "Obecna chyba\n"; + } + return SUCCES; +} + diff --git a/zdenda/src/common/SDCard.cpp b/zdenda/src/common/SDCard.cpp new file mode 100644 index 0000000..0f313f6 --- /dev/null +++ b/zdenda/src/common/SDCard.cpp @@ -0,0 +1,143 @@ +#include "utils.h" +#include "SDCard.h" + +SDCard::SDCard() +{ +} + +SDCard::SDCard(const string cds_cid_Path) +{ + this->filePath = cds_cid_Path; + if (getCIDFromFile() == false) + return; + if (getCSDFromFile() == false) + return; + this->isLoaded = SDCard::readSDCard(); +} + +SDCard::SDCard(string cid, string csd) +{ + for (unsigned int i = 0; i < cid.length(); i++) + this->cid[i] = cid[i]; + for (unsigned int i = 0; i < csd.length(); i++) + this->csd[i] = csd[i]; + + this->isLoaded = SDCard::readSDCard(); +} + +bool SDCard::readSDCard() +{ + + BYTE cHexNibbleToNo[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 0, 0, 0, 0, 0, 0, + 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + for (int i = 0; i < CID_LENGTH; i++) + this->cardData.CID_nibble[i] = (BYTE)cid[i]; + + for (int i = 0; i < cnibblescount / 2; i++) + { + this->cardData.CID[i] = cHexNibbleToNo[this->cardData.CID_nibble[2 * i]] << 4 | cHexNibbleToNo[this->cardData.CID_nibble[2 * i + 1]]; + } + + this->cardData.manufacturerID = this->cardData.CID[0]; + this->cardData.oemID[0] = this->cardData.CID[1]; + this->cardData.oemID[1] = this->cardData.CID[2]; + this->cardData.name[0] = this->cardData.CID[3]; + this->cardData.name[1] = this->cardData.CID[4]; + this->cardData.name[2] = this->cardData.CID[5]; + this->cardData.name[3] = this->cardData.CID[6]; + this->cardData.name[4] = this->cardData.CID[7]; + this->cardData.productRevision_hw = cHexNibbleToNo[this->cardData.CID[16]]; + this->cardData.productRevision_sw = cHexNibbleToNo[this->cardData.CID[17]]; + + if (this->cardData.productRevision_sw < 10) + this->cardData.productRevision = (float)this->cardData.productRevision_hw + ((float)this->cardData.productRevision_sw * 0.1); + else + this->cardData.productRevision = (float)this->cardData.productRevision_hw + ((float)this->cardData.productRevision_sw * 0.01); + + this->cardData.serialNumber = this->cardData.CID[9] << 24 | this->cardData.CID[10] << 16 | this->cardData.CID[11] << 8 | this->cardData.CID[12]; + + // CSD + for (int i = 0; i < CSD_LENGTH; i++) + this->cardData.CSD_nibble[i] = (BYTE)csd[i]; + + for (int i = 0; i < cnibblescount / 2; i++) + { + this->cardData.CSD[i] = cHexNibbleToNo[this->cardData.CSD_nibble[2 * i]] << 4 | cHexNibbleToNo[this->cardData.CSD_nibble[2 * i + 1]]; + } + + if (this->cardData.CSD_nibble[0] == 0x34) + { + this->cardData.cardSize = this->cardData.CSD[7] << 16 | this->cardData.CSD[8] << 8 | this->cardData.CSD[9]; + this->cardData.cardGSize = (this->cardData.cardSize + 1) / 2048; + } + + BYTE sdCrc = 0; + for (int i = 0; i <= 14; i++) + { + BYTE sdChar = this->cardData.CID[i]; + for (int j = 0; j <= 7; j++) + { + sdCrc = sdCrc << 1; + if ((sdChar ^ sdCrc) & 0x80) + sdCrc = sdCrc ^ 0x09; + sdChar = sdChar << 1; + } + sdCrc = sdCrc & 0x7F; + } + this->cardData.CRCOK = ((sdCrc << 1) | 1) == this->cardData.CID[15]; + this->cardData.crcCorrect = (int)this->cardData.CID[15] == (int)((sdCrc << 1) | 1); + return this->cardData.crcCorrect; +} + +bool SDCard::getCIDFromFile() +{ + vector content; + if (readFile(this->filePath + "cid", content) == false) + { + return false; + } + + if (content.size() >= CID_LENGTH) + { + for (int i = 0; i < 32; i++) + this->cid[i] = content[i]; + } + else + return false; + + return true; +} + +bool SDCard::getCSDFromFile() +{ + vector content; + if (readFile(this->filePath + "csd", content) == false) + { + return false; + } + if (content.size() >= CSD_LENGTH) + { + for (int i = 0; i < 32; i++) + this->csd[i] = content[i]; + } + else + return false; + + return true; +} diff --git a/zdenda/src/common/licData.xml b/zdenda/src/common/licData.xml new file mode 100644 index 0000000..6f67b1f --- /dev/null +++ b/zdenda/src/common/licData.xml @@ -0,0 +1,37 @@ + + +EOV_OSV +WAGO +Licence pro EOV_OSV +eov.ceskatrebova.ddts.cz +eov2 +Projekt XXX stanice YYY + + + Položka licence 1 + 111 + 100 + + + Položka licence 2 + 222 + 200 + + + Položka licence 3 + 333 + 300 + + + Položka licence 3 + 444 + 1600 + + + Položka licence 4 + 555 + 1999 + + + + \ No newline at end of file diff --git a/zdenda/src/common/licenceELC1.cpp b/zdenda/src/common/licenceELC1.cpp new file mode 100644 index 0000000..8edb22d --- /dev/null +++ b/zdenda/src/common/licenceELC1.cpp @@ -0,0 +1,218 @@ +#include "licenceELC1.h" +#include "utils.h" + +#define CID_LENGTH 32 +#define CSD_LENGTH 32 + +const std::string cEzLic_p78ou3_sdinfofilepath = "/sys/block/mmcblk0/device/"; +const std::string cEzLic_p78ou3_licencfilepath_f21 = "/mnt/mmc/ez_sys/licence/"; +const std::string cEzLic_p78ou3_licencfilepath_f17 = "/home/admin/ez/licence/"; +const string cEzLic_p78ou3_licencfilepath_f10 = "/root/ez_sys/licence/"; +const WORD maxDataToFile = 10000; // velikost datoveho bufferu pro ulozeni dat licence + +const BYTE licMaxCount = 100; +const DWORD cEzLic_p78ou3_CheckLicNumber_ERR = 0xFFFFFFFF; // 16#FFFFFFFF; // chybna identifikace licence +const DWORD cEzLic_p78ou3_CheckLicNumber_EOV1 = 3781234965; // cislo pro overeni licence EOV, OSV verze 1 +const BYTE cEzLic_p78ou3_CheckLicNumberId_ERR = 0; // id licence pro neidentifikovanou licenci +const BYTE cEzLic_p78ou3_CheckLicNumberId_EOV1 = 1; // id licence pro EOV, OSV verze 1 +const BYTE cEzLic_p78ou3_MaxCheckLicNumberId = cEzLic_p78ou3_CheckLicNumberId_EOV1; // pocet identifikatoru licenci +const DWORD cEzLic_p78ou3_CheckLicNumber[] = {cEzLic_p78ou3_CheckLicNumber_ERR, cEzLic_p78ou3_CheckLicNumber_EOV1}; +const WORD cEzLic_p78ou3_LicPrefixType_ELC1 = 1; // prefix typ1 = pouze zasifrovani dat +const WORD cEzLic_p78ou3_HeaderType_10 = 10; // hlavicka kriptovane casti verze 1.0 +const WORD cEzLic_p78ou3_DataType_10 = 10; // data licence verze 1.0 +const WORD cEzLic_p78ou3_SubType_10_10 = 0x0A0A; // subtype - verze hlavicky + verze data -> cEzLic_p78ou3_HeaderType_XX * 256 + cEzLic_p78ou3_DataType_XX +// ID aplikace +const WORD cEzLic_p78ou3_IDType_DDTS = 1; // aplikace DDTS +const WORD cEzLic_p78ou3_IDType_EOVOSV = 2; // aplikace EOV-OSV +const WORD cEzLic_p78ou3_IDType_DRT = 3; // aplikace DRT +// std::string cEzLic_p78ou3_IDTypeStrData11[] = {"neznamo", "DDTS", "EOV-OSV", "DRT"}; +const BYTE cnibblescount1 = 32; +std::string cSDMonthStr1[] = {"-", "I.", "II.", "III.", "IV.", "V.", "VI.", "VII.", "VIII.", "IX.", "X.", "XI.", "XII.", "-", "-", "-"}; +BYTE cHexNibble_to_No1[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 0, 0, 0, 0, 0, 0, 0, + 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + 10, 11, 12, 13, 14, 15, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +const string eoseovLicenceType = "EOV_OSV"; + +LicenceELC1::LicenceELC1() {} + +LicenceELC1::~LicenceELC1() {} + +LicenceELC1::LicenceELC1(LicenceIdentification &licIdentification) : lIdentification(licIdentification) +{ +} + +bool LicenceELC1::getSDData() +{ + for (int i = 0; i < CID_LENGTH; i++) this->sdData.CID_nibble[i] = (BYTE)cid[i]; + + for (int i = 0; i < cnibblescount / 2; i++) + { + this->sdData.CID[i] = cHexNibble_to_No1[this->sdData.CID_nibble[2 * i]] << 4 | cHexNibble_to_No1[this->sdData.CID_nibble[2 * i + 1]]; + } + + this->sdData.manufacturerID = this->sdData.CID[0]; + this->sdData.oemID[0] = this->sdData.CID[1]; + this->sdData.oemID[1] = this->sdData.CID[2]; + this->sdData.name[0] = this->sdData.CID[3]; + this->sdData.name[1] = this->sdData.CID[4]; + this->sdData.name[2] = this->sdData.CID[5]; + this->sdData.name[3] = this->sdData.CID[6]; + this->sdData.name[4] = this->sdData.CID[7]; + this->sdData.productRevision_hw = cHexNibble_to_No1[this->sdData.CID[16]]; + this->sdData.productRevision_sw = cHexNibble_to_No1[this->sdData.CID[17]]; + + if (this->sdData.productRevision_sw < 10) + this->sdData.productRevision = (float)this->sdData.productRevision_hw + ((float)this->sdData.productRevision_sw * 0.1); + else + this->sdData.productRevision = (float)this->sdData.productRevision_hw + ((float)this->sdData.productRevision_sw * 0.01); + + this->sdData.serialNumber = this->sdData.CID[9] << 24 | this->sdData.CID[10] << 16 | this->sdData.CID[11] << 8 | this->sdData.CID[12]; + this->sdData.manufacturerDate_year = cHexNibble_to_No1[this->sdData.CID_nibble[27]] * 10 + cHexNibble_to_No1[this->sdData.CID_nibble[28]] + 2000; + this->sdData.manufacturerDate_month = cHexNibble_to_No1[this->sdData.CID_nibble[29]]; + string date = cSDMonthStr1[this->sdData.manufacturerDate_month] + std::to_string(this->sdData.manufacturerDate_year); + + for (unsigned i = 0; i < date.length(); i++) + this->sdData.manufacturerDate[i] = date[i]; + + // CSD + for (unsigned int i = 0; i < CSD_LENGTH; i++) this->sdData.CSD_nibble[i] = (BYTE)csd[i]; + + for (unsigned int i = 0; i < cnibblescount / 2; i++) + { + this->sdData.CSD[i] = cHexNibble_to_No1[this->sdData.CSD_nibble[2 * i]] << 4 | cHexNibble_to_No1[this->sdData.CSD_nibble[2 * i + 1]]; + } + + if (this->sdData.CSD_nibble[0] == 0x34) + { + this->sdData.cardSize = this->sdData.CSD[7] << 16 | this->sdData.CSD[8] << 8 | this->sdData.CSD[9]; + this->sdData.cardGSize = (this->sdData.cardSize + 1) / 2048; + } + + BYTE sdCrc = 0; + for (int i = 0; i <= 14; i++) + { + BYTE sdChar = this->sdData.CID[i]; + for (int j = 0; j <= 7; j++) + { + sdCrc = sdCrc << 1; + if ((sdChar ^ sdCrc) & 0x80) + sdCrc = sdCrc ^ 0x09; + sdChar = sdChar << 1; + } + sdCrc = sdCrc & 0x7F; + } + this->sdData.CRCOK = ((sdCrc << 1) | 1) == this->sdData.CID[15]; + + return (int)this->sdData.CID[15] == (int)((sdCrc << 1) | 1); + +} + +void LicenceELC1::initCrypto() +{ + if (this->licType == cEzLic_p78ou3_IDType_EOVOSV) + { + this->cryptData.aesInitVector[0] = this->sdData.CID[10]; + this->cryptData.aesInitVector[1] = this->sdData.CID[12]; + this->cryptData.aesInitVector[2] = this->sdData.CID[11]; + this->cryptData.aesInitVector[3] = this->sdData.CID[9]; + this->cryptData.aesInitVector[4] = this->sdData.CID_nibble[22] - 15; + this->cryptData.aesInitVector[5] = this->sdData.CID_nibble[24] - 15; + this->cryptData.aesInitVector[6] = this->sdData.CID_nibble[25] - 15; + this->cryptData.aesInitVector[7] = this->sdData.CID_nibble[21] - 15; + memcpy(&this->cryptData.aesInitVector[8], &this->cryptData.aesInitVector[0], 8); + + this->cryptData.aesKey[0] = this->sdData.CID[12]; + this->cryptData.aesKey[1] = this->sdData.CID_nibble[23] - 15; + this->cryptData.aesKey[2] = this->sdData.CID_nibble[25] - 15; + this->cryptData.aesKey[3] = this->sdData.CID[11]; + this->cryptData.aesKey[4] = this->sdData.CID[9]; + this->cryptData.aesKey[5] = this->sdData.CID_nibble[21] - 15; + this->cryptData.aesKey[6] = 97 + this->sdData.CID[9] % 25; + this->cryptData.aesKey[7] = this->sdData.CID_nibble[22] - 15; + memcpy(&this->cryptData.aesKey[8], &this->cryptData.aesKey[0], 8); + memcpy(&this->cryptData.aesKey[16], &this->cryptData.aesKey[6], 8); + memcpy(&this->cryptData.aesKey[24], &this->cryptData.aesKey[12], 8); + } +} + +string LicenceELC1::getLicenceName() +{ + string result = ""; + char prefixChar = 97; + int licIndex = lIdentification.licenceIndex; + + // natvrdo, stará ELC + result = "ezlic_eovosv" + to_string(licIndex) + "_"; + result += prefixChar + (this->sdCard.cardData.CID[12] % 25); + result += prefixChar + (this->sdCard.cardData.CID[10] % 25); + result += prefixChar + (this->sdCard.cardData.CID_nibble[22] % 25); + result += prefixChar + ((this->sdCard.cardData.CID_nibble[23] * 2) % 25); + result += prefixChar + (this->sdCard.cardData.CID_nibble[24] % 25); + result += prefixChar + ((this->sdCard.cardData.CID_nibble[25] * 3) % 25); + result += prefixChar + (this->sdCard.cardData.CID[9] % 25); + result += prefixChar + (this->sdCard.cardData.CID[11] % 25); + result += prefixChar + (this->sdCard.cardData.CID[2] % 25); + result += prefixChar + (this->sdCard.cardData.CID[1] % 25); + result += prefixChar + (this->sdCard.cardData.CID[3] % 25); + result += ".lic"; + + return result; +} + +/// @brief get proper licencename +/// @param licPostfix +/// @return +string LicenceELC1::getLicenceName(BYTE licPostfix) +{ + string result = ""; + char prefixChar = 97; + + if (licType == PlcLicenceType::LicenceOther) + { + result = "ezlic_"; + result += prefixChar + (this->sdData.CID[12] % 25); + result += prefixChar + (this->sdData.CID[10] % 25); + result += prefixChar + (this->sdData.CID_nibble[22] % 25); + result += prefixChar + ((this->sdData.CID_nibble[23] * 2) % 25); + result += prefixChar + (this->sdData.CID_nibble[24] % 25); + result += prefixChar + ((this->sdData.CID_nibble[25] * 3) % 25); + result += prefixChar + (this->sdData.CID[9] % 25); + result += prefixChar + (this->sdData.CID[11] % 25); + result += prefixChar + (this->sdData.CID[2] % 25); + result += prefixChar + (this->sdData.CID[1] % 25); + result += prefixChar + (this->sdData.CID[3] % 25); + result += ".lic"; + } + else + { + result = "ezlic_eovosv" + to_string(licPostfix) + "_"; + result += prefixChar + (this->sdData.CID[12] % 25); + result += prefixChar + (this->sdData.CID[10] % 25); + result += prefixChar + (this->sdData.CID_nibble[22] % 25); + result += prefixChar + ((this->sdData.CID_nibble[23] * 2) % 25); + result += prefixChar + (this->sdData.CID_nibble[24] % 25); + result += prefixChar + ((this->sdData.CID_nibble[25] * 3) % 25); + result += prefixChar + (this->sdData.CID[9] % 25); + result += prefixChar + (this->sdData.CID[11] % 25); + result += prefixChar + (this->sdData.CID[2] % 25); + result += prefixChar + (this->sdData.CID[1] % 25); + result += prefixChar + (this->sdData.CID[3] % 25); + result += ".lic"; + } + return result; +} diff --git a/zdenda/src/common/licenceELC2.cpp b/zdenda/src/common/licenceELC2.cpp new file mode 100644 index 0000000..fa2b48d --- /dev/null +++ b/zdenda/src/common/licenceELC2.cpp @@ -0,0 +1,172 @@ +#include "licenceELC2.h" +#include "utils.h" + + + LicenceELC2::LicenceELC2(){} + + LicenceELC2::~LicenceELC2(){} + + LicenceELC2::LicenceELC2(LicenceIdentification &licIdentification): lIdentification(licIdentification) + {} + + /// @brief get proper licencename +/// @param licPostfix +/// @return +string LicenceELC2::getLicenceName() +{ + string result = ""; + char prefixChar = 97; + int licType = (int)lIdentification.licLicenceType; + int lVersion = lIdentification.licenceVersion; + + unordered_map baseString; + baseString.insert(std::pair((int)LicenceType::EOS_EOV, "ezlic_eovosv")); + baseString.insert(std::pair((int)LicenceType::DDTS, "ezlic_ddts")); + baseString.insert(std::pair((int)LicenceType::DRT, "ezlic_drt")); + + struct Index + { + int index[11]; + }; + + std::unordered_map indexes; + Index indexes1 = {7, 16, 20, 23, 18, 4, 9, 11, 6, 9, 13}; + Index indexes2 = {12, 10, 22, 23, 24, 25, 9, 11, 2, 1, 3}; // puvodní indexy + Index indexes3 = {8, 13, 11, 9, 7, 11, 10, 13, 5, 20, 19}; + + indexes.insert(std::pair(1, indexes1)); + indexes.insert(std::pair(2, indexes2)); + indexes.insert(std::pair(3, indexes3)); + + result = baseString.at(licType) + to_string(lIdentification.licenceIndex) + "_"; + + result += prefixChar + ((this->sdCard.cardData.CID[indexes.at(lVersion).index[0]] + (lIdentification.licenceIndex * 11)) % 25); + result += prefixChar + ((this->sdCard.cardData.CID[indexes.at(lVersion).index[1]] + (lIdentification.licenceIndex * 39)) % 25); + + result += prefixChar + ((this->sdCard.cardData.CID_nibble[indexes.at(lVersion).index[2]] + (lIdentification.licenceIndex * 1)) % 25); + result += prefixChar + ((this->sdCard.cardData.CID_nibble[indexes.at(lVersion).index[3]] * 2) % 25); + result += prefixChar + ((this->sdCard.cardData.CID_nibble[indexes.at(lVersion).index[4]] + (lIdentification.licenceIndex * 5)) % 25); + result += prefixChar + ((this->sdCard.cardData.CID_nibble[indexes.at(lVersion).index[5]] * 3) % 25); + + result += prefixChar + ((this->sdCard.cardData.CID[indexes.at(lVersion).index[6]] + (lIdentification.licenceIndex * 52)) % 25); + result += prefixChar + ((this->sdCard.cardData.CID[indexes.at(lVersion).index[7]] + (lIdentification.licenceIndex * 34)) % 25); + result += prefixChar + ((this->sdCard.cardData.CID[indexes.at(lVersion).index[8]] + (lIdentification.licenceIndex * 21)) % 25); + result += prefixChar + ((this->sdCard.cardData.CID[indexes.at(lVersion).index[9]] + (lIdentification.licenceIndex * 47)) % 25); + result += prefixChar + ((this->sdCard.cardData.CID[indexes.at(lVersion).index[10]] + (lIdentification.licenceIndex * 7)) % 25); + + result += ".lic"; + return result; +} + +vector LicenceELC2::cryptPrivateContent(const std::vector &content) +{ + + BYTE initVector[15] = {}; + BYTE aesKey[32] = {}; + + LicenceELC2::initVector(initVector, aesKey); + + unsigned char encrypted[10000] = {}; + const unsigned char *plainTextArray = content.data(); + int finalEncryptedLength = encrypt(plainTextArray, content.size(), aesKey, initVector, encrypted); + + if (finalEncryptedLength <= 0) throw LicenceException((int)GeneralError::EncryptError, "Chyba při kryptování."); + + std::vector result(encrypted, encrypted + finalEncryptedLength); + + return result; +} + +vector LicenceELC2::decryptPrivateContent(const std::vector &content) +{ + + BYTE initVector[15] = {0}; + BYTE aesKey[32] = {0}; + + LicenceELC2::initVector(initVector, aesKey); + + const unsigned char *encryptedData = content.data(); + unsigned char decrypted[10000] = {}; + + int decrypted_len = decrypt(encryptedData, content.size(), aesKey, initVector, decrypted); + if (decrypted_len <= 0) throw LicenceException((int)GeneralError::DecryptError, "Chyba při dekryptování."); + + std::vector result(decrypted, decrypted + decrypted_len); + + return result; +} + +void LicenceELC2::initVector(BYTE (&iVector)[], BYTE (&key)[]) +{ + + struct Vector15 + { + int vec[15]; + }; + + Vector15 vec1 = {this->sdCard.cardData.CID[10], + this->sdCard.cardData.CID[12], + this->sdCard.cardData.CID[11], + this->sdCard.cardData.CID[9], + this->sdCard.cardData.CID_nibble[22] - 15, + this->sdCard.cardData.CID_nibble[24] - 15, + this->sdCard.cardData.CID_nibble[25] - 15, + this->sdCard.cardData.CID_nibble[21] - 15, + 9, 10, 11, 12, 13, 14, 15}; + Vector15 vec2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; //TODO přidat smysluplnější indexy + Vector15 vec3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; + + std::unordered_map vectors; + vectors.insert(std::pair(1, vec1)); + vectors.insert(std::pair(2, vec2)); + vectors.insert(std::pair(3, vec3)); + + struct Key32 + { + int key[32]; + }; + + Key32 key1 = {this->sdCard.cardData.CID[12], + this->sdCard.cardData.CID[23] - 15, + this->sdCard.cardData.CID[25] - 15, + this->sdCard.cardData.CID[11], + this->sdCard.cardData.CID[9], + this->sdCard.cardData.CID_nibble[21], + this->sdCard.cardData.CID[9] % 25, + this->sdCard.cardData.CID_nibble[22] - 15, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}; + Key32 key2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + Key32 key3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + + std::unordered_map keys; + keys.insert(std::pair(1, key1)); + keys.insert(std::pair(2, key2)); + keys.insert(std::pair(3, key3)); + + int lVersion = lIdentification.licenceVersion; + + iVector[0] = vectors.at(lVersion).vec[0]; + iVector[1] = vectors.at(lVersion).vec[1]; + iVector[2] = vectors.at(lVersion).vec[2]; + iVector[3] = vectors.at(lVersion).vec[3]; + iVector[4] = vectors.at(lVersion).vec[4]; + iVector[5] = vectors.at(lVersion).vec[5]; + iVector[6] = vectors.at(lVersion).vec[6]; + iVector[7] = vectors.at(lVersion).vec[7]; + + memcpy(&iVector[8], &iVector[0], 8); + + key[0] = keys.at(lVersion).key[0]; + key[1] = keys.at(lVersion).key[1]; + key[2] = keys.at(lVersion).key[2]; + key[3] = keys.at(lVersion).key[3]; + key[4] = keys.at(lVersion).key[4]; + key[5] = keys.at(lVersion).key[5]; + key[6] = keys.at(lVersion).key[6]; + key[7] = keys.at(lVersion).key[7]; + memcpy(&key[8], &key[0], 8); + memcpy(&key[16], &key[6], 8); + memcpy(&key[24], &key[12], 8); +} + + diff --git a/zdenda/src/common/utils.cpp b/zdenda/src/common/utils.cpp new file mode 100644 index 0000000..efbdf67 --- /dev/null +++ b/zdenda/src/common/utils.cpp @@ -0,0 +1,463 @@ + +#include +#include /* core library */ +#include "utils.h" + +using namespace std; + +const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +const char base64_url_alphabet[] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'}; + +void getCharsFromString(string &source, char *charArray, size_t length) +{ + for (size_t i = 0; i < length; i++) + { + charArray[i] = source[i]; + } +} + +void getCharsFromString(string source, char *charArray) +{ + size_t length = source.length(); + for (size_t i = 0; i < length; i++) + { + charArray[i] = source[i]; + } +} + +std::string right(const std::string &sourceString, size_t numChars) +{ + if (numChars >= sourceString.size()) + { + return sourceString; // If numChars is greater or equal to the string size, return the whole string. + } + return sourceString.substr(sourceString.size() - numChars); +} + +uint16_t calculateCRC16(const uint8_t *data, size_t length) +{ + const uint16_t polynomial = 0xA001; // CRC16-CCITT polynomial + uint16_t crc = 0xFFFF; // Initial value + + for (size_t i = 0; i < length; i++) + { + crc ^= data[i]; // XOR with the current data byte + + for (int j = 0; j < 8; j++) + { + if (crc & 0x0001) + { + crc = (crc >> 1) ^ polynomial; + } + else + { + crc = crc >> 1; + } + } + } + + return crc; +} + +uint16_t crc16(const unsigned char *data_p, unsigned char length) +{ + uint16_t x; + uint16_t crc = 0xFFFF; + + while (length--) + { + x = crc >> 8 ^ *data_p++; + x ^= x >> 4; + crc = (crc << 8) ^ ((unsigned short)(x << 12)) ^ ((unsigned short)(x << 5)) ^ ((unsigned short)x); + } + return crc; +} + +DATE getLicDate() +{ + time_t ttime = time(0); + tm *local_time = localtime(&ttime); + int hoursSeconds = 3600 * local_time->tm_hour; + int minutesSeconds = 60 * local_time->tm_min; + int seconds = 1 * local_time->tm_sec; + int totalSeconds = hoursSeconds + minutesSeconds + seconds; + +#ifdef WINDOWS + DATE dateOnly = ttime - totalSeconds + 7200; // (pro windows); // 7200 + vteřina za dvě hodiny pro srování +#else + DATE dateOnly = ttime - totalSeconds; +#endif + + return dateOnly; +} + +string getDate() +{ + auto r = std::chrono::system_clock::now(); + auto rp = std::chrono::system_clock::to_time_t(r); + std::string h(ctime(&rp)); // converting to c++ string + return h; +} + +int encrypt(const unsigned char *plaintext, int plaintext_len, unsigned char *key, + unsigned char *iv, unsigned char *ciphertext) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + int ciphertext_len; + + /* Create and initialise the context */ + if (!(ctx = EVP_CIPHER_CTX_new())) + return -1; + + /* + * Initialise the encryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if (1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) + return -1; + + /* + * Provide the message to be encrypted, and obtain the encrypted output. + * EVP_EncryptUpdate can be called multiple times if necessary + */ + if (1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len)) + return -1; + ciphertext_len = len; + + /* + * Finalise the encryption. Further ciphertext bytes may be written at + * this stage. + */ + if (1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) + return -1; + ciphertext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return ciphertext_len; +} + +int decrypt(const unsigned char *ciphertext, int ciphertext_len, unsigned char *key, + unsigned char *iv, unsigned char *plaintext) +{ + EVP_CIPHER_CTX *ctx; + + int len; + + int plaintext_len; + + /* Create and initialise the context */ + if (!(ctx = EVP_CIPHER_CTX_new())) + return -1; + + /* + * Initialise the decryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) + return -1; + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary. + */ + if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) + return -1; + plaintext_len = len; + + /* + * Finalise the decryption. Further plaintext bytes may be written at + * this stage. + */ + if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) + return -1; + + plaintext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return plaintext_len; +} + +// converts character array +// to string and returns it +string convertToString(char *a, int size) +{ + int i; + string s = ""; + for (i = 0; i < size; i++) + { + s = s + a[i]; + } + return s; +} + +std::string base64_decode(const std::string &in) +{ + std::string out; + std::vector T(256, -1); + unsigned int i; + for (i = 0; i < 64; i++) + T[base64_url_alphabet[i]] = i; + + int val = 0, valb = -8; + for (i = 0; i < in.length(); i++) + { + unsigned char c = in[i]; + if (T[c] == -1) + break; + val = (val << 6) + T[c]; + valb += 6; + if (valb >= 0) + { + out.push_back(char((val >> valb) & 0xFF)); + valb -= 8; + } + } + return out; +} + +std::string base64_encode_ai(const std::string &input) +{ + std::string encoded; + + size_t input_length = input.length(); + size_t i = 0; + + while (i < input_length) + { + unsigned char input_chunk[3] = {0}; + size_t chunk_size = 0; + + // Fill the input chunk with up to 3 bytes from the input string + for (size_t j = 0; j < 3; ++j) + { + if (i < input_length) + { + input_chunk[j] = input[i++]; + ++chunk_size; + } + } + + // Encode the input chunk into 4 Base64 characters + encoded += base64_chars[(input_chunk[0] & 0xFC) >> 2]; + encoded += base64_chars[((input_chunk[0] & 0x03) << 4) | + ((input_chunk[1] & 0xF0) >> 4)]; + encoded += (chunk_size > 1) + ? base64_chars[((input_chunk[1] & 0x0F) << 2) | + ((input_chunk[2] & 0xC0) >> 6)] + : '='; + encoded += (chunk_size > 2) + ? base64_chars[input_chunk[2] & 0x3F] + : '='; + } + + return encoded; +} + +unordered_map getArguments(int argc, char *argv[]) +{ + const char splitChar = '='; + unordered_map result; + if (argc <= 1) + return result; + + for (int i = 1; i < argc; ++i) + { + bool isArgName = true; + int argLength = strlen(argv[i]); + string argName; + string argValue; + + for (int j = 0; j < argLength; j++) + { + if (argv[i][j] == splitChar) + { + isArgName = false; + continue; + } + + if (isArgName) + { + argName += argv[i][j]; + } + else + { + argValue += argv[i][j]; + } + } + + result.insert(make_pair(argName, argValue)); + } + return result; +} + +string getCompletePath(string fileName) +{ +#ifdef WINDOWS + return fileName; +#else + + char path[PATH_MAX + 1] = {}; + ssize_t length = readlink("/proc/self/exe", path, PATH_MAX); + path[length] = '\0'; + string result = string(dirname(path)) + "/" + fileName; + return result; + // return std::string( result, (count > 0) ? count : 0 ); + // std::filesystem::path exePath = std::filesystem::canonical("/proc/self/exe"); // / std::filesystem::path(argv[0])); + // std::filesystem::path fullPathOther = exePath.parent_path() / fileName; + // std::string fullPathStrOther = fullPathOther.string(); + // return fullPathStrOther; +#endif +} + +void appendStringToVector(const std::string &str, std::vector &charVector) +{ + size_t strLength = str.length(); + for (size_t i = 0; i < strLength; ++i) + { + charVector.push_back(static_cast(str[i])); + } +} + +uint16_t calculateCRC16(std::vector &charVector) +{ + const uint16_t polynomial = 0xA001; // CRC16-CCITT polynomial + uint16_t crc = 0xFFFF; // Initial value + + size_t length = charVector.size(); + + for (size_t i = 0; i < length; i++) + { + crc ^= charVector[i]; // XOR with the current data byte + + for (int j = 0; j < 8; j++) + { + if (crc & 0x0001) + { + crc = (crc >> 1) ^ polynomial; + } + else + { + crc = crc >> 1; + } + } + } + + return crc; +} + +uint16_t calculateCRC16(std::vector &charVector) +{ + const uint16_t polynomial = 0xA001; // CRC16-CCITT polynomial + uint16_t crc = 0xFFFF; // Initial value + + size_t length = charVector.size(); + + for (size_t i = 0; i < length; i++) + { + crc ^= charVector[i]; // XOR with the current data byte + + for (int j = 0; j < 8; j++) + { + if (crc & 0x0001) + { + crc = (crc >> 1) ^ polynomial; + } + else + { + crc = crc >> 1; + } + } + } + + return crc; +} + +uint16_t calculateCRC16(std::vector &charVector, int removeCount) +{ + const uint16_t polynomial = 0xA001; // CRC16-CCITT polynomial + uint16_t crc = 0xFFFF; // Initial value + + size_t length = charVector.size(); + length = length-removeCount; + + for (size_t i = 0; i < length; i++) + { + crc ^= charVector[i]; // XOR with the current data byte + + for (int j = 0; j < 8; j++) + { + if (crc & 0x0001) + { + crc = (crc >> 1) ^ polynomial; + } + else + { + crc = crc >> 1; + } + } + } + + return crc; +} + +uint32_t bytesToDword(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) +{ + return static_cast(byte1) | + (static_cast(byte2) << 8) | + (static_cast(byte3) << 16) | + (static_cast(byte4) << 24); +} + +uint32_t bytesToWord(uint8_t byte1, uint8_t byte2) +{ + return static_cast(byte1) | (static_cast(byte2) << 8); +} + +std::vector joinVectors(const std::vector &vector1, const std::vector &vector2) +{ + std::vector result; + result.insert(result.end(), vector1.begin(), vector1.end()); + result.insert(result.end(), vector2.begin(), vector2.end()); + return result; +} + +bool readFile(string fileName, vector &output) +{ + std::ifstream file(fileName, std::ios::in | std::ios::binary); + + if (file.is_open() != 1) + { + return false; + } + + char byte; + while (file.get(byte)) + { + // Convert the char to unsigned char and push it into the vector + output.push_back(byte); + } + + file.close(); + + return true; +} diff --git a/zdenda/src/output/cid b/zdenda/src/output/cid new file mode 100644 index 0000000..9a70e3e --- /dev/null +++ b/zdenda/src/output/cid @@ -0,0 +1,5 @@ +9f54495344434954615ad803c50171bf +6   . x4   .. nt$6 & manfid 6 +  cid "6  fwrev 6 Jm  csd ,6 gEd$ +subsystem 46 % +driver (6 -  ocr -6 ? power *6 4L  type 6 1M  date #6 rTP hwrev )6 nyR  dsr '6 ` serial 6 NNm erase_size 6 6m block 6 n uevent 6 o  ssr 6 q  scr &6 &y oemid !6 y ( preferred_erase_size %6   name \ No newline at end of file diff --git a/zdenda/src/output/csd b/zdenda/src/output/csd new file mode 100644 index 0000000..609cf45 --- /dev/null +++ b/zdenda/src/output/csd @@ -0,0 +1,2 @@ +400e00325b5900003be77f800a400043 + \ No newline at end of file diff --git a/zdenda/src/output/ezlic_eovosv0_jjacdgpdxpb.lic b/zdenda/src/output/ezlic_eovosv0_jjacdgpdxpb.lic new file mode 100644 index 0000000..4efdd87 Binary files /dev/null and b/zdenda/src/output/ezlic_eovosv0_jjacdgpdxpb.lic differ diff --git a/zdenda/src/output/ezlic_eovosv0_wqxcyjpdxji.lic b/zdenda/src/output/ezlic_eovosv0_wqxcyjpdxji.lic new file mode 100644 index 0000000..6731e88 Binary files /dev/null and b/zdenda/src/output/ezlic_eovosv0_wqxcyjpdxji.lic differ diff --git a/zdenda/src/output/licData.xml b/zdenda/src/output/licData.xml new file mode 100644 index 0000000..47acd9a --- /dev/null +++ b/zdenda/src/output/licData.xml @@ -0,0 +1,27 @@ + + +EOV_OSV +WAGO +Licence pro EOV_OSV +odb.zaluzi.drt.cz +POZ8 +Projekt XXX stanice YYY + + + Položka licence 1 + 111 + 40000 + + + Položka licence 2 + 222 + 51000 + + + Položka licence 3 + 333 + 62000 + + + + \ No newline at end of file diff --git a/zdenda/src/reader/LicenceReader.cpp b/zdenda/src/reader/LicenceReader.cpp new file mode 100644 index 0000000..c86ab44 --- /dev/null +++ b/zdenda/src/reader/LicenceReader.cpp @@ -0,0 +1,265 @@ +#include + +ELCType licElcType = ELCType::ELC2; +LicenceType licLicenceType; +PlcType licPlcType; + +uint8_t licenceVersion = 1; // verze licence, určitě kodování, pojmenování souborů +uint8_t licenceIndex = 0; +uint8_t revision; +uint8_t licCompatibility = 1; // identikator hlavního ELC + +LicenceReader::LicenceReader() +{ +} + +/// @brief provede pouze inicialazaci čtecí třídy +/// @param elcType +/// @param initStructure +/// @return +bool LicenceReader::init(int elcType, InitStructure &initStructure) +{ + try + { + if (elcType > 3) + { + error.code = (int)GeneralError::ELCNotImplemented; + error.message = "ELC není implementováno."; + throw LicenceException((int)GeneralError::ELCNotImplemented, error.message); + } + + this->licIdentification.licElcType = (ELCType)elcType; + this->licIdentification.licLicenceType = (LicenceType)initStructure.licenceType; + this->licIdentification.licenceVersion = licenceVersion; + this->licIdentification.licenceIndex = licenceIndex; + this->licIdentification.licCompatibility = initStructure.compatibility; + } + catch (const LicenceException &ex) + { + error.code = ex.getErrorCode(); + error.message = ex.getErrorMessage(); + return false; + } + + elcSwitchType = elcType * 10 + licCompatibility; + + return true; +} + +/// @brief provede inicializaci čtecí třídy a zároveň načte licenční body do obecné struktury +/// @param elcType +/// @param licenceType +/// @param licenceVersion +/// @param licenceIndex +/// @param compatibility +/// @return +bool LicenceReader::initread(int elcType, InitStructure &initStructure) +{ + try + { + elcSwitchType = elcType * 10 + initStructure.compatibility; + + if (init(elcType, initStructure)) + { + switch (this->licIdentification.licElcType) + { + case ELCType::ELC1: + { // old eoseov + Reader::Licence1 licenceELC1 = Reader::Licence1(this->licIdentification); + this->licence1 = &licenceELC1; + licenceELC1.cid_cdsPath = initStructure.cid_csd_filePath; + licenceELC1.licenceFilePath = initStructure.licenceFilePath; + + try + { + this->licence1->readLicence(&this->licenceInfo); + } + catch (const LicenceException &ex) + { + error.code = ex.getErrorCode(); + error.message = ex.getErrorMessage(); + return false; + } + break; + } + case ELCType::ELC2: + { + Reader::Licence2 licenceELC2 = Reader::Licence2(this->licIdentification); + this->licence2 = &licenceELC2; + licenceELC2.cid_cdsPath = initStructure.cid_csd_filePath; + licenceELC2.licenceFilePath = initStructure.licenceFilePath; + this->licence2->readLicence(&this->licenceInfo); + break; + } + case ELCType::ELC3: + { + break; + } + default: + throw LicenceException((int)GeneralError::ELCNotImplemented, "Toto ELC není implementováno"); + } + } + else + return false; + } + catch (const LicenceException &ex) + { + error.code = ex.getErrorCode(); + error.message = ex.getErrorMessage(); + return false; + } + + return true; // TODO testy +} + +/// @brief vrací informace o licenčím bodu na základě id protocolu a předané návratové struktury +/// @param protocolId +/// @param returnItemStructure +/// @return +bool LicenceReader::getLicenceItemInfo(int protocolId, void *returnItemStructure) +{ + try + { + switch (this->licIdentification.licElcType) + { + case ELCType::ELC1: + { + if (!this->licIdentification.licCompatibility) // defaultní kompatibilita + { + LicenceELC1Info *resultPtr = static_cast(returnItemStructure); + if (this->licenceInfo.licences.count(1)) // stare eov má natvrdo "id" 1. + resultPtr->isValid = true; + else + resultPtr->isValid = false; + } + else + { + LicenceException((int)GeneralError::CompatibilityTypeNotImplemented, "Kompatibilita není implementována."); + } + break; + } + case ELCType::ELC2: + { + if (!this->licIdentification.licCompatibility) // defaultní kompatibilita + { + LicenceELC2Item *resultPtr = static_cast(returnItemStructure); + resultPtr->protocolId = protocolId; // protocolId; + if (this->licenceInfo.licences.count(protocolId)) + resultPtr->dataPointsCount = this->licenceInfo.licences.at(protocolId); + else + resultPtr->dataPointsCount = 0; + } + else + { + switch (this->licIdentification.licCompatibility) + { + case 1: + // kod pro kompatibilitu 1 + break; + default: + LicenceException((int)GeneralError::CompatibilityTypeNotImplemented, "Kompatibilita není implementována."); + break; + } + } + break; + } + case ELCType::ELC3: + { + break; + } + default: + { + error.code = -1; + error.message = "Nepodařilo se identifikovat licenci"; + return false; + } + } + } + catch (const LicenceException &ex) + { + error.code = ex.getErrorCode(); + error.message = ex.getErrorMessage(); + return false; + } + + return true; +} + +/// @brief vrací informace o všech licenčních bodech základě předané návratové struktury +/// @param returnStructure +/// @return +bool LicenceReader::getLicenceInfo(void *returnStructure) +{ + try + { + switch (this->licIdentification.licElcType) + { + case ELCType::ELC1: + { // old eoseov + if (!this->licIdentification.licCompatibility) // defaultní kompatibilita + { + LicenceELC1Info *resultPtr = static_cast(returnStructure); + + if (this->licenceInfo.licences.count(1)) // starý EOS má natvrdo "id" 1 + { + resultPtr->isValid = true; + } + else + { + resultPtr->isValid = false; + } + } + else + { + switch (this->licIdentification.licCompatibility) + { + case 1: + // kod pro kompatibilitu 1 + break; + default: + LicenceException((int)GeneralError::CompatibilityTypeNotImplemented, "Kompatibilita není implementována."); + break; + } + } + break; + } + case ELCType::ELC2: + { + if (!this->licIdentification.licCompatibility) // defaultní kompatibilita + { + Reader::Licence2 licenceELC2 = Reader::Licence2(this->licIdentification); + licenceELC2.readLicence(&this->licenceInfo); + licenceELC2.getLicenceInfo(returnStructure); + } + else + { + switch (this->licIdentification.licCompatibility) + { + case 1: + // kod pro kompatibilitu 1 + break; + default: + LicenceException((int)GeneralError::CompatibilityTypeNotImplemented, "Kompatibilita není implementována."); + break; + } + } + break; + } + case ELCType::ELC3: + { + break; + } + } + } + catch (const LicenceException &ex) + { + error.code = ex.getErrorCode(); + error.message = ex.getErrorMessage(); + return false; + } + return true; +} + +LicenceReader::~LicenceReader() +{ +} diff --git a/zdenda/src/reader/licData.xml b/zdenda/src/reader/licData.xml new file mode 100644 index 0000000..6f67b1f --- /dev/null +++ b/zdenda/src/reader/licData.xml @@ -0,0 +1,37 @@ + + +EOV_OSV +WAGO +Licence pro EOV_OSV +eov.ceskatrebova.ddts.cz +eov2 +Projekt XXX stanice YYY + + + Položka licence 1 + 111 + 100 + + + Položka licence 2 + 222 + 200 + + + Položka licence 3 + 333 + 300 + + + Položka licence 3 + 444 + 1600 + + + Položka licence 4 + 555 + 1999 + + + + \ No newline at end of file diff --git a/zdenda/src/reader/licReaderELC1.cpp b/zdenda/src/reader/licReaderELC1.cpp new file mode 100644 index 0000000..52ecad6 --- /dev/null +++ b/zdenda/src/reader/licReaderELC1.cpp @@ -0,0 +1,124 @@ +#include "licReaderELC1.h" + +namespace Reader +{ + Licence1::Licence1() {} + + Licence1::~Licence1() {} + + Licence1::Licence1(LicenceIdentification &licIdentification) : LicenceELC1(licIdentification) + { + } + + /// @brief načte seznam licenčních bodů do obecné struktury + /// @param licences + /// @return + bool Licence1::readLicence(LicenceInfoGeneral *licences) + { + sdCard = SDCard(this->cid_cdsPath); + if (sdCard.isLoaded == false) throw LicenceException((int)GeneralError::SDCardReadError, "Chyba při čtení SD karty, cesta: " + cid_cdsPath); + + for (unsigned int i = 0; i < CID_LENGTH;i++) this->cid[i] = sdCard.cid[i]; + for (unsigned int i = 0; i < CSD_LENGTH;i++) this->csd[i] = sdCard.csd[i]; + + if (getSDData() == false) throw LicenceException((int)GeneralError::SDCardReadError, "Chyba při čtení SD karty, cesta: " + cid_cdsPath); + + string licFileName = getLicenceName(0); + string licFilePath = this->licenceFilePath + licFileName; + + char licFileNameToRead[licFilePath.length()+1] = {}; + getCharsFromString(licFilePath, licFileNameToRead, licFilePath.length()); + + FILE *licenceFile; + char ch; + + licenceFile = fopen(licFileNameToRead, "rb"); + + if (licenceFile == nullptr) throw LicenceException((int)GeneralError::LicenceReadError, "LicenceReadError: " + licFilePath); + + fseek(licenceFile, 0, SEEK_END); + const int size = ftell(licenceFile); + fseek(licenceFile, 0, SEEK_SET); + + if (size <= 0) throw LicenceException((int)GeneralError::LicenceSizeMismatch, "LicenceSizeMismatch: " + licFilePath); + + int count = 0; + + unsigned char licenceContent[size]; + + for (int i = 0; i < size; i++) + { + ch = fgetc(licenceFile); + licenceContent[i] = ch; + count++; + } + + fclose(licenceFile); + + LicenceDataMainELC licenceHeader{}; + LicenceData licEncryptedData{}; + + memcpy(&licenceHeader, licenceContent, sizeof(LicenceDataMainELC)); + + const int sizeOfEncryptedData = size - sizeof(LicenceDataMainELC); + unsigned char encryptedData[sizeOfEncryptedData] = {}; + for (int i = 0; i < sizeOfEncryptedData; i++) + encryptedData[i] = licenceContent[i + sizeof(LicenceDataMainELC)]; + + BYTE prefixType = (int)licenceContent[3] - 0x30; + if (prefixType == PrefixType::ELC1) + { + if (licenceHeader.licHeader.sizeData > 0) + { + if (licenceHeader.licHeader.licSubType == cEzLic_p78ou3_SubType_10_10) + { + initCrypto(); + + unsigned char decrypted[2000] = {}; + int decrypted_len = decrypt(encryptedData, sizeof(encryptedData), cryptData.aesKey, cryptData.aesInitVector, decrypted); + + if (sizeof(licEncryptedData) != decrypted_len) + { + throw LicenceException((int)GeneralError::LicenceSizeMismatch, "License size mismatch "); + } + else + { + memcpy(&licEncryptedData, decrypted, sizeof(licEncryptedData)); + + if (licEncryptedData.id.version == cEzLic_p78ou3_HeaderType_10 && licEncryptedData.header.licVersion == cEzLic_p78ou3_HeaderType_10) + { + if (licEncryptedData.header.licType == cEzLic_p78ou3_IDType_EOVOSV) + { + if (licEncryptedData.header.licCount > 0) + { + for (int i = 0; i < licMaxCount; i++) + { + licences->licences.insert(pair(licEncryptedData.items[i].protoId, licEncryptedData.items[i].licCount)); + } + } + else + { + throw LicenceException((int)GeneralError::ItemsCountMismatch, "ItemsCountMismatch"); + } + } + } + else + { + throw LicenceException((int)GeneralError::LicenceMismatch, "Licence mismatch"); + } + } + } + } + else + { + throw LicenceException((int)GeneralError::LicenceMismatch, "Licence mismatch"); + } + } + else + { + throw LicenceException((int)GeneralError::LicenceReadError, "Licence error"); + } + + return true; + } +} \ No newline at end of file diff --git a/zdenda/src/reader/licReaderELC2.cpp b/zdenda/src/reader/licReaderELC2.cpp new file mode 100644 index 0000000..7ba21a6 --- /dev/null +++ b/zdenda/src/reader/licReaderELC2.cpp @@ -0,0 +1,136 @@ +#include "licReaderELC2.h" + +namespace Reader +{ + + Licence2::Licence2() {} + + Licence2::~Licence2() {} + + Licence2::Licence2(LicenceIdentification &licIdentification) : LicenceELC2(licIdentification) + { + } + + /// @brief načte seznam licenčních bodů do obecné struktury + /// @param licences + /// @return + bool Licence2::readLicence(LicenceInfoGeneral *licences) + { + sdCard = SDCard(this->cid_cdsPath); + if (sdCard.isLoaded == false) + throw LicenceException((int)GeneralError::SDCardReadError, "Nepodařilo se načíst SD kartu., cesta: " + cid_cdsPath); + + string licFileName = getLicenceName(); + string licFilePath = this->licenceFilePath + licFileName; + + vector content; + if (readFile(licFilePath, content) == false) + { + throw LicenceException((int)GeneralError::FileOpenError, "Chyba otevření souboru licence: " + licFilePath); + } + + this->licBody.licId.licIdent[0] = content[0]; + this->licBody.licId.licIdent[1] = content[1]; + this->licBody.licId.licIdent[2] = content[2]; + this->licBody.licId.licIdent[3] = content[3]; + this->licBody.licId.licIdent[4] = content[4]; + + this->licBody.licenceIdentHeader.licenceType = content[5]; + this->licBody.licenceIdentHeader.licenceTypeVersion = content[6]; + this->licBody.licenceIdentHeader.licenceIndex = content[7]; + this->licBody.licenceIdentHeader.compatibilityVersion = content[8]; + this->licBody.licenceIdentHeader.licItemCount = content[9]; + this->licBody.licenceIdentHeader.publicHeaderLength = bytesToWord(content[10], content[11]); + this->licBody.licenceIdentHeader.cardSize = bytesToWord(content[12], content[13]); + this->licBody.licenceIdentHeader.serialNumber = bytesToDword(content[14], content[15], content[16], content[17]); + + //~~~uint16_t crcPublic = bytesToWord(content[18 + licBody.licenceIdentHeader.publicHeaderLength], content[19 + licBody.licenceIdentHeader.publicHeaderLength]); + + int elcVersion = (int)licBody.licId.licIdent[3] - 48; // verze je text, musí se odečíst 48 + + if (elcVersion != (int)this->lIdentification.licElcType) + { + throw LicenceException((int)GeneralError::ELCMismatch, "Nesouhlasí ELC."); + } + + vector publicPart(content.begin(), content.begin() + 18 + this->licBody.licenceIdentHeader.publicHeaderLength); + +#ifdef CRCCHECK + cout << "CRC read public size: " << publicPart.size() << "\n"; + cout << "CRC read public: " << calculateCRC16(publicPart) << "\n"; +#endif + + vector encryptedPart(content.begin() + licBody.licenceIdentHeader.publicHeaderLength + 18, content.begin() + content.size()); + + // cout << "encryptedPart content length: " << encryptedPart.size() << "\n"; + // for (auto x : encryptedPart) cout << (int)x << "-"; + // cout << "\n"; + + vector privateContentDecrypted; + privateContentDecrypted = decryptPrivateContent(encryptedPart); + +#ifdef CRCCHECK + cout << "CRC read private size: " << privateContentDecrypted.size() << "\n"; + cout << "CRC read private: " << calculateCRC16(privateContentDecrypted) << "\n"; +#endif + + // cout << "privateContentDecrypted content length: " << privateContentDecrypted.size() << "\n"; + // for (auto x : privateContentDecrypted) cout << (int)x << "-"; + // cout << "\n"; + + LicenceBody licBodyDecrypted; + licBodyDecrypted.licenceIdentHeader.licenceType = privateContentDecrypted[0]; + licBodyDecrypted.licenceIdentHeader.licenceTypeVersion = privateContentDecrypted[1]; + licBodyDecrypted.licenceIdentHeader.licenceIndex = privateContentDecrypted[2]; + licBodyDecrypted.licenceIdentHeader.compatibilityVersion = privateContentDecrypted[3]; + licBodyDecrypted.licenceIdentHeader.licItemCount = privateContentDecrypted[4]; + licBodyDecrypted.licenceIdentHeader.publicHeaderLength = bytesToWord(privateContentDecrypted[5], privateContentDecrypted[6]); + licBodyDecrypted.licenceIdentHeader.cardSize = bytesToWord(privateContentDecrypted[7], privateContentDecrypted[8]); + licBodyDecrypted.licenceIdentHeader.serialNumber = bytesToDword(privateContentDecrypted[9], privateContentDecrypted[10], privateContentDecrypted[11], privateContentDecrypted[12]); + + if (licBodyDecrypted.licenceIdentHeader.licItemCount != this->licBody.licenceIdentHeader.licItemCount) + { + throw LicenceException((int)GeneralError::ItemsCountMismatch, "Nesouhlasí počet položek licence."); + } + + int index = 13; + for (int i = 0; i < this->licBody.licenceIdentHeader.licItemCount; i++) + { + licDataItem item; + item.protoId = bytesToWord(privateContentDecrypted[index], privateContentDecrypted[index + 1]); + item.licCount = bytesToWord(privateContentDecrypted[index + 2], privateContentDecrypted[index + 3]); + index += sizeof(licDataItem); + this->licBody.privateContent.dataItems.push_back(item); + this->licenceInfo.licences.insert(pair(item.protoId, item.licCount)); + licences->licences.insert(pair(item.protoId, item.licCount)); + } + + uint16_t crcComplete = bytesToWord(privateContentDecrypted[index], privateContentDecrypted[index + 1]); + + vector completeVector = joinVectors(publicPart, privateContentDecrypted); + if (calculateCRC16(completeVector, 2) != crcComplete) throw LicenceException((int)GeneralError::LicenceCRCMismatch, "Nesouhlasí CRC."); + + return true; + } + + bool Licence2::getLicenceInfo(void *returnStructure) + { + if (returnStructure != nullptr) + { + LicenceELC2Info *resultPtr = static_cast(returnStructure); + for (auto item : this->licBody.privateContent.dataItems) + { + resultPtr->licences.insert(pair(item.protoId, item.licCount)); + } + } + else + { + errorMessage.code = 1; + errorMessage.message = "Error: Null pointer!"; + return false; + } + + return true; + } + +} \ No newline at end of file diff --git a/zdenda/src/reader/licReaderELC3.cpp b/zdenda/src/reader/licReaderELC3.cpp new file mode 100644 index 0000000..6c0e341 --- /dev/null +++ b/zdenda/src/reader/licReaderELC3.cpp @@ -0,0 +1,7 @@ +#include "licReaderELC3.h" + +namespace Reader +{ +} + + diff --git a/zdenda_reader.zip b/zdenda_reader.zip new file mode 100644 index 0000000..f57b083 Binary files /dev/null and b/zdenda_reader.zip differ