Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 7

1 Card Type

1.1 M1 card is the most famous and most widely used non-contact card (such as campus card, bus card,
etc.) of NXP (Philips) Company.。

1.2 The CPU card refers to a smart card with 8/16/32-bit CPU and logic processing capability.

2 Support NFC technology code

2.1 NFC supports 3 operating modes:

1. Reader mode;

2. Simulation Card Mode;

3. Point-to-point mode;

2.2 NFC technology code embedding

Reference to:http://blog.csdn.net/u011115385/article/details/50401272

2.3 NFC supported data formats

Reference to:http://www.cnblogs.com/jyycnblogs/p/5077609.html

3 M1 Card Read and Write

3.1 The storage space is displayed as a sector

3.2 Read M1 card amount

1 Get operation object MifareClassic

MifareClassic mfc = MifareClassic.get(tag);

2 Establish a connection with the card

mfc.connect();

3 Decrypted sector

//Reading data keyA

auth = mfc.authenticateSectorWithKeyA(sector,MERCHANT_KEY);

MERCHANT_KEY:The key set when the card is authorized, obtained by sending a


request, getMerchantKey()Get Merchant key

4 Calculate the current block number (0~63) to get the entire data of the current block
byte[] data = mfc.readBlock(currBlock);//get currBlock block data

5 Converted to a hexadecimal string, according to "Linux machine standard card format 170410" to
obtain the required data

6 Abnormal or failed, prompting the user to operate again

3.3 Write data to M1 card

1 Get operation object MifareClassic

MifareClassic mfc = MifareClassic.get(tag);

2 Establish a connection with the card

mfc.connect();

3 Decrypted sector

//write data use keyB

auth = mfc. authenticateSectorWithKeyB (sector,MERCHANT_KEY);

MERCHANT_KEY:The key set when the card is authorized, obtained by sending a


request, getMerchantKey() get merchant key

4 Calculate the current block number (0~63) to get the entire data of the current block

byte[] data = mfc.readBlock(currBlock);//get currBlock block data

5 Wallet verify

1)Verify Address

2)Check whether the left and right wallets are equal

3)Verify whether left (right) wallet inversion and inversion wallet are equal

4)Whether the left (right) wallet and the backup area wallet are equal

5)The above four kinds of comparisons take exception to the data in the backup area
6 Restructure wallet data

String data = checkMoney(tag);//read wallet balance


