Home › Forums › Ask the Flomies › ACR-1255 unable to authenticate
Tagged: ACR1255 Authentication Failure
-
AuthorPosts
-
September 5, 2018 at 10:33 am #63952
Hello,
We are developing an app for reading NFC cards. The structure of the app is such that we have activities and services.
A service is created for ACS to enable and access cards on a single click and to stop poll once we move from the activity.
here is the code that is being used
package abc; import android.Manifest; import android.arch.lifecycle.MutableLiveData; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothManager; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanResult; import android.content.Context; import android.util.Log; import com.acs.bluetooth.Acr1255uj1Reader; import com.acs.bluetooth.Acr3901us1Reader; import com.acs.bluetooth.BluetoothReader; import com.acs.bluetooth.BluetoothReaderGattCallback; import com.acs.bluetooth.BluetoothReaderManager; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Set; public class BluetoothServiceImpl implements BluetoothService { private MutableLiveData<String> event = new MutableLiveData<>(); private BluetoothAdapter btAdapter; private static boolean isDeviceAuthenticated = false; private static int REQUEST_BLUETOOTH = 1; private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1; private BluetoothReaderManager mBluetoothReaderManager; private BluetoothReader mBluetoothReader; private BluetoothReaderGattCallback blueToothReaderCallBack; private static String authenticationString = "ACR1255U-J1 Auth"; private final byte[] SELECT_MASTER_FILE_APDU_COMMAND = Utils.getEditTextinHexBytes("00 A4 00 0C 02 3F 00 00"); private final byte[] SELECT_AID_APDU_COMMAND = Utils.getEditTextinHexBytes("90 5A 00 00 03 00 10 F0 00"); private final byte[] SELECT_CARD_ID_FILE_APDU_COMMAND = Utils.getEditTextinHexBytes("00 A4 00 0C 02 24 01 00"); private final byte[] READ_FILE_BUFFER_APDU_COMMAND = Utils.getEditTextinHexBytes("00 B0 00 00 07"); /* Device scan callback. */ private BluetoothDevice mBluetoothDevice; private BluetoothAdapter mBluetoothAdapter; private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { //System.out.println("Device found"+device); if(null!=device&&null!=device.getName()&&!device.getName().isEmpty()&&(device.getName().contains("ACS")||device.getName().contains("ACR"))){ System.out.println("Device found"+device.getName()); mBluetoothDevice=device; connectReader(); //authenticateDevice(); }else { // ACR not found } if(null!=mBluetoothDevice){ mBluetoothAdapter.stopLeScan(mLeScanCallback); } } }; private int connectionState = 1; private static final byte[] AUTO_POLLING_START = {(byte) 0xE0, 0x00, 0x00, 0x40, 0x01}; private static final byte[] AUTO_POLLING_STOP = {(byte) 0xE0, 0x00, 0x00, 0x40, 0x00}; private BluetoothGatt mBluetoothGatt; private boolean isTransmissionEnabled; private static final String TAG = "BluetoothServiceImpl"; private CardStep step; @Override public void startService() { isTransmissionEnabled = false; btAdapter = BluetoothAdapter.getDefaultAdapter(); event = new MutableLiveData<>(); enableBluetooth(); // registerBluetoothManager(); setBluetoothScanCallBack(); startBTScanForACRCard(); } private void startBTScanForACRCard() { final BluetoothManager bluetoothManager = ActivityLocator.getInstance().getBluetoothManager(); mBluetoothAdapter = bluetoothManager.getAdapter(); boolean isBTAdaptorEnabled=mBluetoothAdapter.enable(); if(isBTAdaptorEnabled){ scanLeDevice(isBTAdaptorEnabled,mBluetoothAdapter); } } private synchronized void scanLeDevice(final boolean enable,BluetoothAdapter mBluetoothAdapter) { mBluetoothAdapter.startLeScan(mLeScanCallback); } public void setBluetoothScanCallBack() { /* Initialize BluetoothReaderGattCallback. */ blueToothReaderCallBack = new BluetoothReaderGattCallback(); blueToothReaderCallBack.setOnConnectionStateChangeListener( new BluetoothReaderGattCallback.OnConnectionStateChangeListener() { @Override public void onConnectionStateChange(final BluetoothGatt gatt, final int state, final int newState) { if (mBluetoothReaderManager != null) { mBluetoothReaderManager.detectReader( gatt, blueToothReaderCallBack); if (state == BluetoothGatt.GATT_SUCCESS) { if (newState == BluetoothReader.STATE_CONNECTED) { System.out.println("----> here we are:Ghattt success connected" ); mBluetoothReaderManager.detectReader(gatt,blueToothReaderCallBack); }else { System.out.println("----> here we are:Ghattt NOOOOOOOOO uccess connected" ); } } System.out.println("----> here we are"); } } }); registerBluetoothManager(); } private void authenticateDevice() { Log.d(TAG, "Authenticating device"); if (null != mBluetoothReader) { mBluetoothGatt.getDevice().createBond(); //Hex String for authentication String hexString = null; try { hexString = Utils.toHexString((authenticationString).getBytes(Charset.forName("UTF-8"))); } catch (Exception exception) { Log.d(TAG, "Exception while converting string Please check authentication key", exception); } /* Get Hexa bytes of authentication String */ byte masterKey[] = Utils.getEditTextinHexBytes(hexString); if (!isDeviceAuthenticated) { Log.d(TAG, "Authenticating device now............."); isDeviceAuthenticated = mBluetoothReader.authenticate(masterKey); Log.d(TAG, "Authenticating device result............."+isDeviceAuthenticated); } } } private void pollDevice() { if (true == isDeviceAuthenticated && false == isTransmissionEnabled) { if (null != mBluetoothReader) { Log.d(TAG, "Polling started"); isTransmissionEnabled = mBluetoothReader.transmitEscapeCommand(AUTO_POLLING_START); } else { Log.d(TAG, "Polling could not be done as bluetooth is not workin properly"); } } } private void enableBluetooth() { if (btAdapter == null) { Log.d(TAG, "Phone does not support Bluetooth hence exitting"); System.exit(0); } ActivityLocator.getInstance().getAppActivity().requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1); } // private void scanAndFindDevice() { // // if (null != btAdapter && btAdapter.isEnabled()) { // // bluetoothLeScanner = btAdapter.getBluetoothLeScanner(); // bluetoothLeScanner.startScan(leScanCallback); // // } else { // // Log.d(TAG, "Bluetooth not enabled"); // } // // } private void registerBluetoothManager() { mBluetoothReaderManager = new BluetoothReaderManager(); step = INIT; /* Register BluetoothReaderManager's listeners */ mBluetoothReaderManager .setOnReaderDetectionListener(new BluetoothReaderManager.OnReaderDetectionListener() { @Override public void onReaderDetection(BluetoothReader reader) { if(reader instanceof Acr1255uj1Reader) { mBluetoothReader = reader; setDeviceAuthenticationListener(); activateReader(reader); authenticateDevice(); pollDevice(); System.out.println("This is our reader ................."); } System.out.println("Reader detected"); //authenticateDevice(); mBluetoothReader.setOnCardStatusChangeListener(new BluetoothReader.OnCardStatusChangeListener() { @Override public void onCardStatusChange(BluetoothReader bluetoothReader, int i) { if (null != mBluetoothReader) { if (i == BluetoothReader.CARD_STATUS_PRESENT) { Log.d(TAG, "Card active"); mBluetoothReader.transmitApdu(SELECT_MASTER_FILE_APDU_COMMAND); step = SELECT_AID; } else if (i == BluetoothReader.CARD_STATUS_ABSENT) { Log.d(TAG, "Card is inactive"); } } } }); mBluetoothReader.setOnResponseApduAvailableListener(new BluetoothReader.OnResponseApduAvailableListener() { @Override public void onResponseApduAvailable(BluetoothReader bluetoothReader, byte[] bytes, int i) { Log.d(TAG, "Step is " + step); String hexString = Utils.toHexString(bytes); // validation of the value if (Arrays.asList(SELECT_AID, SELECT_FILE, READ).contains(step)) { if (hexString.trim().equalsIgnoreCase("91 00") || (hexString.trim().equalsIgnoreCase("90 00"))) { Log.d(TAG, "correct answer, we continue"); } else { Log.d(TAG, "bad answer, we stop"); event.postValue(CARD_NOT_RECOGNIZED); step = INIT; return; } } switch (step) { case INIT: case SELECT_MASTER: break; case SELECT_AID: Log.d(TAG, "Card data found sending command to read"); mBluetoothReader.transmitApdu(SELECT_AID_APDU_COMMAND); step = SELECT_FILE; break; case SELECT_FILE: mBluetoothReader.transmitApdu(SELECT_CARD_ID_FILE_APDU_COMMAND); step = READ; break; case READ: mBluetoothReader.transmitApdu(READ_FILE_BUFFER_APDU_COMMAND); step = CardStep.CONVERT_READ_DATA; break; case CONVERT_READ_DATA: String data = bytesToHex(bytes); String memberId=Utils.hexToAscii(data); event.postValue(memberId); } } }); } }); } /* Start the process to enable the reader's notifications. */ private void activateReader(BluetoothReader reader) { if (reader == null) { return; } System.out.println("Enabling.........................><<<<<<<<<<<<<<<<<<<,"); if (reader instanceof Acr3901us1Reader) { /* Start pairing to the reader. */ ((Acr3901us1Reader) mBluetoothReader).startBonding(); } else if (mBluetoothReader instanceof Acr1255uj1Reader) { /* Enable notification. */ boolean isNotificationEnabled= mBluetoothReader.enableNotification(true); System.out.println("Enabling..........Notify...............><<<<<<<<<<<<<<<<<<<,"+isNotificationEnabled); //authenticateDevice(); } } private boolean connectReader() { BluetoothManager bluetoothManager = ActivityLocator.getInstance().getBluetoothManager(); if (null == bluetoothManager) { connectionState = (BluetoothReader.STATE_DISCONNECTED); return false; } BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); if (null == bluetoothAdapter) { connectionState = (BluetoothReader.STATE_DISCONNECTED); return false; } /* Clear old GATT */ if (null != mBluetoothGatt) { Log.d(TAG, "CLearing old Gatt"); mBluetoothGatt.disconnect(); mBluetoothGatt.close(); mBluetoothGatt = null; } /* Create a new connection. */ final BluetoothDevice device = bluetoothAdapter .getRemoteDevice(mBluetoothDevice.getAddress()); if (device == null) { Log.d(TAG, "Device not found"); return false; } /* Connect to GATT server. */ connectionState = (BluetoothReader.STATE_CONNECTING); mBluetoothGatt = device.connectGatt(ActivityLocator.getInstance().getAppActivity(), false, blueToothReaderCallBack); return true; } @Override public void stopPolling() { if (null != mBluetoothReader) { Log.d(TAG, "Device polling started"); //isTransmissionEnabled = mBluetoothReader.transmitEscapeCommand(AUTO_POLLING_STOP); } else { Log.d(TAG, "Device cannot poll"); } } @Override public void closeConnection() { // if(null!=mBluetoothGatt) { // mBluetoothGatt.disconnect(); // mBluetoothGatt.close(); // mBluetoothGatt = null; // } } @Override public MutableLiveData<String> getCardEvents() { return event; } public enum CardStep { INIT, SELECT_MASTER, SELECT_AID, SELECT_FILE, READ, CONVERT_READ_DATA, } public void setDeviceAuthenticationListener(){ mBluetoothReader.setOnAuthenticationCompleteListener(new BluetoothReader.OnAuthenticationCompleteListener() { @Override public void onAuthenticationComplete(BluetoothReader bluetoothReader, int i) { System.out.println("Authentication completed..........."); isDeviceAuthenticated = true; //pollDevice(); } }); } } Here is the interface for above class:
package abc;
import android.arch.lifecycle.MutableLiveData;
public interface BluetoothService {
/**
* search for the bluetooth device,
* Note that if bluetooth device is found, no need to disconnect
* and then start polling for card
*/
public void startService();public MutableLiveData<String> getCardEvents();
public void stopPolling();
public void closeConnection();
}
here is the utility file
/*
* Copyright (C) 2014 Advanced Card Systems Ltd. All Rights Reserved.
*
* This software is the confidential and proprietary information of Advanced
* Card Systems Ltd. (“Confidential Information”). You shall not disclose such
* Confidential Information and shall use it only in accordance with the terms
* of the license agreement you entered into with ACS.
*/package abc;
import android.util.Log;
import java.util.Locale;
/**
* The
*Utils
class contains static methods which operate on arrays and
* string.
*
* @author Gary Wong
* @version 1.0, 4 Jun 2014
*/
class Utils {public static final String TAG="Utils";
/**
* Creates a hexadecimalString
representation of the
*byte[]
passed. Each element is converted to a
*String
via the {@link Integer#toHexString(int)} and
* separated by" "
. If the array isnull
, then
*""
is returned.
*
* @param array
* thebyte
array to convert.
* @return theString
representation ofarray
in
* hexadecimal.
*/
public static String toHexString(byte[] array) {String bufferString = "";
if (array != null) {
for (int i = 0; i < array.length; i++) {
String hexChar = Integer.toHexString(array[i] & 0xFF);
if (hexChar.length() == 1) {
hexChar = "0" + hexChar;
}
bufferString += hexChar.toUpperCase(Locale.US) + " ";
}
}
return bufferString;
}private static boolean isHexNumber(byte value) {
if (!(value >= '0' && value <= '9') && !(value >= 'A' && value <= 'F')
&& !(value >= 'a' && value <= 'f')) {
return false;
}
return true;
}/**
* Checks a hexadecimalString
that is contained hexadecimal
* value or not.
*
* @param string
* the string to check.
* @returntrue
thestring
contains Hex number
* only,false
otherwise.
* @throws NullPointerException
* ifstring == null
.
*/
public static boolean isHexNumber(String string) {
if (string == null)
throw new NullPointerException("string was null");boolean flag = true;
for (int i = 0; i < string.length(); i++) {
char cc = string.charAt(i);
if (!isHexNumber((byte) cc)) {
flag = false;
break;
}
}
return flag;
}private static byte uniteBytes(byte src0, byte src1) {
byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))
.byteValue();
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))
.byteValue();
byte ret = (byte) (_b0 ^ _b1);
return ret;
}/**
* Creates abyte[]
representation of the hexadecimal
*String
passed.
*
* @param string
* the hexadecimal string to be converted.
* @return thearray
representation ofString
.
* @throws IllegalArgumentException
* ifstring
length is not in even number.
* @throws NullPointerException
* ifstring == null
.
* @throws NumberFormatException
* ifstring
cannot be parsed as a byte value.
*/
public static byte[] hexString2Bytes(String string) {
if (string == null)
throw new NullPointerException("string was null");int len = string.length();
if (len == 0)
return new byte[0];
if (len % 2 == 1)
throw new IllegalArgumentException(
"string length should be an even number");byte[] ret = new byte[len / 2];
byte[] tmp = string.getBytes();for (int i = 0; i < len; i += 2) {
if (!isHexNumber(tmp[i]) || !isHexNumber(tmp[i + 1])) {
throw new NumberFormatException(
"string contained invalid value");
}
ret[i / 2] = uniteBytes(tmp[i], tmp[i + 1]);
}System.out.println("Return is null"+ret);
return ret;
}/**
* Creates abyte[]
representation of the hexadecimal
*String
in the EditText control.
*
* the EditText control which contains hexadecimal string to be
* converted.
* @return thearray
representation ofString
in
* the EditText control.null
if the string format is
* not correct.
*/
public static byte[] getEditTextinHexBytes(String key) {String rawdata = key;
if (rawdata == null || rawdata.isEmpty()) {
return null;
}String command = key.replace(" ", "").replace("\n", "");
return hexString2Bytes(command);
}public static String hexToAscii(String hexStr) {
StringBuilder output = new StringBuilder("");for (int i = 0; i < hexStr.length()-4; i += 2) {
String str = hexStr.substring(i, i + 2);try {
output.append((char) Integer.parseInt(str, 16));
}catch(NumberFormatException exception){
Log.e(TAG,"Error while converting number",exception);
}
}return output.toString();
}
}This code automatically scan for acs and makes a connection but fails to authenticate . I am unable to figure why it fails at that step.
Using minimum sdk version 23 and maximum, target 28
September 7, 2018 at 7:03 am #63969Hi,
I would recommend reaching out to ACS for support or you could try StackOverflow. Another general suggestion is that you should only post the relevant parts of the code so your issue can be more meaningfully understood without having to run the code / know every moving part.
If you are looking for one of our engineers to help you on your problem one-on-one and try debugging it for you, you could consider Flomio Service Hours for bespoke development work.
I hope you find a solution to your issue.
Kind Regards,
Scott- This reply was modified 6 years, 3 months ago by Scott.
-
AuthorPosts
You must be logged in to reply to this topic.