用java将数据写入nfc智能卡

gg58donl  于 2021-07-03  发布在  Java
关注(0)|答案(3)|浏览(642)

我被要求编写一个简单的程序来读取和写入数据从智能卡(mifare)使用nfc,但我卡住了。
我必须得到uid(到目前为止还不错),写一些数据从数据库中的一些块的卡(没有办法)。
我必须使用java和acr122阅读器。我写的代码仍然需要改进和重构一点,这主要是一个草案,但我想首先做的任务,然后修复一切。我在网上看到了我能找到的东西,但我还是错过了一些东西。到目前为止,我得到的(主要是整理一些代码)是:

package testnfc;
    import javax.smartcardio.*;
    import java.util.Arrays;
    import java.util.List;
    import static testnfc.Helpers.*;
    import java.nio.ByteBuffer;

    public class TestNFC {

    `enter code here`public static void main(String[] args) throws CardException {
    // get and print any card readers (terminals)
    TerminalFactory factory = TerminalFactory.getDefault();
    List<CardTerminal> terminals=null;
    try{

         terminals = factory.terminals().list();
        System.out.println("Terminals: " + terminals);

         // work with the first terminal
        CardTerminal term = terminals.get(0);

        // connect with the card. Throw an exception if a card isn't present 
        // the * means use any available protocol
        try{

            Card card = term.connect("*");
            System.out.println("card: " + card);
            //Got the card
            CardChannel channel = card.getBasicChannel();

            byte[] instruction = hexToBytes("FF CA 00 00 00");
            CommandAPDU getUID = new CommandAPDU(instruction);

            ResponseAPDU response = channel.transmit(getUID);
            String uid = bytesToPrettyHex(response.getData());
            String status = bytesToPrettyHex(new byte[] {(byte)response.getSW1(), (byte)response.getSW2()});
            System.out.printf("UID: %s\tResponse: %s\n", uid, status);  //Status = 90 -> Success, 63 -> Fail

            //Up to this point it works, I can get the terminal and the UID of the card. Now I am trying to write datas in the card
            byte[] dati;
            dati=new byte[4];
            dati[0]=(byte)12;
            dati[1]=(byte)12;
            dati[2]=(byte)12;
            writeData(card, (byte)1, dati);
        }
        catch(CardNotPresentException exc){
            System.out.println("Card not found!");
        }
    }
    catch(CardException ex){
        System.out.println("Terminal not found!");
    }

}

public static void writeData(Card c, byte block, byte[] data)
        throws CardException {
    byte cla = (byte) 0xFF;
    byte ins = (byte) 0xD6;
    byte p1 = (byte) 0x00;
    byte p2 = block;
    byte le = 0x10;
    byte[] params = new byte[21];
    for (int i = 0; i < 21; i++) {
        params[i] = 0x20;
    }
    params[0] = cla;
    params[1] = ins;
    params[2] = p1;
    params[3] = p2;
    params[4] = le;
    for (int i = 0; i < data.length; i++) {
        params[5 + i] = data[i];
    }

    System.out.println("step1");

    CardChannel channel = c.getBasicChannel();
    CommandAPDU command = new CommandAPDU(params);

    System.out.println("Step2");

    ResponseAPDU response = channel.transmit(command);
    System.out.println("Step3, response ->"+ response);
    validateResponse(response);
    System.out.println("Step4");
}

private static void validateResponse(ResponseAPDU response)
        throws CardException {
        int respSW1=0;
        int respSW2=0;
        respSW1 = response.getSW1();
        respSW2 = response.getSW2();
        System.out.println("SW1 ->"+respSW1 + ", SW2 ->"+ respSW2);
        if (respSW1 != 144) {
            throw new CardException("Autentication Problem?");
        }
    }
}

我得到的结果是

Terminals: [PC/SC terminal ACS ACR122 0]
card: PC/SC card in ACS ACR122 0, protocol T=1, state OK
UID: EA:54:42:AA    Response: 90:00
step 1
step2
step3, response ->ResponseAPDU: 2 bytes, SW=6300
SW1 ->99, SW2 ->0
Terminal not found

我能读卡片的uid,但不能写;该卡本身是可以的,使用nfc工具的桌面我可以访问和写。我找了一些文件,但我不能解决问题,我不能正确地学习没有一些例子。我不明白为什么会得到6300代码:从我发现的情况来看,这意味着“非易失性内存的状态发生了变化”,但如果我用nfc工具检查,我找不到任何区别。
我需要改变什么才能从卡片上读写?

w51jfk4q

w51jfk4q1#

一旦你知道这是什么卡,你就可以查看数据表https://www.nxp.com/docs/en/data-sheet/mf1s70yyx_v1.pdf 查看它的内存是如何构造的以及它支持哪些命令。
然后,如何从读取器的picc命令将它们 Package 到伪apdu中(第5节)https://www.acs.com.hk/download-manual/419/api-acr122u-2.04.pdf )

jaql4c8m

jaql4c8m2#

我解决了这个问题。这是我的代码(一个概念证明,只是为了说明它是如何工作的)

package testnfc;

import javax.smartcardio.*;
import java.util.List;
import java.io.*;
import static testnfc.Helpers.*;
import java.lang.Integer;

import java.nio.charset.StandardCharsets;

