From 7aeed949061f4de5d32712b925554b52ad1d1254 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Wed, 7 Jan 2026 19:38:30 +0100 Subject: [PATCH 1/8] feat: add Mifare Classic support and ST25 methods --- CHANGELOG.md | 32 +++++- gradle.properties | 2 +- .../storagecard/MifareClassicKeyType.java | 45 +++++++++ .../SCAuthenticationFailedException.java | 67 +++++++++++++ .../storagecard/StorageCardApiProperties.java | 2 +- .../keypop/storagecard/card/ProductType.java | 46 ++++++++- .../keypop/storagecard/card/StorageCard.java | 8 +- .../card/StorageCardSelectionExtension.java | 44 +++++++++ .../keypop/storagecard/package-info.java | 23 ++++- .../StorageCardTransactionManager.java | 97 +++++++++++++++++++ 10 files changed, 356 insertions(+), 10 deletions(-) create mode 100644 src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java create mode 100644 src/main/java/org/eclipse/keypop/storagecard/SCAuthenticationFailedException.java diff --git a/CHANGELOG.md b/CHANGELOG.md index c5f92e8..0b723d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [unreleased] +## [1.1.0] - 2025-12-05 +### Added +- **Mifare Classic support**: New product types `MIFARE_CLASSIC_1K` and `MIFARE_CLASSIC_4K` in + `ProductType` enum to support NXP Mifare Classic 1K (64 blocks) and 4K (256 blocks) cards. +- **Authentication capability**: New `ProductType.hasAuthentication()` method to indicate whether a + storage card requires authentication before read/write operations. +- **Mifare Classic key types**: New `MifareClassicKeyType` enum with `KEY_A` and `KEY_B` constants + for Mifare Classic authentication. +- **Authentication methods**: New authentication methods for Mifare Classic cards: + - `StorageCardSelectionExtension.prepareMifareClassicAuthenticate(int blockAddress, MifareClassicKeyType, byte[] key)` + - `StorageCardSelectionExtension.prepareMifareClassicAuthenticate(int blockAddress, MifareClassicKeyType, int keyNumber)` + - `StorageCardTransactionManager.prepareMifareClassicAuthenticate(int blockAddress, MifareClassicKeyType, byte[] key)` + - `StorageCardTransactionManager.prepareMifareClassicAuthenticate(int blockAddress, MifareClassicKeyType, int keyNumber)` +- **Authentication exception**: New `SCAuthenticationFailedException` for handling Mifare Classic + authentication failures. +- **ST25-specific system block methods**: New dedicated methods for ST25/SRT512 system block access: + - `StorageCardTransactionManager.prepareSt25ReadSystemBlock()` + - `StorageCardTransactionManager.prepareSt25WriteSystemBlock(byte[] data)` +### Changed +- **System block documentation**: Enhanced `StorageCard.getSystemBlock()` documentation to clarify + it is specific to ST25/SRT512 cards. +- **Package documentation**: Improved `package-info.java` with detailed descriptions of all public + API elements. +### Deprecated +- `StorageCardTransactionManager.prepareReadSystemBlock()` - Use `prepareSt25ReadSystemBlock()` + instead. +- `StorageCardTransactionManager.prepareWriteSystemBlock(byte[])` - Use + `prepareSt25WriteSystemBlock(byte[])` instead. + ## [1.0.0] - 2025-11-21 ### Changed - **Exception hierarchy refactoring**: `StorageCardException` transformed from abstract class to interface. @@ -70,7 +99,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.0] - 2025-06-18 This is the initial release. -[unreleased]: https://github.com/eclipse-keypop/keypop-storagecard-java-api/compare/1.0.0...HEAD +[unreleased]: https://github.com/eclipse-keypop/keypop-storagecard-java-api/compare/1.1.0...HEAD +[1.1.0]: https://github.com/eclipse-keypop/keypop-storagecard-java-api/compare/1.0.0...1.1.0 [1.0.0]: https://github.com/eclipse-keypop/keypop-storagecard-java-api/compare/0.3.0...1.0.0 [0.3.0]: https://github.com/eclipse-keypop/keypop-storagecard-java-api/compare/0.2.0...0.3.0 [0.2.0]: https://github.com/eclipse-keypop/keypop-storagecard-java-api/compare/0.1.0...0.2.0 diff --git a/gradle.properties b/gradle.properties index ed9ac83..12c5b87 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,7 +2,7 @@ group = org.eclipse.keypop title = Keypop Storage Card Java API description = API defining the needed interfaces to manage storage cards -version = 1.0.0-SNAPSHOT +version = 1.1.0-SNAPSHOT # Java Configuration javaSourceLevel = 1.8 diff --git a/src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java b/src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java new file mode 100644 index 0000000..31cbbf8 --- /dev/null +++ b/src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java @@ -0,0 +1,45 @@ +/* ************************************************************************************** + * Copyright (c) 2025 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 + * MIT License which is available at https://opensource.org/licenses/MIT + * + * SPDX-License-Identifier: MIT + ************************************************************************************** */ +package org.eclipse.keypop.storagecard; + +/** + * Enumeration of the Mifare Classic key types used for authentication. + * + *

