美文网首页
Android NFC(二)M1卡电子钱包功能

Android NFC(二)M1卡电子钱包功能

作者: ccDown | 来源:发表于2019-03-15 18:06 被阅读0次

    M1任意可写块都可实现电子钱包的功能。本质其实就是按照一定的数据格式来对块值进行初始化、加值、减值。电子钱包的数据结构下图示例:


    钱包结构.png

    比如要将第5扇区的第0块作为电子钱包的存储位置,就要先将该块的数据格式化为上述形式。

    钱包正值的意思是将10进制余额转为16进制数然后按字节逆序排列
    钱包反值的意思是将钱包正值取反
    地址的意思是当前的块值序号,如20块填14(10进制的20转为16进制的14)

    如电子钱包余额为0,该块值数据为:00000000ffffffff0000000014eb14eb
    当电子钱包余额为1时,该块值数据为:01000000feffffff0100000018e718e7
    当电子钱包余额为100时,该块值数据为:640000009bffffff6400000018e718e7

    余额的加值减值都要转换为10进制数然后进行计算之后再重新组装为16进制数据

    电子钱包块值初始化:

      /**
     * 初始化块值
     *
     * @param blockIndex
     * @param data
     * @return
     */
    public static byte[] m1FormatBlock(int blockIndex, int data) {
    
        //region 系统的方法
        //construct value block of value zero; "address" byte is set to 0 in this example 
    
        //byte[] zeroValue = {0, 0, 0, 0, 255, 255, 255, 255, 0, 0, 0, 0, 0, 255, 0, 255 }; 
        //mifare.writeBlock(blockIndex, zeroValue); 
    
        //end region
    
        byte[] result = new byte[16];
    
        //钱包正值
        byte[] temps = new byte[4];
        //钱包反值
        byte[] noTemps = new byte[4];
        
        //4个字节的钱包值  反序排列 如1000 转为16进制00 00 03 e8  反序为 e8 03 00 00
        for (int i = 0; i < 4; i++) {
            int temp = data >> 8 * i;
            temps[i] = (byte) (temp & 0xFF);
    
            int noTemp = (~data) >> 8 * i;
            noTemps[i] = (byte) (noTemp & 0xFF);
        }
    
        //钱包1-4字节 正值 
        //钱包5-8字节 反值 
        //钱包9-12字节 正值 
        for (int i = 0; i < 12; i++) {
            if (i<4){
                result[i] = temps[i%4];
            } else if (i < 8){
                result[i] = noTemps[i%4];
            } else if (i < 12){
                result[i] = temps[i%4];
            }
        }
    
        /**
         *  钱包地址 
         *  12字节 16进制正值 
         *  13字节 16进制反值
         *  14字节 16进制正值 
         *  15字节 16进制反值 
         */
        result[12] = (byte) (blockIndex & 0xFF);
        result[13] = (byte) ~(blockIndex & 0xFF);
        result[14] = (byte) (blockIndex & 0xFF);
        result[15] = (byte) ~(blockIndex & 0xFF);
        return result;
    }
    

    电子钱包余额加(将余额转换为十进制数进行加操作计算出结果,然后再将结果转换为16进制倒序写入到卡中):

        /**
     * 加值
     */
    private void m1incvalue(int block,int value) {
        // increase the value block by some amount 
        mifare.increment(blockIndex, value); 
        // result is stored in scratch register inside tag; now write result to block 
        mifare.transfer(blockIndex); 
    }
    

    电子钱包余额减(将余额转换为十进制数进行减操作计算出结果,然后再将结果转换为16进制倒序写入到卡中):

    /**
     * 减值
     */
    private void m1decvalue(int block,int value) {
         // decrease the value block by some amount 
        mifare.decrement(blockIndex, value); 
        // result is stored in scratch register inside tag; now write result to block 
        mifare.transfer(blockIndex); 
    }
    

    根据块值获取余额(取前4字节数据):

     /**
     * 根据值块获取值数据
     *
     * @param block
     * @return
     */
    public static int resolveBlockValue(final byte[] block) {
        byte[] blockValue = new byte[4];
        if (block != null && block.length == 16) {
            //获取前四位值
            System.arraycopy(block, 0, blockValue, 0, blockValue.length);
            //反转数组
            byte[] temp = new byte[4];
            for (int i = 0; i < temp.length; i++) {
                temp[temp.length - 1 - i] = block[i];
            }
            String hex = bytesToHexString(temp);
            return hex2Int(hex);
        }
        return -100;
    }
    
    /**
     * 十六进制转int 
     *
     * @param hex
     * @return
     */
    public static int hex2Int(String hex) {
        byte[] bytes = hex2Bytes(hex);
        int len = bytes.length;
        int rec = 0;
        for (int i = 0; i < len; i++) {
            int temp = bytes[i] & 0xff;
            int off = (len - 1 - i) * 8;
            rec |= (temp << off);
        }
        return rec;
    }
    
    /**
     * 十六进制转Byte
     *
     * @param hexStr
     * @return
     */
    public static byte[] hex2Bytes(String hexStr) {
        int len = hexStr.length();
        if (len % 2 != 0) {
            throw new RuntimeException("length error");
        }
        byte[] b = new byte[hexStr.length() / 2];
        int bLen = b.length;
        int j = 0;
        for (int i = 0; i < bLen; i++) {
            char c0 = hexStr.charAt(j++);
            char c1 = hexStr.charAt(j++);
            b[i] = (byte) ((parse(c0) << 4) | parse(c1));
        }
        return b;
    }
    
    private static int parse(char c) {
        if (c >= 'a')
            return (c - 'a' + 10) & 0x0f;
        if (c >= 'A')
            return (c - 'A' + 10) & 0x0f;
        return (c - '0') & 0x0f;
    }
    

    遇到的问题:
    1.构建值块:http://cn.voidcc.com/question/p-tpvgkusm-xv.html
    2.加值减值失败:https://stackoverflow.com/questions/11999710/how-to-use-mifareclassic-api-increment-and-decrement-in-android

    参考官方文档:
    https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf

    相关文章

      网友评论

          本文标题:Android NFC(二)M1卡电子钱包功能

          本文链接:https://www.haomeiwen.com/subject/cfxrmqtx.html