public class TestNFC {
    public static void main(String[] args) throws CardException {
        // get and print any card readers (terminals)
        TerminalFactory factory = TerminalFactory.getDefault();
        List<CardTerminal> terminals=null;
        try{

             terminals = factory.terminals().list();
            System.out.println("Terminals: " + terminals);

             // work with the first terminal
            CardTerminal term = terminals.get(0);

            // connect with the card. Throw an exception if a card isn't present 
            // the * means use any available protocol
            try{
                Card card = term.connect("*");
                System.out.println("card: " + card);

                // Once we have the card, we can open a communication channel for sending commands and getting responses
                CardChannel channel = card.getBasicChannel();

                byte[] dati;
                String valori=[data to be written];
                dati=valori.getBytes();
                System.out.println("valori ->" + valori + ", dati ->"+dati);

                //Not used right now
                //loadAuthentication(card);

                byte addr = 0x06;

                authenticate(card, addr);

                writeData(card, addr, dati);

                readData(card, addr); 

            }
            catch(CardNotPresentException exc){
                System.out.println("Card not found!");
                stampTrace(exc);
            }
        }
        catch(CardException ex){
            System.out.println("Terminal not found");
            stampTrace(ex);
        }

    }

    /*
    * Prints stack trace (for debug)
    */
    public static String stampTrace(Exception ex){
        StringWriter errors = new StringWriter();
        ex.printStackTrace(new PrintWriter (errors));

        String ret=errors.toString();
        System.out.println(ret);
        return ret;
    }

    /*
    * Funzioni per convertire in byte, per passare i parametri alle funzionin;
    */
    public byte fromIntToByte(int i){
        Integer v=i;
        byte b=v.byteValue();
        return b;
    }
    public byte[] fromStringToByte(String s){
        byte[] byteArray=s.getBytes();
        return byteArray;
    }

    public static void authenticate(Card c, byte addr) throws CardException {
        byte cls = (byte) 0xFF;
        byte ins = (byte) 0x86;
        byte p1 = (byte) 0x00;
        byte p2 = (byte) 0x00; 
        byte lc = (byte) 0x05;

        byte[] params = new byte[] { cls, ins, p1, p2, lc, 0x01, 0x00, addr, 0x60, 0x00 };// 0x60 -> Key A per auth, 0x61 -> key B

        CardChannel channel = c.getBasicChannel();
        CommandAPDU command = new CommandAPDU(params);
        System.out.println("Tryint to authenticate.");
        ResponseAPDU response = channel.transmit(command);
        validateResponse(response);
        System.out.println("Autenticated!");
    }

    /*
    * Load new auth key in the card. Not used at the moment
    */
    public static void loadAuthentication(Card c) throws CardException {
        byte cla = (byte) 0xFF;
        byte ins = (byte) 0x82;
        byte p1 = (byte) 0x00; 
        byte p2 = (byte) 0x01;
        byte lc = (byte) 0x06;
        byte key = (byte) 0xFF;

        byte[] params = new byte[] { cla, ins, p1, p2, lc, key, key, key,
                key, key, key };
        CardChannel channel = c.getBasicChannel();
        CommandAPDU command = new CommandAPDU(params);
        ResponseAPDU response = channel.transmit(command);
        validateResponse(response);
        System.out.println("Auth OK!");
    }

    /*
    * Reads from card
    * @param c card to be read
    * @param block  block I want to read
    */
    public static byte[] readData(Card c, byte block) throws CardException {
        byte cla = (byte) 0xFF;
        byte ins = (byte) 0xB0;
        byte p1 = (byte) 0x00;
        byte p2 = block;
        byte le = (byte) 0x10;

        byte[] params = new byte[] { cla, ins, p1, p2, le };
        CardChannel channel = c.getBasicChannel();
        CommandAPDU command = new CommandAPDU(params);
        System.out.println("Trying to read");
        ResponseAPDU response = channel.transmit(command);
        System.out.println("Read, response ->"+response);

        String ret=new String(response.getData(), StandardCharsets.UTF_8);
        System.out.println("getData ->"+response.getData()+", string ->"+ret);
        validateResponse(response);
        return response.getData();
    }   

    /*
    * Writes data into card
    * @param c      card to be written
    * @param block  block I want to write in
    * @param data   what I want to write
    */
    public static void writeData(Card c, byte block, byte[] data)
            throws CardException {
        byte cla = (byte) 0xFF; 
        byte ins = (byte) 0xD6; 
        byte p1 = (byte) 0x00;
        byte p2 = (byte) block;
        byte le = 0x10;
        byte[] params = new byte[21];
        for (int i = 0; i < 21; i++) {
            params[i] = 0x20;
        }
        params[0] = cla;
        params[1] = ins;
        params[2] = p1;
        params[3] = p2;
        params[4] = le;
        for (int i = 0; i < data.length; i++) {
            params[5 + i] = data[i];
            System.out.println("i ->"+ String.valueOf(i)+", dato ->"+params[5+i]);
        }

        CardChannel channel = c.getBasicChannel();
        CommandAPDU command = new CommandAPDU(params);

        ResponseAPDU response = channel.transmit(command);
        System.out.println("step3, response ->"+ response);

        validateResponse(response);
        System.out.println("step4");
    }

    /*
    * Checks the response 
    */
    private static void validateResponse(ResponseAPDU response)
            throws CardException {
        int respSW1=0;
        int respSW2=0;
        respSW1 = response.getSW1();
        respSW2 = response.getSW2();
        System.out.println("SW1 ->"+respSW1 + ", SW2 ->"+ respSW2);
        //TODO Fix message!!
        if (respSW1 != 144) {
            throw new CardException("Autentication Problem?");
        }
    }
}
3mpgtkmj

3mpgtkmj3#

根据nfc工具,它是mifare经典的1kb

相关问题