Mifare Classic cards support two types of keys per sector for access control: Key A and Key B. + * Each sector can be protected independently using these keys, allowing fine-grained access + * control. + * + * @since 1.1.0 + */ +public enum MifareClassicKeyType { + + /** + * Key A type. + * + *

This is the primary key used for authentication to a Mifare Classic sector. In most + * configurations, Key A has read/write permissions while Key B may have restricted permissions. + * + * @since 1.1.0 + */ + KEY_A, + + /** + * Key B type. + * + *

This is the secondary key used for authentication to a Mifare Classic sector. Key B is often + * used for restricted operations or read-only access, depending on the sector's access + * conditions. + * + * @since 1.1.0 + */ + KEY_B +} diff --git a/src/main/java/org/eclipse/keypop/storagecard/SCAuthenticationFailedException.java b/src/main/java/org/eclipse/keypop/storagecard/SCAuthenticationFailedException.java new file mode 100644 index 0000000..d2b446c --- /dev/null +++ b/src/main/java/org/eclipse/keypop/storagecard/SCAuthenticationFailedException.java @@ -0,0 +1,67 @@ +/* ************************************************************************************** + * Copyright (c) 2025 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 + * MIT License which is available at https://opensource.org/licenses/MIT + * + * SPDX-License-Identifier: MIT + ************************************************************************************** */ +package org.eclipse.keypop.storagecard; + +import org.eclipse.keypop.reader.CardCommunicationException; +import org.eclipse.keypop.storagecard.card.StorageCard; + +/** + * Indicates that an authentication attempt on a {@link StorageCard} has failed. + * + *

This exception is thrown when authentication to a Mifare Classic sector fails, typically due + * to incorrect key data or key type. Authentication is required before reading from or writing to + * protected sectors on Mifare Classic cards. + * + * @since 1.1.0 + */ +public final class SCAuthenticationFailedException extends CardCommunicationException + implements StorageCardException { + + private final Integer blockAddress; + + /** + * Creates a new exception indicating an authentication failure during the execution of a storage + * card command. + * + * @param blockAddress The block address involved in the error, or {@code null} if not relevant. + * @param message The message describing the exception context. + * @since 1.1.0 + */ + public SCAuthenticationFailedException(Integer blockAddress, String message) { + super(message); + this.blockAddress = blockAddress; + } + + /** + * Creates a new exception indicating an authentication failure during the execution of a storage + * card command, with an underlying cause. + * + * @param blockAddress The block address involved in the error, or {@code null} if not relevant. + * @param message The message describing the exception context. + * @param cause The underlying cause of the exception. + * @since 1.1.0 + */ + public SCAuthenticationFailedException(Integer blockAddress, String message, Throwable cause) { + super(message, cause); + this.blockAddress = blockAddress; + } + + /** + * {@inheritDoc} + * + * @since 1.1.0 + */ + @Override + public Integer getBlockAddress() { + return blockAddress; + } +} diff --git a/src/main/java/org/eclipse/keypop/storagecard/StorageCardApiProperties.java b/src/main/java/org/eclipse/keypop/storagecard/StorageCardApiProperties.java index 853d3a8..e1f8912 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/StorageCardApiProperties.java +++ b/src/main/java/org/eclipse/keypop/storagecard/StorageCardApiProperties.java @@ -23,7 +23,7 @@ public final class StorageCardApiProperties { * * @since 1.0.0 */ - public static final String VERSION = "1.0"; + public static final String VERSION = "1.1"; /** Private constructor */ private StorageCardApiProperties() {} diff --git a/src/main/java/org/eclipse/keypop/storagecard/card/ProductType.java b/src/main/java/org/eclipse/keypop/storagecard/card/ProductType.java index 6209af5..d090444 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/card/ProductType.java +++ b/src/main/java/org/eclipse/keypop/storagecard/card/ProductType.java @@ -23,19 +23,34 @@ public enum ProductType { * * @since 1.0.0 */ - MIFARE_ULTRALIGHT(16, 4, false, true), + MIFARE_ULTRALIGHT(16, 4, false, true, false), + + /** + * NXP Mifare Classic 1K + * + * @since 1.1.0 + */ + MIFARE_CLASSIC_1K(64, 16, false, true, true), + + /** + * NXP Mifare Classic 4K + * + * @since 1.1.0 + */ + MIFARE_CLASSIC_4K(256, 16, false, true, true), /** * ST Microelectronics ST25 / SRT512 * * @since 1.0.0 */ - ST25_SRT512(16, 4, true, false); + ST25_SRT512(16, 4, true, false, false); private final int blockCount; private final int blockSize; private final boolean hasSystemBlock; private final boolean hasWriteAcknowledgment; + private final boolean hasAuthentication; /** * Constructor. @@ -45,13 +60,20 @@ public enum ProductType { * @param hasSystemBlock Whether this card type has an accessible system block. * @param hasWriteAcknowledgment Whether this card provides a reliable acknowledgment confirming * successful write operations. + * @param hasAuthentication Whether this card type requires authentication before read/write + * operations. */ ProductType( - int blockCount, int blockSize, boolean hasSystemBlock, boolean hasWriteAcknowledgment) { + int blockCount, + int blockSize, + boolean hasSystemBlock, + boolean hasWriteAcknowledgment, + boolean hasAuthentication) { this.blockCount = blockCount; this.blockSize = blockSize; this.hasSystemBlock = hasSystemBlock; this.hasWriteAcknowledgment = hasWriteAcknowledgment; + this.hasAuthentication = hasAuthentication; } /** @@ -108,4 +130,22 @@ public boolean hasSystemBlock() { public boolean hasWriteAcknowledgment() { return hasWriteAcknowledgment; } + + /** + * Indicates whether this storage card type requires authentication before read/write operations. + * + *

If this method returns {@code true}, the card requires successful authentication to a sector + * before read or write operations can be performed on blocks within that sector. For Mifare + * Classic cards, authentication must be performed using Key A or Key B with the appropriate + * authentication methods. + * + *

If this method returns {@code false}, the card allows direct read/write operations without + * prior authentication. + * + * @return {@code true} if the card requires authentication, {@code false} otherwise. + * @since 1.1.0 + */ + public boolean hasAuthentication() { + return hasAuthentication; + } } diff --git a/src/main/java/org/eclipse/keypop/storagecard/card/StorageCard.java b/src/main/java/org/eclipse/keypop/storagecard/card/StorageCard.java index 301d83d..a109c5b 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/card/StorageCard.java +++ b/src/main/java/org/eclipse/keypop/storagecard/card/StorageCard.java @@ -40,10 +40,12 @@ public interface StorageCard extends SmartCard { * Retrieves the system block from the storage card when available. * *

The system block contains card-specific metadata and configuration data such as access - * control settings. Not all storage card types provide access to system blocks. + * control settings. This feature is specific to ST25/SRT512 cards which provide access to a + * system block at address 255. * - *

The system block must have been previously read using a the {{@link - * StorageCardTransactionManager#prepareReadSystemBlock()}) method. + *

The system block must have been previously read using the {@link + * StorageCardTransactionManager#prepareSt25ReadSystemBlock()} method (or the deprecated {@link + * StorageCardTransactionManager#prepareReadSystemBlock()} method). * * @return The system block data as a byte array, or null if the system block has not been read * yet. diff --git a/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java b/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java index 432b63f..b0df3c5 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java +++ b/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java @@ -12,6 +12,7 @@ package org.eclipse.keypop.storagecard.card; import org.eclipse.keypop.reader.selection.spi.CardSelectionExtension; +import org.eclipse.keypop.storagecard.MifareClassicKeyType; /** * Extends the {@link CardSelectionExtension} interface of the "Keypop Reader API" to provide means @@ -54,4 +55,47 @@ public interface StorageCardSelectionExtension extends CardSelectionExtension { * @since 1.0.0 */ StorageCardSelectionExtension prepareReadBlocks(int fromBlockAddress, int toBlockAddress); + + /** + * Prepares a Mifare Classic authentication command using a provided key. + * + *

This method is specific to Mifare Classic cards and must be called before reading from or + * writing to protected sectors. The authentication applies to the entire sector containing the + * specified block address. + * + *

The key must be a 6-byte array representing the Mifare Classic key value. + * + * @param blockAddress The address of any block within the sector to authenticate. + * @param mifareClassicKeyType The type of key to use (Key A or Key B). + * @param key The 6-byte key data for authentication. + * @return The current instance. + * @throws IllegalArgumentException If the block address is out of range, or if the key is null or + * not exactly 6 bytes long. + * @throws UnsupportedOperationException If the current card type does not support authentication. + * @since 1.1.0 + */ + StorageCardSelectionExtension prepareMifareClassicAuthenticate( + int blockAddress, MifareClassicKeyType mifareClassicKeyType, byte[] key); + + /** + * Prepares a Mifare Classic authentication command using a key stored in the reader. + * + *

This method is specific to Mifare Classic cards and must be called before reading from or + * writing to protected sectors. The authentication applies to the entire sector containing the + * specified block address. + * + *

The key is referenced by its storage index in the reader's key storage. This allows using + * pre-configured keys without transmitting them over the communication channel. + * + * @param blockAddress The address of any block within the sector to authenticate. + * @param mifareClassicKeyType The type of key to use (Key A or Key B). + * @param keyNumber The index of the key in the reader's key storage. + * @return The current instance. + * @throws IllegalArgumentException If the block address is out of range, or if the key number is + * invalid. + * @throws UnsupportedOperationException If the current card type does not support authentication. + * @since 1.1.0 + */ + StorageCardSelectionExtension prepareMifareClassicAuthenticate( + int blockAddress, MifareClassicKeyType mifareClassicKeyType, int keyNumber); } diff --git a/src/main/java/org/eclipse/keypop/storagecard/package-info.java b/src/main/java/org/eclipse/keypop/storagecard/package-info.java index e438fc5..8f0a92f 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/package-info.java +++ b/src/main/java/org/eclipse/keypop/storagecard/package-info.java @@ -1,2 +1,23 @@ -/** Contains the factories and builders to create the public elements of the extension. */ +/** + * Contains the factories, builders, and exceptions for the Storage Card API. + * + *

This package provides the main entry points for interacting with storage cards: + * + *

+ */ package org.eclipse.keypop.storagecard; diff --git a/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java b/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java index c86c8d6..e1d4503 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java +++ b/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java @@ -13,6 +13,7 @@ import org.eclipse.keypop.reader.ChannelControl; import org.eclipse.keypop.reader.transaction.spi.CardTransactionManager; +import org.eclipse.keypop.storagecard.MifareClassicKeyType; import org.eclipse.keypop.storagecard.card.ProductType; import org.eclipse.keypop.storagecard.card.StorageCard; @@ -62,7 +63,10 @@ public interface StorageCardTransactionManager * @throws UnsupportedOperationException If the current card type does not support system block * access. * @since 1.0.0 + * @deprecated Use {@link #prepareSt25ReadSystemBlock()} instead. This method will be removed in a + * future version. */ + @Deprecated StorageCardTransactionManager prepareReadSystemBlock(); /** @@ -88,9 +92,50 @@ public interface StorageCardTransactionManager * write access. * @see ProductType#getBlockSize() * @since 1.0.0 + * @deprecated Use {@link #prepareSt25WriteSystemBlock(byte[])} instead. This method will be + * removed in a future version. */ + @Deprecated StorageCardTransactionManager prepareWriteSystemBlock(byte[] data); + /** + * Prepares the reading of the system block from an ST25/SRT512 storage card. + * + *

This method is specific to ST25 and SRT512 card types which provide access to a system block + * at address 255 containing card-specific metadata and configuration data. + * + *

Once this command is processed, the result is available in {@link StorageCard}. + * + * @return The current instance. + * @throws UnsupportedOperationException If the current card type is not ST25/SRT512. + * @since 1.1.0 + */ + StorageCardTransactionManager prepareSt25ReadSystemBlock(); + + /** + * Prepares the writing of data to the system block of an ST25/SRT512 storage card. + * + *

This method is specific to ST25 and SRT512 card types which provide access to a system block + * at address 255 containing card-specific metadata and configuration data. + * + *

The data length must match the block size defined by the card's {@link ProductType}. + * + *

Important: After execution of this write command, the {@link StorageCard} + * memory image is not automatically updated. ST25/SRT512 cards do not provide + * reliable status codes to confirm successful write operations. To ensure data consistency, an + * explicit read operation must be performed after the write to refresh the memory image and + * verify the actual content stored on the card. + * + * @param data The data to be written to the system block. The length must match the card's block + * size. + * @return The current instance. + * @throws IllegalArgumentException If data is null or its length does not match the block size. + * @throws UnsupportedOperationException If the current card type is not ST25/SRT512. + * @see ProductType#getBlockSize() + * @since 1.1.0 + */ + StorageCardTransactionManager prepareSt25WriteSystemBlock(byte[] data); + /** * Prepares the reading of a specific block from the storage card. * @@ -149,4 +194,56 @@ public interface StorageCardTransactionManager * @since 1.0.0 */ StorageCardTransactionManager prepareWriteBlocks(int fromBlockAddress, byte[] data); + + /** + * Prepares a Mifare Classic authentication command using a provided key. + * + *

This method is specific to Mifare Classic cards and must be called before reading from or + * writing to protected sectors. The authentication applies to the entire sector containing the + * specified block address. + * + *

The key must be a 6-byte array representing the Mifare Classic key value. + * + *

Once authenticated, subsequent read and write operations within the same sector can be + * performed without re-authentication, until the card is removed from the field or another sector + * is accessed. + * + * @param blockAddress The address of any block within the sector to authenticate. + * @param mifareClassicKeyType The type of key to use (Key A or Key B). + * @param key The 6-byte key data for authentication. + * @return The current instance. + * @throws IllegalArgumentException If the block address is out of range, or if the key is null or + * not exactly 6 bytes long. + * @throws UnsupportedOperationException If the current card type does not support authentication. + * @since 1.1.0 + */ + StorageCardTransactionManager prepareMifareClassicAuthenticate( + int blockAddress, MifareClassicKeyType mifareClassicKeyType, byte[] key); + + /** + * Prepares a Mifare Classic authentication command using a key stored in the reader. + * + *

This method is specific to Mifare Classic cards and must be called before reading from or + * writing to protected sectors. The authentication applies to the entire sector containing the + * specified block address. + * + *

The key is referenced by its storage index in the reader's key storage. This allows using + * pre-configured keys without transmitting them over the communication channel, providing + * enhanced security. + * + *

Once authenticated, subsequent read and write operations within the same sector can be + * performed without re-authentication, until the card is removed from the field or another sector + * is accessed. + * + * @param blockAddress The address of any block within the sector to authenticate. + * @param mifareClassicKeyType The type of key to use (Key A or Key B). + * @param keyNumber The index of the key in the reader's key storage. + * @return The current instance. + * @throws IllegalArgumentException If the block address is out of range, or if the key number is + * invalid. + * @throws UnsupportedOperationException If the current card type does not support authentication. + * @since 1.1.0 + */ + StorageCardTransactionManager prepareMifareClassicAuthenticate( + int blockAddress, MifareClassicKeyType mifareClassicKeyType, int keyNumber); } From 49dc671c80d218fdfff3e2a90c68082cbdc1a63b Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Tue, 13 Jan 2026 16:49:15 +0100 Subject: [PATCH 2/8] docs: simplify package documentation --- .../keypop/storagecard/package-info.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/main/java/org/eclipse/keypop/storagecard/package-info.java b/src/main/java/org/eclipse/keypop/storagecard/package-info.java index 8f0a92f..a8d991f 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/package-info.java +++ b/src/main/java/org/eclipse/keypop/storagecard/package-info.java @@ -1,23 +1,4 @@ /** * Contains the factories, builders, and exceptions for the Storage Card API. - * - *

This package provides the main entry points for interacting with storage cards: - * - *

*/ package org.eclipse.keypop.storagecard; From 01cddc04afaceee5828b62c6b8b5f76efba8f05f Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Tue, 13 Jan 2026 16:52:55 +0100 Subject: [PATCH 3/8] docs: update copyright year to 2026 --- .../org/eclipse/keypop/storagecard/MifareClassicKeyType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java b/src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java index 31cbbf8..7ac6df3 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java +++ b/src/main/java/org/eclipse/keypop/storagecard/MifareClassicKeyType.java @@ -1,5 +1,5 @@ /* ************************************************************************************** - * Copyright (c) 2025 Calypso Networks Association https://calypsonet.org/ + * Copyright (c) 2026 Calypso Networks Association https://calypsonet.org/ * * See the NOTICE file(s) distributed with this work for additional information * regarding copyright ownership. From d619ab63501c3b83f2828fbaf55e341f6003aecd Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Tue, 13 Jan 2026 16:56:38 +0100 Subject: [PATCH 4/8] docs: remove redundant package documentation entry --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b723d6..da926e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,8 +27,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - **System block documentation**: Enhanced `StorageCard.getSystemBlock()` documentation to clarify it is specific to ST25/SRT512 cards. -- **Package documentation**: Improved `package-info.java` with detailed descriptions of all public - API elements. ### Deprecated - `StorageCardTransactionManager.prepareReadSystemBlock()` - Use `prepareSt25ReadSystemBlock()` instead. From d700085c025271408c55e74745c20e7aa1bee6ab Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Tue, 13 Jan 2026 17:00:34 +0100 Subject: [PATCH 5/8] docs: reformat Storage Card API package doc --- .../java/org/eclipse/keypop/storagecard/package-info.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/eclipse/keypop/storagecard/package-info.java b/src/main/java/org/eclipse/keypop/storagecard/package-info.java index a8d991f..4e9bf6e 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/package-info.java +++ b/src/main/java/org/eclipse/keypop/storagecard/package-info.java @@ -1,4 +1,2 @@ -/** - * Contains the factories, builders, and exceptions for the Storage Card API. - */ +/** Contains the factories, builders, and exceptions for the Storage Card API. */ package org.eclipse.keypop.storagecard; From 89c7d7cdab9660016594ccc820bef7d813754708 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Tue, 13 Jan 2026 17:01:35 +0100 Subject: [PATCH 6/8] docs: remove duplicate version entry in changelog --- CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index da926e5..9d79d76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,6 @@ 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] - -## [1.1.0] - 2025-12-05 ### Added - **Mifare Classic support**: New product types `MIFARE_CLASSIC_1K` and `MIFARE_CLASSIC_4K` in `ProductType` enum to support NXP Mifare Classic 1K (64 blocks) and 4K (256 blocks) cards. From b3b5ba90ca66a448a9183321e113803cab61f2b8 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Thu, 15 Jan 2026 16:49:41 +0100 Subject: [PATCH 7/8] docs: add clarification on Mifare Classic key handling --- .../card/StorageCardSelectionExtension.java | 10 ++++++++++ .../transaction/StorageCardTransactionManager.java | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java b/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java index b0df3c5..ae7e25a 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java +++ b/src/main/java/org/eclipse/keypop/storagecard/card/StorageCardSelectionExtension.java @@ -65,6 +65,16 @@ public interface StorageCardSelectionExtension extends CardSelectionExtension { * *

The key must be a 6-byte array representing the Mifare Classic key value. * + *

When the key value is provided this way, it will be sent to the reader to be stored as a + * volatile key at index 0 (see Load Key command of the PC/SC standard). This volatile key is + * temporary and will be erased after usage, when the reader is powered off. + * + *

Security Note: This method transmits the key value over the communication + * channel between the application and the reader. For production environments and + * security-sensitive applications, it is recommended to use {@link + * #prepareMifareClassicAuthenticate(int, MifareClassicKeyType, int)} instead, which references a + * pre-stored key in the reader without transmitting the key value. + * * @param blockAddress The address of any block within the sector to authenticate. * @param mifareClassicKeyType The type of key to use (Key A or Key B). * @param key The 6-byte key data for authentication. diff --git a/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java b/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java index e1d4503..e7924ac 100644 --- a/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java +++ b/src/main/java/org/eclipse/keypop/storagecard/transaction/StorageCardTransactionManager.java @@ -204,6 +204,16 @@ public interface StorageCardTransactionManager * *

The key must be a 6-byte array representing the Mifare Classic key value. * + *

When the key value is provided this way, it will be sent to the reader to be stored as a + * volatile key at index 0 (see Load Key command of the PC/SC standard). This volatile key is + * temporary and will be erased after usage, when the reader is powered off. + * + *

Security Note: This method transmits the key value over the communication + * channel between the application and the reader. For production environments and + * security-sensitive applications, it is recommended to use {@link + * #prepareMifareClassicAuthenticate(int, MifareClassicKeyType, int)} instead, which references a + * pre-stored key in the reader without transmitting the key value. + * *

Once authenticated, subsequent read and write operations within the same sector can be * performed without re-authentication, until the card is removed from the field or another sector * is accessed. From 8c3231f33c72d5e7093f3a7dad118b09eea3fb34 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Fortune Date: Fri, 6 Feb 2026 10:26:10 +0100 Subject: [PATCH 8/8] Release 1.1.0 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d79d76..8eb2633 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ 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] + +## [1.1.0] - 2026-02-06 ### Added - **Mifare Classic support**: New product types `MIFARE_CLASSIC_1K` and `MIFARE_CLASSIC_4K` in `ProductType` enum to support NXP Mifare Classic 1K (64 blocks) and 4K (256 blocks) cards.