Хороший день.
Несколько дней назад я приобрел терминал (модель P18Q), который поддерживает различные методы аутентификации для карт Mifare Plus. Поставщик сообщил мне, что мне нужно внедрить свои собственные алгоритмы шифрования для связи с картой, которая работает в режиме SL3, и для аутентификации в определенном секторе. Однако при использовании моей пользовательской реализации - где я отправляю свой ключ AES вместе с ответом на вызов - я последовательно сталкиваюсь с ошибкой во время процесса MPLUS_FIRSTAUTH_F2. < /P>
Кто -нибудь знает, правильно ли я выполняю аутентификацию? К сожалению, я не могу использовать официальную библиотеку NXP на этом терминале, так как в нем отсутствует стандартный читатель Android NFC. Вместо этого он связывается только через Apdus с внешним терминалом. Я делаю что -то не так? Это моя первая работа с этим типом карты. < /P>
public void test_MifarePlus() {
final int CID = 0;
final int fsdi = PICC_FSD_256;
int DRI = PICC_BITRATE_TXRX_106K;
int DSI = PICC_BITRATE_TXRX_106K;
clearLog();
appendLog("Iniciando autenticación Mifare Plus...");
try {
appendLog(">>> Paso 1: Detectando tarjeta...");
String uid = detectNfcCard();
if (uid == null || uid.isEmpty()) {
appendLog("Error: No se detectó tarjeta NFC");
return;
}
appendLog("Tarjeta detectada. UID: " + uid);
appendLog("\n>>> Paso 2: Activando tarjeta...");
String ATS = activateTypeACard(fsdi, CID);
if (ATS == null || ATS.length() < 2) {
appendLog("Error: Fallo en activación de tarjeta");
return;
}
byte[] atsBytes = ByteArrayTools.hexStringToByteArray(ATS);
int[] rates = PICC_ParseRate(atsBytes);
DRI = rates[0];
DSI = rates[1];
appendLog("ATS recibido: " + ATS);
appendLog("Parámetros negociados - DRI: " + DRI + ", DSI: " + DSI);
appendLog("\n>>> Paso 3: Solicitud PPS...");
int ppsStatus = requestPPS(CID, DRI, DSI);
if (ppsStatus != 0) {
appendLog("Error: Fallo en PPS (Código: " + ppsStatus + ")");
return;
}
appendLog("PPS exitoso");
appendLog("\n>>> Paso 4: Configurando autenticación SL3...");
P18QMifarePlus channel = new P18QMifarePlus();
MifarePlus mifarePlus = new MifarePlus(channel);
byte[] keyAES;
try {
keyAES = ByteArrayTools.hexStringToByteArray(AESKey);
if (keyAES == null || keyAES.length != 16) {
appendLog("Error: Clave AES inválida. Debe ser de 16 bytes");
return;
}
} catch (IllegalArgumentException e) {
appendLog("Error: Formato de clave AES inválido");
return;
}
appendLog("\n>>> Paso 5: Autenticación F1...");
int blockToAuth = 0x4002;
byte[] encryptedChallenge = mifarePlus.mplus_firstAuth_f1(blockToAuth);
if (encryptedChallenge == null || encryptedChallenge.length < 16) {
appendLog("Error: Challenge inválido o autenticación F1 fallida");
return;
}
appendLog("Challenge cifrado recibido: " +
ByteArrayTools.byteArrayToHexString(encryptedChallenge));
byte[] randB;
try {
randB = aesDecrypt(Arrays.copyOf(encryptedChallenge, 16), keyAES);
if (randB == null || randB.length != 16) {
appendLog("Error: Descifrado de RAND_B fallido");
return;
}
} catch (Exception e) {
appendLog("Error al descifrar RAND_B: " + e.getMessage());
return;
}
appendLog("RAND_B descifrado: " + ByteArrayTools.byteArrayToHexString(randB));
byte[] randB_rot = rotateLeftByte(randB);
byte[] randA = generateSecureRandom(16);
byte[] responseData = concatenateArrays(randA, randB_rot);
appendLog("RAND_A generado: " + ByteArrayTools.byteArrayToHexString(randA));
appendLog("RAND_B rotado: " + ByteArrayTools.byteArrayToHexString(randB_rot));
appendLog("\n>>> Paso 6: Autenticación F2...");
byte[] encryptedResponse;
try {
encryptedResponse = aesEncrypt(responseData, keyAES);
} catch (Exception e) {
appendLog("Error al cifrar respuesta F2: " + e.getMessage());
return;
}
appendLog("Datos a enviar (cifrados): " +
ByteArrayTools.byteArrayToHexString(encryptedResponse));
byte[] authResponse = mifarePlus.mplus_firstAuth_f2(encryptedResponse);
if (authResponse == null || authResponse.length == 0) {
appendLog("Error: Respuesta de autenticación F2 inválida");
return;
}
if (authResponse[0] != (byte) 0x90) {
appendLog("Autenticación fallida. Código de error: " +
String.format("%02X", authResponse[0]));
return;
}
appendLog("\nAutenticación SL3 completada con éxito!");
appendLog("Respuesta final: " + ByteArrayTools.byteArrayToHexString(authResponse));
} catch (Exception e) {
appendLog("Error crítico: " + e.toString());
e.printStackTrace();
} finally {
try {
int removalStatus = removeCPUCard();
appendLog(removalStatus == 0 ? "Operación completada" : "Error al remover tarjeta");
} catch (Exception e) {
appendLog("Error al limpiar: " + e.getMessage());
}
}
}
private byte[] aesEncrypt(byte[] data, byte[] key) throws Exception {
if (data == null || key == null) {
throw new IllegalArgumentException("Datos o clave nulos");
}
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
return cipher.doFinal(data);
}
private byte[] aesDecrypt(byte[] data, byte[] key) throws Exception {
if (data == null || key == null) {
throw new IllegalArgumentException("Datos o clave nulos");
}
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
SecretKeySpec secretKey = new SecretKeySpec(key, "AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return cipher.doFinal(data);
}
private byte[] rotateLeftByte(byte[] input) {
if (input == null || input.length == 0) {
throw new IllegalArgumentException("Array de entrada inválido");
}
byte[] output = new byte[input.length];
System.arraycopy(input, 1, output, 0, input.length - 1);
output[input.length - 1] = input[0];
return output;
}
private byte[] generateSecureRandom(int length) {
byte[] randomBytes = new byte[length];
new SecureRandom().nextBytes(randomBytes);
return randomBytes;
}
private byte[] concatenateArrays(byte[] a, byte[] b) {
byte[] result = new byte[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
public byte[] mplus_firstAuth_f1(int key) throws Exception {
byte bloque1 = (byte) ( ( key >> 8 ) & 0xFF );
byte bloque2 = (byte) ( ( key ) & 0xFF );
byte[] apdu = new byte[4];
apdu[0] = 0x70;
apdu[1] = bloque2;
apdu[2] = bloque1;
apdu[3] = 0x00;
byte[] response = mplusMgr.sendApduCommand(apdu);
if ( response == null ) {
return null;
}
if ( response[0] == (byte) 0x90 ) {
return Arrays.copyOfRange(response, 1, response.length);
} else {
return null;
}
}
public byte[] mplus_firstAuth_f2(byte[] data) throws Exception {
if ( data == null ) {
return null;
}
byte[] apdu = new byte[data.length + 1];
apdu[0] = (byte) 0x72;
System.arraycopy(data, 0, apdu, 1, data.length);
byte[] response = mplusMgr.sendApduCommand(apdu);
return response;
}
Подробнее здесь: https://stackoverflow.com/questions/796 ... us-ev2-sl3
Аутентификация с Mifare Plus EV2 SL3 ⇐ JAVA
-
- Похожие темы
- Ответы
- Просмотры
- Последнее сообщение