if (data != null) {
Log.e("TAG", "the data before writing: " + data);
String replace = reversal(fillZero(wrteData, 8));//fill zero
Log.e("TAG", " after Zero filling,the replacement data:" + replace);
String newStr = obtainNewByte(data, 0, replace);// New write data String
Log.e("TAG", "new data: " + newStr);
7 write into data

writeTag(tag, 4, 1, hexStr2ByteArray(newStr));//write operation


writeTag(tag, 4, 2, hexStr2ByteArray(newStr));//backup area
8 Abnormal or failed, prompting the user to operate again

4 CPU Card read and write

4.1 Storage space is displayed as MF file directory

4.2 read balance

1 Get operation object

IsoDep isodep = IsoDep.get(tag);

2 Establish contact with the card

isodep.connect();

3 Reading the directory, returning the last 4 digits of 9000 for success, or failure

String mfHxs = "00A40000023F01";


byte[] mfRsp = isodep.transceive(HexStringToByteArray(mfHxs));

4 Reading balance, returning the last 4 digits of 9000 for success, or failure
byte[] balance = {(byte) 0x80, (byte) 0x5C, 0x00, 0x02, 0x04};
byte[] balanceRsp = isodep.transceive(balance);

5 All the code for the card reading process

//CPU Card reading balance


public String readCPU(Tag tag) {
Log.i(TAG, "New tag readCPU");
try {
IsoDep isodep = IsoDep.get(tag);
isodep.connect();
// Read CPU card Balance
// Read MF Directory
String mfHxs = "00A40000023F01";
byte[] mfRsp = isodep.transceive(HexStringToByteArray(mfHxs));
Log.d(TAG, "mfRsp:" + ByteArrayToHexString(mfRsp));
//read balance
byte[] balance = {(byte) 0x80, (byte) 0x5C, 0x00, 0x02, 0x04};
byte[] balanceRsp = isodep.transceive(balance);
Log.d(TAG, "balanceRsp:" + ByteArrayToHexString(balanceRsp));
if (balanceRsp != null && balanceRsp.length > 4) {
int cash = byteToInt(balanceRsp, 4);
float ba = cash / 100.0f;
Log.e(TAG, "Balance:" + ba);
}
isodep.close();
} catch (IOException e) {
Log.e(TAG, "Error communicating with card: " + e.toString());
}
return null;
}

4.3 Write amount(Redeposit command)

1 Get operation object

IsoDep isodep = IsoDep.get(tag);

2 get contact with card

isodep.connect();

3 Reading the directory, returning the last 4 digits of 9000 for success, or failure

/**
* Read MF directory
* CLA 80; INS 50;P1 00;P2 02;Lc 02(The length of the file name);Data 3F(file name);Le 00
* First read the directory, the next initialization of the Redeposit command operation can be
successful, otherwise 6985
*/
String mfHxs = "00A40000023F01";
byte[] mfRsp = isodep.transceive(HexStringToByteArray(mfHxs));
4 Redeposit initialization operation, returning the last 4 digits of 9000 for success, or failure
/**
* Initialization Redeposit command
* CLA 80; INS 50;P1 00;P2 02;Lc 0B;Data such as ;le 10
* Key index 1 byte; transaction amount 4 bytes; terminal number 6 bytes
*/
// Key Identifier: The key identifier in the IC card
String keyLogo = "01";
// Initialization Redeposit command
// String cmd1 = "805000020B"+"01"+"00000064"+"000013000000"+"10";
String cmd1 = "805000020B" + keyLogo + transationMenoy + terminalNum + "10";
Log.d(TAG, "cmd1:" + cmd1);
// Initialize the Redeposit and return the result
byte[] res1 = isodep.transceive(HexStringToByteArray(cmd1));
5 Redeposit command

1)Calculate the redeposit key: To realize at package “so” file

2)Calculate the process key: To realize at package “so” file

3)Calculate Mac Value: To realize at package “so” file

// Process key original data(4-byte random number + 2-byte electronic passbook or Wallet
online transaction number +8000)
String str1 = "F09AF5BD00028000";
//MAC original data(4-byte transaction amount + 1 byte transaction type identifier + 6-
byte terminal number + 4 bytes host transaction date + 3 bytes host transaction time)
String str2 = "000000640200001300000020170616160447";
// Authorization key
String str3 = "1122334455667788";
//snake: fixed value
String str4 = "26911300";
// Card physical card number
String str5 = "8D7FC6A5";
//call “so”file to get MAC
String mac = NfcUtil.add(HexStringToByteArray(str1), HexStringToByteArray(str2),
HexStringToByteArray(str3), HexStringToByteArray(str4), HexStringToByteArray(str5));

4)Execute the redeposit command and return the result. The last 4 digits of 9000
represent success, or fail.

/**
* redeposit command
* CLA 80; INS 52;P1 00;P2 02;Lc 0B;Data such as;Le 04
* Transaction date (host) 4 bytes; transaction time (host) 3 bytes; MAC2 4 bytes
*/
str5 = ByteArrayToHexString(tag.getId());
String mac = getMac(res1);
String cmd2 = "805200000B" + getCurrentData() + mac.substring(0, 8) + "04";
Log.e("TAG", "CMD2==" + cmd2);
byte[] res2 = isodep.transceive(HexStringToByteArray(cmd2));

6 Write the amount data all code

//CPU card write amount


