diff --git a/.github/scripts/check_version.sh b/.github/scripts/check_version.sh new file mode 100644 index 0000000..8a952c3 --- /dev/null +++ b/.github/scripts/check_version.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +tag=$1 +echo "Input tag: '$tag'" + +version=`grep "^version" gradle.properties | cut -d= -f2 | tr -d "[:space:]"` +echo "Version in 'gradle.properties' file: '$version'" + +if [ "$tag" != "" ]; then + echo "Release mode: check version consistency..." + if [ "$tag" != "$version" ]; then + echo "ERROR: the tag '$tag' is different from the version '$version' in the 'gradle.properties' file" + exit 1 + fi +else + echo "Snapshot mode: fetch existing tags..." + git fetch --tags + if [ $(git tag -l "$version") ]; then + echo "ERROR: version '$version' has already been released" + exit 1 + fi +fi diff --git a/.github/workflows/java-test.yml b/.github/workflows/java-test.yml new file mode 100644 index 0000000..0fbc6c1 --- /dev/null +++ b/.github/workflows/java-test.yml @@ -0,0 +1,28 @@ +name: Compile and Test + +on: + pull_request: + branches: + - main + workflow_dispatch: # To authorize manual run + +jobs: + java-test: + runs-on: ubuntu-latest + steps: + - name: Check out repository code from ${{ github.repository }}/${{ github.ref }} + uses: actions/checkout@v4 + - name: Set up JDK 11 + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'adopt' + - name: Update permissions + working-directory: . + run: chmod +x ./gradlew ./.github/scripts/*.sh + - name: Check version + working-directory: . + run: ./.github/scripts/check_version.sh + - name: Build and Test + working-directory: . + run: ./gradlew build test --info --stacktrace diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d94e3d6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] diff --git a/README.md b/README.md index 5094ef6..5ad1914 100644 --- a/README.md +++ b/README.md @@ -1 +1,142 @@ -# keyple-java-tool \ No newline at end of file +## Introduction + +This Git repository contains a set of tools for facilitating interaction with Calypso cards and analyzing their file +structure. The tools are developed and maintained by the [Calypso Networks Association](https://calypsonet.org). + +This document provides a detailed description of the tools, including their features, usage, dependencies, license, and +copyright information. Although there are two separate executables, they offer closely related and interconnected +functionalities for working with Calypso cards. + +--- + +## Calypso Card Analyzer + +The Calypso Card Analyzer is a tool for analyzing the file structure of a Calypso smart card. It retrieves the card's +data and generates a JSON report containing the card's structure and application data. + +### Features + +- Analyze the file structure of a Calypso smart card +- Retrieve card data and application data +- Generate a JSON report containing the card's structure and application data + +### Program workflow + +1. Initialize the smart card reader and check if a card is present. +2. Retrieve the traceability information of the card. +3. Get the application data for each AID (Application Identifier) in the provided AID list. +4. Create a `CardStructureData` object containing the traceability information, software information, and application + data. +5. Convert the `CardStructureData` object to a JSON string using the Gson library. +6. Write the JSON string to a file with a name based on the current date and the card's serial number. +7. Print the JSON string to the console. + +--- + +## Calypso Card File Structure Checker + +The Calypso Card File Structure Checker is a tool for checking the file structure of a Calypso card against a given JSON +file containing the expected file structure. + +### Features + +- Check the file structure of a Calypso card against a given JSON file +- Compare the expected file structure with the actual file structure of the card +- Print the differences between the expected and actual file structures to the console + +### Program workflow + +1. Load the expected file structure from a JSON file. +2. Initialize the smart card reader and check if a card is present. +3. Retrieve the actual file structure of the card. +4. Compare the expected file structure with the actual file structure. +5. Print the differences between the expected and actual file structures to the console. + +--- + +## Building and Using the Tools + +### Building the JARs + +To build the JARs for the Calypso Card Analyzer and Calypso Card File Structure Checker tools, follow these steps: + +1. Clone this Git repository to your local machine. +2. Open a terminal and navigate to the root directory of the project. +3. Run the following command to build the JARs: + +```bash +./gradlew build +``` + +After running this command, the JARs will be generated in the `build/libs` directory of the project. + +### Using the Calypso Card Analyzer JAR + +To use the Calypso Card Analyzer JAR, follow these steps: + +1. Download the Calypso Card Analyzer JAR from + the [releases](https://github.com/CalypsoNetworksAssociation/calypso-card-analysis-tools/releases) page of this + repository. +2. Connect a PC/SC card reader to your computer. +3. Insert a Calypso card into the reader. +4. Open a terminal and navigate to the directory containing the downloaded JAR. +5. Run the following command: + +```bash +java -jar Tool_AnalyzeCardFileStructure.jar [readerNameRegex] +``` + +The `readerNameRegex` parameter is optional and can be used to specify a regular expression for selecting the card reader +to use. If this parameter is not provided, the tool will use the following +expression `.*(ASK.*|Identiv.*2|ACS ACR122U|SCR3310).*`. + +The Calypso Card Analyzer tool will read the card and generate a JSON report containing the card's structure and +application data. + +### Using the Calypso Card File Structure Checker JAR + +To use the Calypso Card File Structure Checker JAR, follow these steps: + +1. Download the Calypso Card File Structure Checker JAR from + the [releases](https://github.com/CalypsoNetworksAssociation/calypso-card-analysis-tools/releases) page of this + repository. +2. Connect a PC/SC card reader to your computer. +3. Insert a Calypso card into the reader. +4. Open a terminal and navigate to the directory containing the downloaded JAR. +5. Run the following command: + +```bash +java -jar Tool_CheckCardFileStructure.jar [readerNameRegex] +``` + +Replace `` with the name of the JSON file containing the reference file structure. + +The `readerNameRegex` parameter is optional and can be used to specify a regular expression for selecting the card reader +to use. If this parameter is not provided, the tool will use the following +expression `.*(ASK.*|Identiv.*2|ACS ACR122U|SCR3310).*`. + +For example, if you want to use the `TestKit_CalypsoPrimeRegularProfile_v3.json` card profile provided in +the `card_profiles` directory, you can run the following command: + +```bash +java -jar Tool_CheckCardFileStructure.jar card_profiles/TestKit_CalypsoPrimeRegularProfile_v3.json +``` + +The tool will then read the reference file structure from the specified JSON file, check if a card is present in the +reader, and perform the necessary checks. The verification results will be displayed in the console. + +### Dependencies + +- Eclipse Keyple Core +- Eclipse Keyple Calypso Extension +- Eclipse Keyple PC/SC Plugin +- Google Gson + +### License + +This program is made available under the terms of the Eclipse Public License 2.0. See the [LICENSE](LICENSE) file for +more information. + +### Copyright + +Copyright (c) 2024 [Calypso Networks Association](https://calypsonet.org) \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 0075b33..6566f7e 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,13 +28,15 @@ repositories { maven(url = "https://s01.oss.sonatype.org/content/repositories/snapshots") } dependencies { - implementation("org.calypsonet.terminal:calypsonet-terminal-reader-java-api:1.3.+") { isChanging = true } - implementation("org.calypsonet.terminal:calypsonet-terminal-calypso-java-api:1.8.+") { isChanging = true } - implementation("org.eclipse.keyple:keyple-common-java-api:2.0.+") { isChanging = true } - implementation("org.eclipse.keyple:keyple-service-java-lib:2.3.+") { isChanging = true } - implementation("org.eclipse.keyple:keyple-plugin-pcsc-java-lib:2.1.+") { isChanging = true } - implementation("org.eclipse.keyple:keyple-card-calypso-java-lib:2.2.0") - implementation("org.eclipse.keyple:keyple-util-java-lib:2.+") { isChanging = true } +// Begin Keyple configuration (generated by 'https://keyple.org/components/overview/configuration-wizard/') + implementation("org.eclipse.keypop:keypop-reader-java-api:2.0.0") + implementation("org.eclipse.keypop:keypop-calypso-card-java-api:2.0.0") + implementation("org.eclipse.keyple:keyple-common-java-api:2.0.0") + implementation("org.eclipse.keyple:keyple-util-java-lib:2.3.1") + implementation("org.eclipse.keyple:keyple-service-java-lib:3.1.0") + implementation("org.eclipse.keyple:keyple-card-calypso-java-lib:3.0.1") + implementation("org.eclipse.keyple:keyple-plugin-pcsc-java-lib:2.1.2") +// End Keyple configuration implementation("org.slf4j:slf4j-simple:1.7.32") implementation("com.google.code.gson:gson:2.8.5") } @@ -64,7 +66,7 @@ tasks { archiveClassifier.set("Analyze-fat") duplicatesStrategy = DuplicatesStrategy.EXCLUDE manifest { - attributes("Main-Class" to "org.cna.keyple.tool.card.Tool_AnalyzeCardFileStructure") + attributes("Main-Class" to "org.calypsonet.tool.calypso.card.Tool_AnalyzeCardFileStructure") } from(configurations.runtimeClasspath.get() .onEach { println("add from dependencies: ${it.name}") } @@ -73,4 +75,23 @@ tasks { sourcesMain.allSource.forEach { println("add from sources: ${it.name}") } from(sourcesMain.output) } -} \ No newline at end of file + register("fatJarCheck", Jar::class.java) { + archiveClassifier.set("Check-fat") + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + manifest { + attributes("Main-Class" to "org.calypsonet.tool.calypso.card.Tool_CheckCardFileStructure") + } + from(configurations.runtimeClasspath.get() + .onEach { println("add from dependencies: ${it.name}") } + .map { if (it.isDirectory) it else zipTree(it) }) + val sourcesMain = sourceSets.main.get() + sourcesMain.allSource.forEach { println("add from sources: ${it.name}") } + from(sourcesMain.output) + } +} + +afterEvaluate { + tasks.named("build").configure { + dependsOn(tasks.named("fatJarAnalyze"), tasks.named("fatJarCheck")) + } +} diff --git a/TestKit_CalypsoBasicProfile_v2.json b/card_profiles/TestKit_CalypsoBasicProfile_v2.json similarity index 100% rename from TestKit_CalypsoBasicProfile_v2.json rename to card_profiles/TestKit_CalypsoBasicProfile_v2.json diff --git a/TestKit_CalypsoLightClassicProfile_v1.json b/card_profiles/TestKit_CalypsoLightClassicProfile_v1.json similarity index 100% rename from TestKit_CalypsoLightClassicProfile_v1.json rename to card_profiles/TestKit_CalypsoLightClassicProfile_v1.json diff --git a/TestKit_CalypsoLightClassicProfile_v3.json b/card_profiles/TestKit_CalypsoLightClassicProfile_v3.json similarity index 100% rename from TestKit_CalypsoLightClassicProfile_v3.json rename to card_profiles/TestKit_CalypsoLightClassicProfile_v3.json diff --git a/TestKit_CalypsoLightReferenceProfile_v1.json b/card_profiles/TestKit_CalypsoLightReferenceProfile_v1.json similarity index 100% rename from TestKit_CalypsoLightReferenceProfile_v1.json rename to card_profiles/TestKit_CalypsoLightReferenceProfile_v1.json diff --git a/TestKit_CalypsoLightReferenceProfile_v3.json b/card_profiles/TestKit_CalypsoLightReferenceProfile_v3.json similarity index 100% rename from TestKit_CalypsoLightReferenceProfile_v3.json rename to card_profiles/TestKit_CalypsoLightReferenceProfile_v3.json diff --git a/TestKit_CalypsoPrimeExtendedProfile_v1.json b/card_profiles/TestKit_CalypsoPrimeExtendedProfile_v1.json similarity index 100% rename from TestKit_CalypsoPrimeExtendedProfile_v1.json rename to card_profiles/TestKit_CalypsoPrimeExtendedProfile_v1.json diff --git a/TestKit_CalypsoPrimeExtendedProfile_v2.json b/card_profiles/TestKit_CalypsoPrimeExtendedProfile_v2.json similarity index 100% rename from TestKit_CalypsoPrimeExtendedProfile_v2.json rename to card_profiles/TestKit_CalypsoPrimeExtendedProfile_v2.json diff --git a/TestKit_CalypsoPrimeExtendedProfile_v3.json b/card_profiles/TestKit_CalypsoPrimeExtendedProfile_v3.json similarity index 100% rename from TestKit_CalypsoPrimeExtendedProfile_v3.json rename to card_profiles/TestKit_CalypsoPrimeExtendedProfile_v3.json diff --git a/TestKit_CalypsoPrimeExtendedProfile_v3_AlternativeConf.json b/card_profiles/TestKit_CalypsoPrimeExtendedProfile_v3_AlternativeConf.json similarity index 100% rename from TestKit_CalypsoPrimeExtendedProfile_v3_AlternativeConf.json rename to card_profiles/TestKit_CalypsoPrimeExtendedProfile_v3_AlternativeConf.json diff --git a/TestKit_CalypsoPrimePkiProfile_v2.json b/card_profiles/TestKit_CalypsoPrimePkiProfile_v2.json similarity index 100% rename from TestKit_CalypsoPrimePkiProfile_v2.json rename to card_profiles/TestKit_CalypsoPrimePkiProfile_v2.json diff --git a/TestKit_CalypsoPrimePkiProfile_v3.json b/card_profiles/TestKit_CalypsoPrimePkiProfile_v3.json similarity index 100% rename from TestKit_CalypsoPrimePkiProfile_v3.json rename to card_profiles/TestKit_CalypsoPrimePkiProfile_v3.json diff --git a/TestKit_CalypsoPrimePkiProfile_v3_AlternativeConf.json b/card_profiles/TestKit_CalypsoPrimePkiProfile_v3_AlternativeConf.json similarity index 100% rename from TestKit_CalypsoPrimePkiProfile_v3_AlternativeConf.json rename to card_profiles/TestKit_CalypsoPrimePkiProfile_v3_AlternativeConf.json diff --git a/TestKit_CalypsoPrimeRegularProfile_v1.json b/card_profiles/TestKit_CalypsoPrimeRegularProfile_v1.json similarity index 100% rename from TestKit_CalypsoPrimeRegularProfile_v1.json rename to card_profiles/TestKit_CalypsoPrimeRegularProfile_v1.json diff --git a/TestKit_CalypsoPrimeRegularProfile_v2.json b/card_profiles/TestKit_CalypsoPrimeRegularProfile_v2.json similarity index 100% rename from TestKit_CalypsoPrimeRegularProfile_v2.json rename to card_profiles/TestKit_CalypsoPrimeRegularProfile_v2.json diff --git a/TestKit_CalypsoPrimeRegularProfile_v3.json b/card_profiles/TestKit_CalypsoPrimeRegularProfile_v3.json similarity index 100% rename from TestKit_CalypsoPrimeRegularProfile_v3.json rename to card_profiles/TestKit_CalypsoPrimeRegularProfile_v3.json diff --git a/TestKit_CalypsoPrimeRegularProfile_v3_AlternativeConf.json b/card_profiles/TestKit_CalypsoPrimeRegularProfile_v3_AlternativeConf.json similarity index 100% rename from TestKit_CalypsoPrimeRegularProfile_v3_AlternativeConf.json rename to card_profiles/TestKit_CalypsoPrimeRegularProfile_v3_AlternativeConf.json diff --git a/gradle.properties b/gradle.properties index 1de5877..b0fe069 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ -group = org.cna.keyple -title = Keyple Card Calypso Java Tools -description = Card Calypso tools using the API of the Keyple solution. +group = org.calypsonet.tool +title = Calypso card analyzer +description = Calypso card tools dedicated to file structures analysis. version = 2.0.0 -javaSourceLevel = 1.7 -javaTargetLevel = 1.7 +javaSourceLevel = 1.8 +javaTargetLevel = 1.8 diff --git a/src/main/java/org/cna/keyple/tool/calypso/card/Tool_AnalyzeCardFileStructure.java b/src/main/java/org/calypsonet/tool/calypso/card/Tool_AnalyzeCardFileStructure.java similarity index 54% rename from src/main/java/org/cna/keyple/tool/calypso/card/Tool_AnalyzeCardFileStructure.java rename to src/main/java/org/calypsonet/tool/calypso/card/Tool_AnalyzeCardFileStructure.java index 16be8fe..eaa03d1 100644 --- a/src/main/java/org/cna/keyple/tool/calypso/card/Tool_AnalyzeCardFileStructure.java +++ b/src/main/java/org/calypsonet/tool/calypso/card/Tool_AnalyzeCardFileStructure.java @@ -1,5 +1,5 @@ /* ************************************************************************************** - * Copyright (c) 2019 Calypso Networks Association https://calypsonet.org/ + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ * * See the NOTICE file(s) distributed with this work for additional information * regarding copyright ownership. @@ -9,52 +9,63 @@ * * SPDX-License-Identifier: EPL-2.0 ************************************************************************************** */ -package org.cna.keyple.tool.calypso.card; +package org.calypsonet.tool.calypso.card; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.io.FileWriter; import java.text.SimpleDateFormat; import java.util.*; -import org.calypsonet.terminal.calypso.GetDataTag; -import org.calypsonet.terminal.calypso.SelectFileControl; -import org.calypsonet.terminal.calypso.card.CalypsoCard; -import org.calypsonet.terminal.calypso.card.CalypsoCardSelection; -import org.calypsonet.terminal.calypso.card.ElementaryFile; -import org.calypsonet.terminal.calypso.transaction.CardTransactionManager; -import org.calypsonet.terminal.calypso.transaction.UnexpectedCommandStatusException; -import org.calypsonet.terminal.reader.CardReader; -import org.calypsonet.terminal.reader.selection.CardSelectionManager; -import org.calypsonet.terminal.reader.selection.CardSelectionResult; -import org.cna.keyple.tool.calypso.carddata.CardApplicationData; -import org.cna.keyple.tool.calypso.carddata.CardFileData; -import org.cna.keyple.tool.calypso.carddata.CardStructureData; -import org.cna.keyple.tool.calypso.carddata.RecordData; -import org.cna.keyple.tool.calypso.common.ToolUtils; +import org.calypsonet.tool.calypso.carddata.CardApplicationData; +import org.calypsonet.tool.calypso.carddata.CardFileData; +import org.calypsonet.tool.calypso.carddata.CardStructureData; +import org.calypsonet.tool.calypso.carddata.RecordData; +import org.calypsonet.tool.calypso.common.ToolUtils; import org.eclipse.keyple.card.calypso.CalypsoExtensionService; import org.eclipse.keyple.core.service.Plugin; import org.eclipse.keyple.core.service.SmartCardService; import org.eclipse.keyple.core.service.SmartCardServiceProvider; import org.eclipse.keyple.plugin.pcsc.PcscPluginFactoryBuilder; import org.eclipse.keyple.plugin.pcsc.PcscReader; +import org.eclipse.keypop.calypso.card.GetDataTag; +import org.eclipse.keypop.calypso.card.SelectFileControl; +import org.eclipse.keypop.calypso.card.card.CalypsoCard; +import org.eclipse.keypop.calypso.card.card.CalypsoCardSelectionExtension; +import org.eclipse.keypop.calypso.card.card.ElementaryFile; +import org.eclipse.keypop.calypso.card.transaction.ChannelControl; +import org.eclipse.keypop.calypso.card.transaction.FreeTransactionManager; +import org.eclipse.keypop.calypso.card.transaction.SelectFileException; +import org.eclipse.keypop.calypso.card.transaction.UnexpectedCommandStatusException; +import org.eclipse.keypop.reader.CardReader; +import org.eclipse.keypop.reader.selection.CardSelectionManager; +import org.eclipse.keypop.reader.selection.CardSelectionResult; +import org.eclipse.keypop.reader.selection.CommonIsoCardSelector; +import org.eclipse.keypop.reader.selection.IsoCardSelector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Tool for analyzing the file structure of a Calypso smart card. + * + * @since 2.0.0 . + */ public class Tool_AnalyzeCardFileStructure { private static final Logger logger = LoggerFactory.getLogger(Tool_AnalyzeCardFileStructure.class); private static final SmartCardService smartCardService = SmartCardServiceProvider.getService(); private static final CalypsoExtensionService calypsoCardService = CalypsoExtensionService.getInstance(); + private static final String SOFTWARE_INFORMATION = "AnalyzeCardFileStructure"; + private static final String SOFTWARE_NAME = "Calypso Card Analyzer"; private static CardReader cardReader; - private static CardTransactionManager cardTransactionManager; + private static FreeTransactionManager cardTransactionManager; private static void fillFilesTable(CalypsoCard selectedApp) { cardTransactionManager.prepareSelectFile(SelectFileControl.FIRST_EF); try { - cardTransactionManager.processCommands(); - } catch (UnexpectedCommandStatusException e) { + cardTransactionManager.processCommands(ChannelControl.KEEP_OPEN); + } catch (UnexpectedCommandStatusException | SelectFileException e) { return; } @@ -69,8 +80,8 @@ private static void fillFilesTable(CalypsoCard selectedApp) { numberOfFiles++; cardTransactionManager.prepareSelectFile(SelectFileControl.NEXT_EF); try { - cardTransactionManager.processCommands(); - } catch (UnexpectedCommandStatusException e) { + cardTransactionManager.processCommands(ChannelControl.KEEP_OPEN); + } catch (UnexpectedCommandStatusException | SelectFileException e) { return; } @@ -90,12 +101,13 @@ private static CardFileData getFileData(ElementaryFile selectedFile, CalypsoCard for (int i = 0; i < selectedFile.getHeader().getRecordsNumber(); i++) { calypsoCardService - .createCardTransactionWithoutSecurity(cardReader, selectedApp) + .getCalypsoCardApiFactory() + .createFreeTransactionManager(cardReader, selectedApp) .prepareReadRecord(selectedFile.getSfi(), (byte) (i + 1)) - .processCommands(); + .processCommands(ChannelControl.KEEP_OPEN); fileData - .getRecordData() + .getRecordDataList() .add((new RecordData(i + 1, selectedFile.getData().getContent((i + 1))))); } } @@ -104,16 +116,25 @@ private static CardFileData getFileData(ElementaryFile selectedFile, CalypsoCard } private static CardApplicationData getApplicationData( - CalypsoCardSelection.FileOccurrence fileOccurrence, String aid) { + CommonIsoCardSelector.FileOccurrence fileOccurrence, String aid) { - CardSelectionManager cardSelectionManager = smartCardService.createCardSelectionManager(); + CardSelectionManager cardSelectionManager = + smartCardService.getReaderApiFactory().createCardSelectionManager(); - cardSelectionManager.prepareSelection( - calypsoCardService - .createCardSelection() - .setFileOccurrence(fileOccurrence) - .acceptInvalidatedCard() - .filterByDfName(aid)); + IsoCardSelector isoCardSelector = + SmartCardServiceProvider.getService() + .getReaderApiFactory() + .createIsoCardSelector() + .filterByDfName(aid) + .setFileOccurrence(fileOccurrence); + + CalypsoCardSelectionExtension calypsoCardSelectionExtension = + CalypsoExtensionService.getInstance() + .getCalypsoCardApiFactory() + .createCalypsoCardSelectionExtension() + .acceptInvalidatedCard(); + + cardSelectionManager.prepareSelection(isoCardSelector, calypsoCardSelectionExtension); CardSelectionResult selectionResult = cardSelectionManager.processCardSelectionScenario(cardReader); @@ -125,20 +146,21 @@ private static CardApplicationData getApplicationData( CalypsoCard selectedApplication = (CalypsoCard) selectionResult.getActiveSmartCard(); cardTransactionManager = - calypsoCardService.createCardTransactionWithoutSecurity(cardReader, selectedApplication); - cardTransactionManager.prepareSelectFile(SelectFileControl.CURRENT_DF); - cardTransactionManager.processCommands(); + calypsoCardService + .getCalypsoCardApiFactory() + .createFreeTransactionManager(cardReader, selectedApplication); + cardTransactionManager + .prepareSelectFile(SelectFileControl.CURRENT_DF) + .processCommands(ChannelControl.KEEP_OPEN); // Get and fill the Application file information CardApplicationData cardAppData = new CardApplicationData(selectedApplication); fillFilesTable(selectedApplication); - Iterator filesIter = selectedApplication.getFiles().iterator(); + for (ElementaryFile elementaryFile : selectedApplication.getFiles()) { - while (filesIter.hasNext()) { - - CardFileData cardFileData = getFileData(filesIter.next(), selectedApplication); + CardFileData cardFileData = getFileData(elementaryFile, selectedApplication); cardAppData.getFileList().add(cardFileData); } @@ -147,19 +169,24 @@ private static CardApplicationData getApplicationData( public static byte[] getTraceabilityInfo(List aidList) { - CardSelectionManager cardSelectionManager = smartCardService.createCardSelectionManager(); + CardSelectionManager cardSelectionManager = + smartCardService.getReaderApiFactory().createCardSelectionManager(); - Iterator aidListIter = aidList.iterator(); + for (String currentAid : aidList) { - while (aidListIter.hasNext()) { + IsoCardSelector isoCardSelector = + SmartCardServiceProvider.getService() + .getReaderApiFactory() + .createIsoCardSelector() + .filterByDfName(currentAid); - String currentAid = (String) aidListIter.next(); + CalypsoCardSelectionExtension calypsoCardSelectionExtension = + CalypsoExtensionService.getInstance() + .getCalypsoCardApiFactory() + .createCalypsoCardSelectionExtension() + .acceptInvalidatedCard(); - cardSelectionManager.prepareSelection( - calypsoCardService - .createCardSelection() - .acceptInvalidatedCard() - .filterByDfName(currentAid)); + cardSelectionManager.prepareSelection(isoCardSelector, calypsoCardSelectionExtension); CardSelectionResult selectionResult = cardSelectionManager.processCardSelectionScenario(cardReader); @@ -169,36 +196,38 @@ public static byte[] getTraceabilityInfo(List aidList) { CalypsoCard calypsoCard = (CalypsoCard) selectionResult.getActiveSmartCard(); cardTransactionManager = - calypsoCardService.createCardTransactionWithoutSecurity(cardReader, calypsoCard); - cardTransactionManager.prepareGetData(GetDataTag.TRACEABILITY_INFORMATION); - cardTransactionManager.processCommands(); + calypsoCardService + .getCalypsoCardApiFactory() + .createFreeTransactionManager(cardReader, calypsoCard); + cardTransactionManager + .prepareGetData(GetDataTag.TRACEABILITY_INFORMATION) + .processCommands(ChannelControl.KEEP_OPEN); return calypsoCard.getTraceabilityInformation(); } } - return null; + return null; // NOSONAR } public static void getApplicationsData(String aid, List cardAppDataList) { CardApplicationData cardAppData = - getApplicationData(CalypsoCardSelection.FileOccurrence.FIRST, aid); + getApplicationData(CommonIsoCardSelector.FileOccurrence.FIRST, aid); while (cardAppData != null) { cardAppDataList.add(cardAppData); - cardAppData = getApplicationData(CalypsoCardSelection.FileOccurrence.NEXT, aid); + cardAppData = getApplicationData(CommonIsoCardSelector.FileOccurrence.NEXT, aid); } } - public static boolean initReaders() { + public static boolean initReaders(String readerNameRegex) { Plugin plugin = smartCardService.registerPlugin(PcscPluginFactoryBuilder.builder().build()); smartCardService.checkCardExtension(calypsoCardService); - String pcscContactlessCardReaderName = - ToolUtils.getCardReaderName(plugin, ToolUtils.CARD_READER_NAME_REGEX); + String pcscContactlessCardReaderName = ToolUtils.getCardReaderName(plugin, readerNameRegex); cardReader = plugin.getReader(pcscContactlessCardReaderName); plugin @@ -214,7 +243,14 @@ public static boolean initReaders() { public static void main(String[] args) { - boolean isCardPresent = initReaders(); + String readerNameRegex; + if (args.length == 1) { + readerNameRegex = args[0]; + } else { + readerNameRegex = ToolUtils.DEFAULT_CARD_READER_NAME_REGEX; + } + + boolean isCardPresent = initReaders(readerNameRegex); if (isCardPresent) { @@ -242,12 +278,10 @@ public static void main(String[] args) { CardStructureData cardStructureData = new CardStructureData( - traceabilityInfo, "AnalyzeCardFileStructure", new Date(), 2, "Keyple"); - - Iterator aidListIter = aidList.iterator(); + traceabilityInfo, SOFTWARE_INFORMATION, new Date(), 2, SOFTWARE_NAME); - while (aidListIter.hasNext()) { - getApplicationsData((String) aidListIter.next(), cardStructureData.getApplicationList()); + for (String aid : aidList) { + getApplicationsData(aid, cardStructureData.getApplicationList()); } try { @@ -260,11 +294,10 @@ public static void main(String[] args) { String dateString = new SimpleDateFormat("yyyyMMdd").format(new Date()); String fileName = - new String( - dateString - + "_CardData_" - + cardStructureData.getApplicationList().get(0).getCsnDec() - + ".json"); + dateString + + "_CardData_" + + cardStructureData.getApplicationList().get(0).getCsnDec() + + ".json"; cardStructureData.setId(fileName); @@ -275,7 +308,7 @@ public static void main(String[] args) { fw.close(); } catch (Exception e) { - logger.error("Exception while writing the report: " + e.getCause()); + logger.error("Exception while writing the report: {}", e.getMessage(), e); } cardStructureData.print(logger); diff --git a/src/main/java/org/cna/keyple/tool/calypso/card/Tool_CheckCardFileStructure.java b/src/main/java/org/calypsonet/tool/calypso/card/Tool_CheckCardFileStructure.java similarity index 58% rename from src/main/java/org/cna/keyple/tool/calypso/card/Tool_CheckCardFileStructure.java rename to src/main/java/org/calypsonet/tool/calypso/card/Tool_CheckCardFileStructure.java index 231d9c8..b0bc1bb 100644 --- a/src/main/java/org/cna/keyple/tool/calypso/card/Tool_CheckCardFileStructure.java +++ b/src/main/java/org/calypsonet/tool/calypso/card/Tool_CheckCardFileStructure.java @@ -1,5 +1,5 @@ /* ************************************************************************************** - * Copyright (c) 2019 Calypso Networks Association https://calypsonet.org/ + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ * * See the NOTICE file(s) distributed with this work for additional information * regarding copyright ownership. @@ -9,21 +9,26 @@ * * SPDX-License-Identifier: EPL-2.0 ************************************************************************************** */ -package org.cna.keyple.tool.calypso.card; +package org.calypsonet.tool.calypso.card; + +import static org.calypsonet.tool.calypso.common.ToolUtils.SEPARATOR_LINE; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.io.FileReader; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; -import org.cna.keyple.tool.calypso.carddata.*; -import org.cna.keyple.tool.calypso.carddata.AccessConditions.AccessCondition; -import org.cna.keyple.tool.calypso.common.ToolUtils; +import org.calypsonet.tool.calypso.carddata.*; +import org.calypsonet.tool.calypso.common.ToolUtils; import org.eclipse.keyple.core.util.HexUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Provides functionality to check the file structure of a Calypso card. + * + * @since 2.0.0 + */ public class Tool_CheckCardFileStructure { private static final Logger logger = LoggerFactory.getLogger(Tool_CheckCardFileStructure.class); @@ -31,18 +36,17 @@ public class Tool_CheckCardFileStructure { private static List dataRefStatus; private static void checkAccessCondition( - int groupNumber, AccessCondition dataToCheck, AccessCondition dataRead) { + int groupNumber, + AccessConditions.AccessCondition dataToCheck, + AccessConditions.AccessCondition dataRead) { if (dataToCheck.getAccessCondition() != null && !dataToCheck.getAccessCondition().equals(dataRead.getAccessCondition())) { logger.info( - "Group " - + groupNumber - + ":: Expected Access Condition to be [" - + dataToCheck.getAccessCondition() - + "] and found [" - + dataRead.getAccessCondition() - + "]."); + "Group {}:: Expected Access Condition to be [{}] and found [{}].", + groupNumber, + dataToCheck.getAccessCondition(), + dataRead.getAccessCondition()); } if (dataToCheck.getAccessCondition().equals("10") @@ -51,20 +55,15 @@ private static void checkAccessCondition( if (dataToCheck.getKeyLevel() == null) { logger.info( - "Group " - + groupNumber - + ":: Structure to check error. Access Condition [" - + dataToCheck.getAccessCondition() - + "] requires an associated Key Level."); + "Group {}:: Structure to check error. Access Condition [{}] requires an associated Key Level.", + groupNumber, + dataToCheck.getAccessCondition()); } else if (!dataToCheck.getKeyLevel().equals(dataRead.getKeyLevel())) { logger.info( - "Group " - + groupNumber - + ":: Expected Key Level to be [" - + dataToCheck.getKeyLevel() - + "] and found [" - + dataRead.getKeyLevel() - + "]."); + "Group {}:: Expected Key Level to be [{}] and found [{}].", + groupNumber, + dataToCheck.getKeyLevel(), + dataRead.getKeyLevel()); } } } @@ -81,20 +80,15 @@ private static void checkAccessConditions( private static void checkString(String name, String dataToCheck, String dataRead) { if (dataToCheck != null && !dataToCheck.equals(dataRead)) { - logger.info( - "Expected " + name + " to be [" + dataToCheck + "] and found [" + dataRead + "]."); + logger.info("Expected {} to be [{}] and found [{}].", name, dataToCheck, dataRead); } } private static void checkDataRef(FileReference refToCheck) { - if (dataRefStatus.size() > 0) { - - Iterator dataRefIterator = dataRefStatus.iterator(); - - while (dataRefIterator.hasNext()) { + if (!dataRefStatus.isEmpty()) { - FileReference fileRef = (FileReference) dataRefIterator.next(); + for (FileReference fileRef : dataRefStatus) { if (fileRef.getLinkedFileLid().equals(refToCheck.getBaseFileLid())) { @@ -102,15 +96,11 @@ private static void checkDataRef(FileReference refToCheck) { fileRef.setReferenceFoundFlag(true); } else { logger.info( - "DataRef for file " - + refToCheck.getBaseFileLid() - + " [" - + refToCheck.getRefValueRead() - + "] doesn't match the value of the linked file " - + fileRef.getBaseFileLid() - + " [" - + fileRef.getRefValueRead() - + "]."); + "DataRef for file {} [{}] doesn't match the value of the linked file {} [{}].", + refToCheck.getBaseFileLid(), + refToCheck.getRefValueRead(), + fileRef.getBaseFileLid(), + fileRef.getRefValueRead()); } return; @@ -128,15 +118,11 @@ private static void checkCardFileData(CardFileData dataToCheck, List 2) { + logger.error( + "Usage: java -jar Tool_CheckCardFileStructure.jar [readerNameRegex]"); + return; + } + + String readerNameRegex; + if (args.length == 2) { + readerNameRegex = args[1]; + } else { + readerNameRegex = ToolUtils.DEFAULT_CARD_READER_NAME_REGEX; + } + + boolean isCardPresent = Tool_AnalyzeCardFileStructure.initReaders(readerNameRegex); CardStructureData fileStructureToCheck; - dataRefStatus = new ArrayList(); + dataRefStatus = new ArrayList<>(); Gson gson = new GsonBuilder() @@ -276,65 +263,51 @@ public static void main(String[] args) { .create(); try { - fileStructureToCheck = - gson.fromJson( - new FileReader("TestKit_CalypsoPrimeRegularProfile_v3.json"), - CardStructureData.class); + FileReader fileReader = new FileReader(args[0]); + fileStructureToCheck = gson.fromJson(fileReader, CardStructureData.class); } catch (Exception e) { - logger.error("Exception while loading file structure to check " + e.getCause()); + logger.error("Exception while loading file structure to check {}", e.getMessage(), e); return; } /* Check if a card is present in the reader */ if (isCardPresent) { - Iterator appToCheckListIter = fileStructureToCheck.getApplicationList().iterator(); + for (CardApplicationData cardApplicationData : fileStructureToCheck.getApplicationList()) { - while (appToCheckListIter.hasNext()) { + List cardAppDataList = new ArrayList<>(); - List cardAppDataList = new ArrayList(); - CardApplicationData cardAppDataToCheck = (CardApplicationData) appToCheckListIter.next(); - - logger.info( - "========================================================================================================"); - logger.info("Checking Application:: " + HexUtil.toHex(cardAppDataToCheck.getAid())); + logger.info(SEPARATOR_LINE); + logger.info("Checking Application: {}", HexUtil.toHex(cardApplicationData.getAid())); Tool_AnalyzeCardFileStructure.getApplicationsData( - HexUtil.toHex(cardAppDataToCheck.getAid()), cardAppDataList); + HexUtil.toHex(cardApplicationData.getAid()), cardAppDataList); - if (cardAppDataList.size() == 0) { + if (cardAppDataList.isEmpty()) { logger.info("Application not present in card!"); } else if (cardAppDataList.size() > 1) { logger.info( - "Found (" - + cardAppDataList.size() - + ") applications for the given AID. Aborting application analysis"); + "Found ({}) applications for the given AID. Aborting application analysis", + cardAppDataList.size()); } else { - checkCardAppData(cardAppDataToCheck, cardAppDataList.get(0)); + checkCardAppData(cardApplicationData, cardAppDataList.get(0)); } } - logger.info( - "========================================================================================================"); - - Iterator dataRefIter = dataRefStatus.iterator(); + logger.info(SEPARATOR_LINE); - while (dataRefIter.hasNext()) { + for (FileReference fileRef : dataRefStatus) { - FileReference fileRef = (FileReference) dataRefIter.next(); - - if (fileRef.getReferenceFoundFlag() != true) { + if (!fileRef.getReferenceFoundFlag()) { logger.info( - "No/Incorrect data ref found for file " - + fileRef.getBaseFileLid() - + ". Should be linked with file " - + fileRef.getLinkedFileLid()); + "No/Incorrect data ref found for file {}. Should be linked with file {}", + fileRef.getBaseFileLid(), + fileRef.getLinkedFileLid()); } } - logger.info( - "========================================================================================================"); + logger.info(SEPARATOR_LINE); } } } diff --git a/src/main/java/org/cna/keyple/tool/calypso/carddata/AccessConditions.java b/src/main/java/org/calypsonet/tool/calypso/carddata/AccessConditions.java similarity index 71% rename from src/main/java/org/cna/keyple/tool/calypso/carddata/AccessConditions.java rename to src/main/java/org/calypsonet/tool/calypso/carddata/AccessConditions.java index 689c14e..c78a1e4 100644 --- a/src/main/java/org/cna/keyple/tool/calypso/carddata/AccessConditions.java +++ b/src/main/java/org/calypsonet/tool/calypso/carddata/AccessConditions.java @@ -1,5 +1,5 @@ /* ************************************************************************************** - * Copyright (c) 2019 Calypso Networks Association https://calypsonet.org/ + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ * * See the NOTICE file(s) distributed with this work for additional information * regarding copyright ownership. @@ -9,25 +9,31 @@ * * SPDX-License-Identifier: EPL-2.0 ************************************************************************************** */ -package org.cna.keyple.tool.calypso.carddata; +package org.calypsonet.tool.calypso.carddata; -import org.cna.keyple.tool.calypso.common.ToolUtils; +import org.calypsonet.tool.calypso.common.ToolUtils; +import org.eclipse.keyple.core.util.HexUtil; public class AccessConditions { + /** + * Access conditions parameters. + * + * @since 2.0.0 + */ public class AccessCondition { - private String accessCondition; + private final String accessCondition; - private String keyLevel; + private final String keyLevel; - private String description; + private final String description; public AccessCondition(byte inAc, byte inKl) { - accessCondition = String.format("%02X", inAc); + accessCondition = HexUtil.toHex(inAc); - keyLevel = String.format("%02X", inKl); + keyLevel = HexUtil.toHex(inKl); description = ToolUtils.getAcName(accessCondition, keyLevel, true); } @@ -45,13 +51,13 @@ public String getDescription() { } } - private AccessCondition group0; + private final AccessCondition group0; - private AccessCondition group1; + private final AccessCondition group1; - private AccessCondition group2; + private final AccessCondition group2; - private AccessCondition group3; + private final AccessCondition group3; public AccessConditions(byte[] accessConditions, byte[] keyLevels) { diff --git a/src/main/java/org/calypsonet/tool/calypso/carddata/CardApplicationData.java b/src/main/java/org/calypsonet/tool/calypso/carddata/CardApplicationData.java new file mode 100644 index 0000000..728c700 --- /dev/null +++ b/src/main/java/org/calypsonet/tool/calypso/carddata/CardApplicationData.java @@ -0,0 +1,377 @@ +/* ************************************************************************************** + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ + * + * See the NOTICE file(s) distributed with this work for additional information + * regarding copyright ownership. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ************************************************************************************** */ +package org.calypsonet.tool.calypso.carddata; + +import static org.calypsonet.tool.calypso.common.ToolUtils.SEPARATOR_LINE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.calypsonet.tool.calypso.common.ToolUtils; +import org.eclipse.keyple.core.util.ByteArrayUtil; +import org.eclipse.keyple.core.util.HexUtil; +import org.eclipse.keypop.calypso.card.WriteAccessLevel; +import org.eclipse.keypop.calypso.card.card.CalypsoCard; +import org.slf4j.Logger; + +/** + * All data related to a card application. + * + * @since 2.0.0 + */ +public class CardApplicationData { + + public static class Issuer { + + private final String value; + + private final String name; + + public Issuer(byte inValue) { + + value = HexUtil.toHex(inValue); + + name = ToolUtils.getIssuerName(inValue); + } + + public String getValue() { + return value; + } + + public String getName() { + return name; + } + } + + private final byte[] fci; + + private final String calypsoRevision; + + private final byte[] aid; + + private final byte[] csn; + + private final long csnDec; + + private final String sessionModif; + + private final int sessionModifDec; + + private final int bufferSize; + + private final String platform; + + private final String applicationType; + + private final String applicationSubtype; + + private final Issuer issuer; + + private final String version; + + private final String revision; + + private final String transactionCounter; + + private final long transactionCounterDec; + + private final AccessConditions accessConditions; + + private final String status; + + private final String kif1; + + private final String kif2; + + private final String kif3; + + private final String kvc1; + + private final String kvc2; + + private final String kvc3; + + private final String lid; + + List fileList = null; + + private static int getSessionBufferSize(int sessionModification) { + + switch (sessionModification) { + case 6: + return 215; + + case 7: + return 256; + + case 8: + return 304; + + case 9: + return 362; + + case 10: + return 430; + + case 11: + return 512; + + case 12: + return 608; + + case 13: + return 724; + + case 14: + return 861; + + case 15: + return 1024; + + default: + return 0; + } + } + + public CardApplicationData(CalypsoCard appData) { + + csn = + Arrays.copyOf( + appData.getApplicationSerialNumber(), appData.getApplicationSerialNumber().length); + + csnDec = ByteArrayUtil.extractLong(appData.getApplicationSerialNumber(), 0, 8, false); + + calypsoRevision = appData.getProductType().toString(); + + sessionModif = ToolUtils.padLeft(HexUtil.toHex(appData.getSessionModification()), 4, '0'); + + sessionModifDec = appData.getSessionModification(); + + bufferSize = getSessionBufferSize(appData.getSessionModification()); + + transactionCounter = "Not available"; // String.format("%06X", appData.getTransactionCounter()); + + transactionCounterDec = 0; // appData.getTransactionCounter(); + + platform = HexUtil.toHex(appData.getPlatform()); + + issuer = new Issuer(appData.getSoftwareIssuer()); + + version = HexUtil.toHex(appData.getSoftwareVersion()); + + revision = HexUtil.toHex(appData.getSoftwareRevision()); + + fci = + Arrays.copyOf( + appData.getSelectApplicationResponse(), appData.getSelectApplicationResponse().length); + + aid = Arrays.copyOf(appData.getDfName(), appData.getDfName().length); + + lid = HexUtil.toHex(appData.getDirectoryHeader().getLid()); + + kif1 = HexUtil.toHex(appData.getDirectoryHeader().getKif(WriteAccessLevel.PERSONALIZATION)); + kif2 = HexUtil.toHex(appData.getDirectoryHeader().getKif(WriteAccessLevel.LOAD)); + kif3 = HexUtil.toHex(appData.getDirectoryHeader().getKif(WriteAccessLevel.DEBIT)); + + kvc1 = HexUtil.toHex(appData.getDirectoryHeader().getKvc(WriteAccessLevel.PERSONALIZATION)); + kvc2 = HexUtil.toHex(appData.getDirectoryHeader().getKvc(WriteAccessLevel.LOAD)); + kvc3 = HexUtil.toHex(appData.getDirectoryHeader().getKvc(WriteAccessLevel.DEBIT)); + + status = HexUtil.toHex(appData.getDirectoryHeader().getDfStatus()); + + accessConditions = + new AccessConditions( + appData.getDirectoryHeader().getAccessConditions(), + appData.getDirectoryHeader().getKeyIndexes()); + + applicationType = HexUtil.toHex(appData.getApplicationType()); + + applicationSubtype = HexUtil.toHex(appData.getApplicationSubtype()); + + fileList = new ArrayList<>(); + } + + public void print(Logger logger) { + + logger.info(SEPARATOR_LINE); + String paddedAid = ToolUtils.padLeft(HexUtil.toHex(this.getAid()), 32, ' '); + String paddedLid = ToolUtils.padLeft(this.getLid(), 4, '0'); + String group0 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup0().getAccessCondition(), + this.getAccessConditions().getGroup0().getKeyLevel(), + false); + String group1 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup1().getAccessCondition(), + this.getAccessConditions().getGroup1().getKeyLevel(), + false); + String group2 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup2().getAccessCondition(), + this.getAccessConditions().getGroup2().getKeyLevel(), + false); + String group3 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup3().getAccessCondition(), + this.getAccessConditions().getGroup3().getKeyLevel(), + false); + logger.info( + "| AID | LID | KVC1 | KVC2 | KVC3 | KIF1 | KIF2 | KIF3 | G0 | G1 | G2 | G3 |"); + logger.info( + "|{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} |", + paddedAid, + paddedLid, + this.getKvc1(), + this.getKvc2(), + this.getKvc3(), + this.getKif1(), + this.getKif2(), + this.getKif3(), + group0, + group1, + group2, + group3); + logger.info(SEPARATOR_LINE); + + logger.info("= FCI:: {}", HexUtil.toHex(this.getFci())); + logger.info("= Serial Number:: {} ({})", HexUtil.toHex(this.getCsn()), this.getCsnDec()); + logger.info("= Transaction Counter:: {}", this.getTransactionCounterDec()); + logger.info("= Revision:: {}", this.getCalypsoRevision()); + logger.info("= Session Buffer Size:: {} bytes", this.getBufferSize()); + logger.info("= Platform (Chip Type):: {}", this.getPlatform()); + + if (this.getIssuerInfo() != null) { + logger.info( + "= Issuer:: {} ({})", this.getIssuerInfo().getName(), this.getIssuerInfo().getValue()); + } else { + logger.info("= Issuer:: null"); + } + logger.info("= Software Version:: {}.{}", this.getVersion(), this.getRevision()); + logger.info("= Application Type:: {}", this.getApplicationType()); + logger.info("= Application Subtype:: {}", this.getApplicationSubtype()); + logger.info("= DF Status:: {}", this.getStatus()); + logger.info(SEPARATOR_LINE); + + logger.info("| LID | Type | SID | #R | Size | G0 | G1 | G2 | G3 | DRef |"); + logger.info("----------------------------------------------------------"); + + for (CardFileData fileData : this.getFileList()) { + + fileData.print(logger); + } + } + + public byte[] getFci() { + return fci; + } + + public byte[] getCsn() { + return csn; + } + + public long getCsnDec() { + return csnDec; + } + + public String getCalypsoRevision() { + return calypsoRevision; + } + + public String getSessionModif() { + return sessionModif; + } + + public int getSessionModifDec() { + return sessionModifDec; + } + + public int getBufferSize() { + return bufferSize; + } + + public String getTransactionCounter() { + return transactionCounter; + } + + public long getTransactionCounterDec() { + return transactionCounterDec; + } + + public String getPlatform() { + return platform; + } + + public Issuer getIssuerInfo() { + return issuer; + } + + public String getVersion() { + return version; + } + + public String getRevision() { + return revision; + } + + public byte[] getAid() { + return aid; + } + + public String getLid() { + return lid; + } + + public String getKif1() { + return kif1; + } + + public String getKif2() { + return kif2; + } + + public String getKif3() { + return kif3; + } + + public String getKvc1() { + return kvc1; + } + + public String getKvc2() { + return kvc2; + } + + public String getKvc3() { + return kvc3; + } + + public AccessConditions getAccessConditions() { + return accessConditions; + } + + public String getApplicationType() { + return applicationType; + } + + public String getApplicationSubtype() { + return applicationSubtype; + } + + public String getStatus() { + return status; + } + + public List getFileList() { + return fileList; + } +} diff --git a/src/main/java/org/calypsonet/tool/calypso/carddata/CardFileData.java b/src/main/java/org/calypsonet/tool/calypso/carddata/CardFileData.java new file mode 100644 index 0000000..e50b49e --- /dev/null +++ b/src/main/java/org/calypsonet/tool/calypso/carddata/CardFileData.java @@ -0,0 +1,157 @@ +/* ************************************************************************************** + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ + * + * See the NOTICE file(s) distributed with this work for additional information + * regarding copyright ownership. + * + * This program and the accompanying materials are made available under the terms of the + * Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + ************************************************************************************** */ +package org.calypsonet.tool.calypso.carddata; + +import java.util.ArrayList; +import java.util.List; +import org.calypsonet.tool.calypso.common.ToolUtils; +import org.eclipse.keyple.core.util.HexUtil; +import org.eclipse.keypop.calypso.card.card.ElementaryFile; +import org.slf4j.Logger; + +/** + * All data related to a file of the card. + * + * @since 2.0.0 + */ +public class CardFileData { + + private final String sfi; + + private final String lid; + + private final String efType; + + private final String ref; + + private final String recSize; + + private final int recSizeDec; + + private final String numRec; + + private final int numRecDec; + + private final AccessConditions accessConditions; + + private final List recordDataList; + + public CardFileData(ElementaryFile fileInfo) { + + int efTypeValue = ToolUtils.getEfTypeIntValue(fileInfo.getHeader().getEfType()); + + lid = HexUtil.toHex(fileInfo.getHeader().getLid()); + + sfi = HexUtil.toHex(fileInfo.getSfi()); + + efType = HexUtil.toHex(efTypeValue); + + numRec = HexUtil.toHex(fileInfo.getHeader().getRecordsNumber()); + + numRecDec = fileInfo.getHeader().getRecordsNumber(); + + recSize = ToolUtils.padLeft(String.valueOf(fileInfo.getHeader().getRecordSize()), 4, '0'); + + recSizeDec = fileInfo.getHeader().getRecordSize(); + + accessConditions = + new AccessConditions( + fileInfo.getHeader().getAccessConditions(), fileInfo.getHeader().getKeyIndexes()); + + recordDataList = new ArrayList<>(); + + ref = HexUtil.toHex(fileInfo.getHeader().getSharedReference()); + } + + public String getLid() { + return lid; + } + + public String getSfi() { + return sfi; + } + + public String getEfType() { + return efType; + } + + public String getNumRec() { + return numRec; + } + + public int getNumRecDec() { + return numRecDec; + } + + public String getRecSize() { + return recSize; + } + + public int getRecSizeDec() { + return recSizeDec; + } + + public AccessConditions getAccessConditions() { + return accessConditions; + } + + public String getDataRef() { + return ref; + } + + public List getRecordDataList() { + return recordDataList; + } + + public void print(Logger logger) { + + String group0 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup0().getAccessCondition(), + this.getAccessConditions().getGroup0().getKeyLevel(), + false); + String group1 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup1().getAccessCondition(), + this.getAccessConditions().getGroup1().getKeyLevel(), + false); + String group2 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup2().getAccessCondition(), + this.getAccessConditions().getGroup2().getKeyLevel(), + false); + String group3 = + ToolUtils.getAcName( + this.getAccessConditions().getGroup3().getAccessCondition(), + this.getAccessConditions().getGroup3().getKeyLevel(), + false); + + logger.info( + "| {} | {} | {} | {} | {} | {} | {} | {} | {}| {} |", + this.getLid(), + ToolUtils.getEfTypeName(this.getEfType(), false), + this.getSfi(), + ToolUtils.padLeft(String.valueOf(this.getNumRecDec()), 2, '0'), + ToolUtils.padLeft(String.valueOf(this.getRecSizeDec()), 4, '0'), + group0, + group1, + group2, + group3, + this.getDataRef()); + + if (getRecordDataList() != null) { + for (RecordData recordData : getRecordDataList()) { + logger.info("+ #{}:{}", recordData.getIndex(), HexUtil.toHex(recordData.getValue())); + } + } + } +} diff --git a/src/main/java/org/cna/keyple/tool/calypso/carddata/CardStructureData.java b/src/main/java/org/calypsonet/tool/calypso/carddata/CardStructureData.java similarity index 51% rename from src/main/java/org/cna/keyple/tool/calypso/carddata/CardStructureData.java rename to src/main/java/org/calypsonet/tool/calypso/carddata/CardStructureData.java index 542d4c5..f85a6eb 100644 --- a/src/main/java/org/cna/keyple/tool/calypso/carddata/CardStructureData.java +++ b/src/main/java/org/calypsonet/tool/calypso/carddata/CardStructureData.java @@ -1,5 +1,5 @@ /* ************************************************************************************** - * Copyright (c) 2018 Calypso Networks Association https://calypsonet.org/ + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ * * See the NOTICE file(s) distributed with this work for additional information * regarding copyright ownership. @@ -9,28 +9,34 @@ * * SPDX-License-Identifier: EPL-2.0 ************************************************************************************** */ -package org.cna.keyple.tool.calypso.carddata; +package org.calypsonet.tool.calypso.carddata; import java.text.SimpleDateFormat; import java.util.*; +import org.calypsonet.tool.calypso.common.ToolUtils; import org.eclipse.keyple.core.util.HexUtil; import org.slf4j.Logger; +/** + * Structure of a card's data. + * + * @since 2.0.0 + */ public class CardStructureData { private String id; - private String infos; + private final String infos; - private String date; + private final String date; - private int version; + private final int version; - private String software; + private final String software; - private byte[] traceability; + private final byte[] traceability; - private List applicationList = null; + private final List applicationList; public CardStructureData( byte[] traceabilityInfo, @@ -41,18 +47,15 @@ public CardStructureData( traceability = Arrays.copyOf(traceabilityInfo, traceabilityInfo.length); - infos = new String(softwareInfo); - - String dateString = - new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date(creationDate.getTime())); + infos = softwareInfo; - date = new String(dateString); + date = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(creationDate); version = softwareVersion; - software = new String(softwareName); + software = softwareName; - applicationList = new ArrayList(); + applicationList = new ArrayList<>(); } public List getApplicationList() { @@ -61,24 +64,18 @@ public List getApplicationList() { public void print(Logger logger) { - logger.info( - "========================================================================================================"); - logger.info("{}", String.format("= Id:: %s", this.getId())); - logger.info("{}", String.format("= Date:: %s", this.getDate())); - logger.info("{}", String.format("= Version:: %03d", this.getVersion())); - logger.info("{}", String.format("= Software:: %s", this.getSoftware())); - logger.info("{}", String.format("= Traceability:: %s", HexUtil.toHex(this.getTraceability()))); - - List applicationList = this.getApplicationList(); - Iterator appIter = applicationList.iterator(); - - while (appIter.hasNext()) { - CardApplicationData applicationData = (CardApplicationData) appIter.next(); + logger.info(ToolUtils.SEPARATOR_LINE); + logger.info("= Id:: {}", this.getId()); + logger.info("= Date:: {}", this.getDate()); + logger.info("= Version:: {}", ToolUtils.padLeft(String.valueOf(this.getVersion()), 3, '0')); + logger.info("= Software:: {}", this.getSoftware()); + logger.info("= Traceability:: {}", HexUtil.toHex(this.getTraceability())); + for (CardApplicationData applicationData : this.getApplicationList()) { applicationData.print(logger); } - logger.info( - "========================================================================================================"); + + logger.info(ToolUtils.SEPARATOR_LINE); } public byte[] getTraceability() { diff --git a/src/main/java/org/cna/keyple/tool/calypso/carddata/FileReference.java b/src/main/java/org/calypsonet/tool/calypso/carddata/FileReference.java similarity index 60% rename from src/main/java/org/cna/keyple/tool/calypso/carddata/FileReference.java rename to src/main/java/org/calypsonet/tool/calypso/carddata/FileReference.java index d4a3dbd..8ee7c31 100644 --- a/src/main/java/org/cna/keyple/tool/calypso/carddata/FileReference.java +++ b/src/main/java/org/calypsonet/tool/calypso/carddata/FileReference.java @@ -1,5 +1,5 @@ /* ************************************************************************************** - * Copyright (c) 2019 Calypso Networks Association https://calypsonet.org/ + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ * * See the NOTICE file(s) distributed with this work for additional information * regarding copyright ownership. @@ -9,25 +9,31 @@ * * SPDX-License-Identifier: EPL-2.0 ************************************************************************************** */ -package org.cna.keyple.tool.calypso.carddata; +package org.calypsonet.tool.calypso.carddata; +/** + * Contains information about a file: the LID, the linked file LID, the reference value read, and a + * flag indicating whether the reference has been found. + * + * @since 2.0.0 + */ public class FileReference { - private String baseFileLid; + private final String baseFileLid; - private String linkedFileLid; + private final String linkedFileLid; - private String refValueRead; + private final String refValueRead; - private Boolean referenceFoundFlag; + private boolean referenceFoundFlag; public FileReference(String baseLid, String linkedLid, String refValue) { - this.baseFileLid = new String(baseLid); + this.baseFileLid = baseLid; - this.linkedFileLid = new String(linkedLid); + this.linkedFileLid = linkedLid; - this.refValueRead = new String(refValue); + this.refValueRead = refValue; this.referenceFoundFlag = false; } @@ -44,11 +50,11 @@ public String getRefValueRead() { return refValueRead; } - public Boolean getReferenceFoundFlag() { + public boolean getReferenceFoundFlag() { return referenceFoundFlag; } - public void setReferenceFoundFlag(Boolean referenceFoundFlag) { + public void setReferenceFoundFlag(boolean referenceFoundFlag) { this.referenceFoundFlag = referenceFoundFlag; } } diff --git a/src/main/java/org/cna/keyple/tool/calypso/carddata/RecordData.java b/src/main/java/org/calypsonet/tool/calypso/carddata/RecordData.java similarity index 70% rename from src/main/java/org/cna/keyple/tool/calypso/carddata/RecordData.java rename to src/main/java/org/calypsonet/tool/calypso/carddata/RecordData.java index d93da3f..8cea8af 100644 --- a/src/main/java/org/cna/keyple/tool/calypso/carddata/RecordData.java +++ b/src/main/java/org/calypsonet/tool/calypso/carddata/RecordData.java @@ -1,5 +1,5 @@ /* ************************************************************************************** - * Copyright (c) 2019 Calypso Networks Association https://calypsonet.org/ + * Copyright (c) 2024 Calypso Networks Association https://calypsonet.org/ * * See the NOTICE file(s) distributed with this work for additional information * regarding copyright ownership. @@ -9,22 +9,27 @@ * * SPDX-License-Identifier: EPL-2.0 ************************************************************************************** */ -package org.cna.keyple.tool.calypso.carddata; +package org.calypsonet.tool.calypso.carddata; import java.util.Arrays; +import org.eclipse.keyple.core.util.HexUtil; +/** + * Represents a record data including index and value. + * + * @since 2.0.0 + */ public class RecordData { - private String index; + private final String index; - private byte[] value; + private final byte[] value; public RecordData(int recordIndex, byte[] recordData) { - index = String.format("%02X", recordIndex); + index = HexUtil.toHex(recordIndex); value = Arrays.copyOf(recordData, recordData.length); - ; } public String getIndex() { diff --git a/src/main/java/org/cna/keyple/tool/calypso/common/ToolUtils.java b/src/main/java/org/calypsonet/tool/calypso/common/ToolUtils.java similarity index 81% rename from src/main/java/org/cna/keyple/tool/calypso/common/ToolUtils.java rename to src/main/java/org/calypsonet/tool/calypso/common/ToolUtils.java index 3793ff0..d5f407c 100644 --- a/src/main/java/org/cna/keyple/tool/calypso/common/ToolUtils.java +++ b/src/main/java/org/calypsonet/tool/calypso/common/ToolUtils.java @@ -9,21 +9,29 @@ * * SPDX-License-Identifier: EPL-2.0 ************************************************************************************** */ -package org.cna.keyple.tool.calypso.common; +package org.calypsonet.tool.calypso.common; import com.google.gson.*; import java.lang.reflect.Type; -import org.calypsonet.terminal.calypso.card.ElementaryFile; import org.eclipse.keyple.core.service.Plugin; import org.eclipse.keyple.core.util.HexUtil; +import org.eclipse.keypop.calypso.card.card.ElementaryFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Utility class for various tool functions. + * + * @since 2.0.0 + */ public class ToolUtils { private static final Logger logger = LoggerFactory.getLogger(ToolUtils.class); + public static final String SEPARATOR_LINE = + "========================================================================================================"; - public static final String CARD_READER_NAME_REGEX = ".*(ASK.*|Identiv.*2|ACS ACR122U|SCR3310).*"; + public static final String DEFAULT_CARD_READER_NAME_REGEX = + ".*(ASK.*|Identiv.*2|ACS ACR122U|SCR3310).*"; public static final String ISO_CARD_PROTOCOL = "ISO_14443_4_CARD"; public static final String SAM_READER_NAME_REGEX = ".*(Cherry TC|Identiv.*|SCM Microsystems|HID|Generic|ACS).*"; @@ -34,6 +42,8 @@ public class ToolUtils { public static final int CARD_EF_TYPE_SIMULATED_COUNTERS = 8; public static final int CARD_EF_TYPE_COUNTERS = 9; + private ToolUtils() {} + public static String getCardReaderName(Plugin plugin, String readerNameRegex) { for (String readerName : plugin.getReaderNames()) { if (readerName.matches(readerNameRegex)) { @@ -42,16 +52,7 @@ public static String getCardReaderName(Plugin plugin, String readerNameRegex) { } } throw new IllegalStateException( - String.format("Reader '%s' not found in plugin '%s'", readerNameRegex, plugin.getName())); - } - - public static long bytesToLong(byte[] b, int length) { - long result = 0; - for (int i = 0; i < length; i++) { - result <<= 8; - result |= (b[i] & 0xFF); - } - return result; + "Reader '" + readerNameRegex + "' not found in plugin '" + plugin.getName() + "'"); } public static String getEfTypeName(String inEfType, boolean longModeFlag) { @@ -65,31 +66,34 @@ public static String getEfTypeName(int inEfType, boolean longModeFlag) { switch (inEfType) { case CARD_EF_TYPE_BINARY: { - return ((longModeFlag == true) ? "Binary" : "Bin "); + return (longModeFlag ? "Binary" : "Bin "); } case CARD_EF_TYPE_LINEAR: { - return ((longModeFlag == true) ? "Linear" : "Lin "); + return (longModeFlag ? "Linear" : "Lin "); } case CARD_EF_TYPE_CYCLIC: { - return ((longModeFlag == true) ? "Cyclic" : "Cycl"); + return (longModeFlag ? "Cyclic" : "Cycl"); } case CARD_EF_TYPE_SIMULATED_COUNTERS: { - return ((longModeFlag == true) ? "SimulatedCounter" : "SimC"); + return (longModeFlag ? "SimulatedCounter" : "SimC"); } case CARD_EF_TYPE_COUNTERS: { - return ((longModeFlag == true) ? "Counter" : "Cnt "); + return (longModeFlag ? "Counter" : "Cnt "); } - } - return "--"; + default: + { + return "--"; + } + } } public static int getEfTypeIntValue(ElementaryFile.Type inType) { @@ -119,8 +123,12 @@ public static int getEfTypeIntValue(ElementaryFile.Type inType) { { return CARD_EF_TYPE_SIMULATED_COUNTERS; } + + default: + { + return 0; + } } - return 0; } public static String getAcName(String inAcValue, String inKeyLevel, boolean longModeFlag) { @@ -135,36 +143,38 @@ public static String getAcName(int inAcValue, int inKeyLevel, boolean longModeFl switch (inAcValue) { case 0x1F: { - return ((longModeFlag == true) ? "Always" : "AA"); + return (longModeFlag ? "Always" : "AA"); } case 0x00: { - return ((longModeFlag == true) ? "Never" : "NN"); + return (longModeFlag ? "Never" : "NN"); } case 0x10: { - return ((longModeFlag == true) ? ("Session" + inKeyLevel) : ("S" + inKeyLevel)); + return (longModeFlag ? ("Session" + inKeyLevel) : ("S" + inKeyLevel)); } case 0x01: { - return ((longModeFlag == true) ? "PIN" : "PN"); + return (longModeFlag ? "PIN" : "PN"); } case 0x14: { - return ((longModeFlag == true) ? "Confidential" + inKeyLevel : "C" + inKeyLevel); + return (longModeFlag ? "Confidential" + inKeyLevel : "C" + inKeyLevel); } case 0x15: { - return ((longModeFlag == true) ? "Confidential&PIN" + inKeyLevel : "P" + inKeyLevel); + return (longModeFlag ? "Confidential&PIN" + inKeyLevel : "P" + inKeyLevel); + } + default: + { + return "--"; } } - - return "--"; } public static String getIssuerName(byte inIssuer) { @@ -396,9 +406,12 @@ public static String getIssuerName(byte inIssuer) { { return "Aruba PEC"; } - } - return "--"; + default: + { + return "--"; + } + } } public static class HexTypeAdapter implements JsonSerializer, JsonDeserializer { @@ -413,6 +426,18 @@ public JsonElement serialize(byte[] data, Type typeOfSrc, JsonSerializationConte } } + public static String padLeft(String input, int length, char padChar) { + if (length <= input.length()) { + return input; + } + StringBuilder sb = new StringBuilder(); + for (int i = input.length(); i < length; i++) { + sb.append(padChar); + } + sb.append(input); + return sb.toString(); + } + /* public static boolean unlockSam(SamResource samResource, byte[] unlockData) throws KeypleReaderException { diff --git a/src/main/java/org/cna/keyple/tool/calypso/carddata/CardApplicationData.java b/src/main/java/org/cna/keyple/tool/calypso/carddata/CardApplicationData.java deleted file mode 100644 index cf89512..0000000 --- a/src/main/java/org/cna/keyple/tool/calypso/carddata/CardApplicationData.java +++ /dev/null @@ -1,389 +0,0 @@ -/* ************************************************************************************** - * Copyright (c) 2018 Calypso Networks Association https://calypsonet.org/ - * - * See the NOTICE file(s) distributed with this work for additional information - * regarding copyright ownership. - * - * This program and the accompanying materials are made available under the terms of the - * Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - ************************************************************************************** */ -package org.cna.keyple.tool.calypso.carddata; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import org.calypsonet.terminal.calypso.WriteAccessLevel; -import org.calypsonet.terminal.calypso.card.CalypsoCard; -import org.cna.keyple.tool.calypso.common.ToolUtils; -import org.eclipse.keyple.core.util.HexUtil; -import org.slf4j.Logger; - -public class CardApplicationData { - - public class Issuer { - - private String value; - - private String name; - - public Issuer(byte inValue) { - - value = String.format("%02X", inValue); - - name = new String(ToolUtils.getIssuerName(inValue)); - } - - public String getValue() { - return value; - } - - public String getName() { - return name; - } - } - - private byte[] fci; - - private String calypsoRevision; - - private byte[] aid; - - private byte[] csn; - - private long csnDec; - - private String sessionModif; - - private int sessionModifDec; - - private int bufferSize; - - private String platform; - - private String applicationType; - - private String applicationSubtype; - - private Issuer issuer; - - private String version; - - private String revision; - - private String transactionCounter; - - private long transactionCounterDec; - - private AccessConditions accessConditions; - - private String status; - - private String kif1; - - private String kif2; - - private String kif3; - - private String kvc1; - - private String kvc2; - - private String kvc3; - - private String lid; - - List fileList = null; - - private static int getSessionBufferSize(int sessionModification) { - - switch (sessionModification) { - case 6: - return 215; - - case 7: - return 256; - - case 8: - return 304; - - case 9: - return 362; - - case 10: - return 430; - - case 11: - return 512; - - case 12: - return 608; - - case 13: - return 724; - - case 14: - return 861; - - case 15: - return 1024; - - default: - return 0; - } - } - - public CardApplicationData(CalypsoCard appData) { - - csn = - Arrays.copyOf( - appData.getApplicationSerialNumber(), appData.getApplicationSerialNumber().length); - - csnDec = ToolUtils.bytesToLong(appData.getApplicationSerialNumber(), 8); - - calypsoRevision = new String(appData.getProductType().toString()); - - sessionModif = String.format("%04X", appData.getSessionModification()); - - sessionModifDec = appData.getSessionModification(); - - bufferSize = getSessionBufferSize(appData.getSessionModification()); - - transactionCounter = "Not available"; // String.format("%06X", appData.getTransactionCounter()); - - transactionCounterDec = 0; // appData.getTransactionCounter(); - - platform = String.format("%02X", appData.getPlatform()); - - issuer = new Issuer(appData.getSoftwareIssuer()); - - version = String.format("%02X", appData.getSoftwareVersion()); - - revision = String.format("%02X", appData.getSoftwareRevision()); - - fci = - Arrays.copyOf( - appData.getSelectApplicationResponse(), appData.getSelectApplicationResponse().length); - - aid = Arrays.copyOf(appData.getDfName(), appData.getDfName().length); - - lid = String.format("%04X", appData.getDirectoryHeader().getLid()); - - kif1 = - String.format( - "%02X", appData.getDirectoryHeader().getKif(WriteAccessLevel.PERSONALIZATION)); - - kif2 = String.format("%02X", appData.getDirectoryHeader().getKif(WriteAccessLevel.LOAD)); - - kif3 = String.format("%02X", appData.getDirectoryHeader().getKif(WriteAccessLevel.DEBIT)); - - kvc1 = - String.format( - "%02X", appData.getDirectoryHeader().getKvc(WriteAccessLevel.PERSONALIZATION)); - - kvc2 = String.format("%02X", appData.getDirectoryHeader().getKvc(WriteAccessLevel.LOAD)); - - kvc3 = String.format("%02X", appData.getDirectoryHeader().getKvc(WriteAccessLevel.DEBIT)); - - status = String.format("%02X", appData.getDirectoryHeader().getDfStatus()); - - accessConditions = - new AccessConditions( - appData.getDirectoryHeader().getAccessConditions(), - appData.getDirectoryHeader().getKeyIndexes()); - - applicationType = String.format("%02X", appData.getApplicationType()); - - applicationSubtype = String.format("%02X", appData.getApplicationSubtype()); - - fileList = new ArrayList(); - } - - public void print(Logger logger) { - - logger.info( - "========================================================================================================"); - logger.info( - "| AID | LID | KVC1 | KVC2 | KVC3 | KIF1 | KIF2 | KIF3 | G0 | G1 | G2 | G3 |"); - logger.info( - "{}", - String.format( - "|%32s | %4s | %2s | %2s | %2s | %2s | %2s | %2s | %s | %s | %s | %s |", - HexUtil.toHex(this.getAid()), - this.getLid(), - this.getKvc1(), - this.getKvc2(), - this.getKvc3(), - this.getKif1(), - this.getKif2(), - this.getKif3(), - ToolUtils.getAcName( - this.getAccessConditions().getGroup0().getAccessCondition(), - this.getAccessConditions().getGroup0().getKeyLevel(), - false), - ToolUtils.getAcName( - this.getAccessConditions().getGroup1().getAccessCondition(), - this.getAccessConditions().getGroup1().getKeyLevel(), - false), - ToolUtils.getAcName( - this.getAccessConditions().getGroup2().getAccessCondition(), - this.getAccessConditions().getGroup2().getKeyLevel(), - false), - ToolUtils.getAcName( - this.getAccessConditions().getGroup3().getAccessCondition(), - this.getAccessConditions().getGroup3().getKeyLevel(), - false))); - logger.info( - "========================================================================================================"); - - logger.info("{}", String.format("= FCI:: %s", HexUtil.toHex(this.getFci()))); - logger.info( - "{}", - String.format("= Serial Number:: %s (%d)", HexUtil.toHex(this.getCsn()), this.getCsnDec())); - logger.info("{}", String.format("= Transaction Counter:: %d", this.getTransactionCounterDec())); - logger.info("{}", String.format("= Revision:: %s", this.getCalypsoRevision())); - logger.info("{}", String.format("= Session Buffer Size:: %d bytes", this.getBufferSize())); - logger.info("{}", String.format("= Platform (Chip Type):: %s", this.getPlatform())); - - if (this.getIssuerInfo() != null) { - logger.info( - "{}", - String.format( - "= Issuer:: %s(%s)", - this.getIssuerInfo().getName(), this.getIssuerInfo().getValue())); - } else { - logger.info("= Issuer:: null"); - } - - logger.info( - "{}", String.format("= Software Version:: %s.%s", this.getVersion(), this.getRevision())); - logger.info("{}", String.format("= Application Type:: %s", this.getApplicationType())); - logger.info("{}", String.format("= Application Subtype:: %s", this.getApplicationSubtype())); - logger.info("{}", String.format("= DF Status:: %2s", this.getStatus())); - logger.info( - "========================================================================================================"); - - logger.info("| LID | Type | SID | #R | Size | G0 | G1 | G2 | G3 | DRef |"); - logger.info("----------------------------------------------------------"); - - List fileList = this.getFileList(); - Iterator fileIter = fileList.iterator(); - - while (fileIter.hasNext()) { - - CardFileData fileData = (CardFileData) fileIter.next(); - - fileData.print(logger); - } - } - - public byte[] getFci() { - return fci; - } - - public byte[] getCsn() { - return csn; - } - - public long getCsnDec() { - return csnDec; - } - - public String getCalypsoRevision() { - return calypsoRevision; - } - - public String getSessionModif() { - return sessionModif; - } - - public int getSessionModifDec() { - return sessionModifDec; - } - - public int getBufferSize() { - return bufferSize; - } - - public String getTransactionCounter() { - return transactionCounter; - } - - public long getTransactionCounterDec() { - return transactionCounterDec; - } - - public String getPlatform() { - return platform; - } - - public Issuer getIssuerInfo() { - return issuer; - } - - public Issuer getIssuer() { - return issuer; - } - - public String getVersion() { - return version; - } - - public String getRevision() { - return revision; - } - - public byte[] getAid() { - return aid; - } - - public String getLid() { - return lid; - } - - public String getKif1() { - return kif1; - } - - public String getKif2() { - return kif2; - } - - public String getKif3() { - return kif3; - } - - public String getKvc1() { - return kvc1; - } - - public String getKvc2() { - return kvc2; - } - - public String getKvc3() { - return kvc3; - } - - public AccessConditions getAccessConditions() { - return accessConditions; - } - - public String getApplicationType() { - return applicationType; - } - - public String getApplicationSubtype() { - return applicationSubtype; - } - - public String getStatus() { - return status; - } - - public List getFileList() { - return fileList; - } -} diff --git a/src/main/java/org/cna/keyple/tool/calypso/carddata/CardFileData.java b/src/main/java/org/cna/keyple/tool/calypso/carddata/CardFileData.java deleted file mode 100644 index 29a5273..0000000 --- a/src/main/java/org/cna/keyple/tool/calypso/carddata/CardFileData.java +++ /dev/null @@ -1,156 +0,0 @@ -/* ************************************************************************************** - * Copyright (c) 2019 Calypso Networks Association https://calypsonet.org/ - * - * See the NOTICE file(s) distributed with this work for additional information - * regarding copyright ownership. - * - * This program and the accompanying materials are made available under the terms of the - * Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0 - * - * SPDX-License-Identifier: EPL-2.0 - ************************************************************************************** */ -package org.cna.keyple.tool.calypso.carddata; - -import java.util.ArrayList; -import java.util.List; -import org.calypsonet.terminal.calypso.card.ElementaryFile; -import org.cna.keyple.tool.calypso.common.ToolUtils; -import org.eclipse.keyple.core.util.HexUtil; -import org.slf4j.Logger; - -public class CardFileData { - - private String sfi; - - private String lid; - - private String efType; - - private String efTypeName; - - private String ref; - - private String recSize; - - private int recSizeDec; - - private String numRec; - - private int numRecDec; - - private AccessConditions accessConditions; - - private List recordData; - - public CardFileData(ElementaryFile fileInfo) { - - int efTypeValue = ToolUtils.getEfTypeIntValue(fileInfo.getHeader().getEfType()); - - lid = String.format("%04X", fileInfo.getHeader().getLid()); - - sfi = String.format("%02X", fileInfo.getSfi()); - - efType = String.format("%02X", efTypeValue); - - efTypeName = ToolUtils.getEfTypeName(efTypeValue, true); - - numRec = String.format("%02X", fileInfo.getHeader().getRecordsNumber()); - - numRecDec = fileInfo.getHeader().getRecordsNumber(); - - recSize = String.format("%04X", fileInfo.getHeader().getRecordSize()); - - recSizeDec = fileInfo.getHeader().getRecordSize(); - - accessConditions = - new AccessConditions( - fileInfo.getHeader().getAccessConditions(), fileInfo.getHeader().getKeyIndexes()); - - recordData = new ArrayList(); - - ref = String.format("%04X", fileInfo.getHeader().getSharedReference()); - } - - public String getLid() { - return lid; - } - - public String getSfi() { - return sfi; - } - - public String getEfType() { - return efType; - } - - public String getFileTypeName() { - return efType; - } - - public String getNumRec() { - return numRec; - } - - public int getNumRecDec() { - return numRecDec; - } - - public String getRecSize() { - return recSize; - } - - public int getRecSizeDec() { - return recSizeDec; - } - - public AccessConditions getAccessConditions() { - return accessConditions; - } - - public String getDataRef() { - return ref; - } - - public List getRecordData() { - return recordData; - } - - public void print(Logger logger) { - - logger.info( - "{}", - String.format( - "| %4s | %s | %2s | %2d | %4d | %s | %s | %s | %s | %4s |", - this.getLid(), - ToolUtils.getEfTypeName(this.getEfType(), false), - this.getSfi(), - this.getNumRecDec(), - this.getRecSizeDec(), - ToolUtils.getAcName( - this.getAccessConditions().getGroup0().getAccessCondition(), - this.getAccessConditions().getGroup0().getKeyLevel(), - false), - ToolUtils.getAcName( - this.getAccessConditions().getGroup1().getAccessCondition(), - this.getAccessConditions().getGroup1().getKeyLevel(), - false), - ToolUtils.getAcName( - this.getAccessConditions().getGroup2().getAccessCondition(), - this.getAccessConditions().getGroup2().getKeyLevel(), - false), - ToolUtils.getAcName( - this.getAccessConditions().getGroup3().getAccessCondition(), - this.getAccessConditions().getGroup3().getKeyLevel(), - false), - this.getDataRef())); - - for (int i = 0; this.getRecordData() != null && i < this.getRecordData().size(); i++) { - logger.info( - "{}", - String.format( - "+ #%s:%s", - this.getRecordData().get(i).getIndex(), - HexUtil.toHex(this.getRecordData().get(i).getValue()))); - } - } -}