private void writeCPU(Tag tag) {
IsoDep isodep = IsoDep.get(tag);
try {
isodep.connect();
/**
* Read MF directory
* CLA 80; INS 50;P1 00;P2 02;Lc 02(The length of the file name);Data 3F(file
name);Le 00
* First read the directory, the next initialization of the Redeposit command operation
can be successful, otherwise 6985
*/
String mfHxs = "00A40000023F01";
byte[] mfRsp = isodep.transceive(HexStringToByteArray(mfHxs));
Log.d(TAG, "mfRsp:" + ByteArrayToHexString(mfRsp));
/**
* Initialization Redeposit command
* CLA 80; INS 50;P1 00;P2 02;Lc 0B;Data 如下;le 10
* Key index 1 byte; transaction amount 4 bytes; terminal number 6 bytes
*/
// Key Identifier: The key identifier in the IC card
String keyLogo = "01";
// Initialization redeposit command
// String cmd1 = "805000020B"+"01"+"00000064"+"000013000000"+"10";
String cmd1 = "805000020B" + keyLogo + transationMenoy + terminalNum + "10";
Log.d(TAG, "cmd1:" + cmd1);
// Initialize the Redeposit and return the result
byte[] res1 = isodep.transceive(HexStringToByteArray(cmd1));
Log.d(TAG, "res1:" + ByteArrayToHexString(res1));
/**
* Redeposit Command
* CLA 80; INS 52;P1 00;P2 02;Lc 0B;Data such as;Le 04
* Transaction date (host) 4 bytes; transaction time (host) 3 bytes; MAC2 4 bytes
*/
str5 = ByteArrayToHexString(tag.getId());
String mac = getMac(res1);
String cmd2 = "805200000B" + getCurrentData() + mac.substring(0, 8) + "04";
Log.e("TAG", "CMD2==" + cmd2);
byte[] res2 = isodep.transceive(HexStringToByteArray(cmd2));
Log.d(TAG, "res2:" + ByteArrayToHexString(res2));
String res3 = ByteArrayToHexString(res2);
String res4 = res3.substring(res3.length()-4,res3.length());
if("9000".equals(res4)){
writeSucess();
}else {
Toast.makeText(this, " Failed to write the card. Please re-apply for reading ",
Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
// e.printStackTrace();
Toast.makeText(this, " Failed to write the card. Please re-apply for reading ",
Toast.LENGTH_LONG).show();
}
}

5 Remark

1 Realize code type:ReadNfcActivity

2 Algorithm dependent library:libnative-lib.so

Call method: kl.enjoy.com.klapp.util. NfcUtil.add(…)

3 M1 card reference standard file: Linux machine standard card format 170410.xlsx

4 CPU card storage method: Shenzhen Cardlan Technology CPU card demand 20170510.doc
Enclose Command Reference Page 89: New FMCOS 2.0 User Manual.pdf

Calculate the MAC encapsulation file: libnative-lib.so

Calculate the MAC c source code: cpp folder

Jni call file: NfcUtil.java

5 Call C code use cmake Technology

6 Difficulties

6.1 Basic type correspondence between JAVA, JNI, and C

Such as string:JAVA[String]、JNI[jstring]、C[char*]

6.2 Basic type conversion between JAVA, JNI, and C

//jbytearray transfter to char[]


jbyte* bBuffer1 = (*env)->GetByteArrayElements(env,jBuffer1,0);
// c converts char[] to a hexadecimal string,
CharStr2HexStr(buff3, sizeof(buff3),pszHexStr);
// Jni returns java available string
return (*env)->NewStringUTF(env,pszHexStr);

6.3 Method void *memset(void *s,int c,size_t n)

Effect: Set the value of the first n bytes of the opened memory space s to the value c.

memset(buff1, 0, sizeof(buff1)*2);// Initialization, buff1 is hexadecimal, so the third parameter


needs to be multiplied by 2

You might also like