Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac983353 authored by Jean-Baptiste Queru's avatar Jean-Baptiste Queru
Browse files

Merge da01b4ab from gingerbread

Change-Id: I644f170fe18042ffb09b9b852321f68c651c7972
parents 6d904e70 da01b4ab
Loading
Loading
Loading
Loading
+43 −81
Original line number Diff line number Diff line
@@ -118781,7 +118781,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<method name="authenticateBlock"
<method name="authenticateSectorWithKeyA"
 return="boolean"
 abstract="false"
 native="false"
@@ -118791,16 +118791,14 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="block" type="int">
<parameter name="sectorIndex" type="int">
</parameter>
<parameter name="key" type="byte[]">
</parameter>
<parameter name="keyA" type="boolean">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="authenticateSector"
<method name="authenticateSectorWithKeyB"
 return="boolean"
 abstract="false"
 native="false"
@@ -118810,17 +118808,15 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="sector" type="int">
<parameter name="sectorIndex" type="int">
</parameter>
<parameter name="key" type="byte[]">
</parameter>
<parameter name="keyA" type="boolean">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="decrement"
 return="void"
<method name="blockToSector"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
@@ -118829,38 +118825,38 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="block" type="int">
<parameter name="blockIndex" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="get"
 return="android.nfc.tech.MifareClassic"
<method name="decrement"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="true"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="tag" type="android.nfc.Tag">
<parameter name="blockIndex" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="getBlockCount"
 return="int"
<method name="get"
 return="android.nfc.tech.MifareClassic"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 static="true"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="sector" type="int">
<parameter name="tag" type="android.nfc.Tag">
</parameter>
</method>
<method name="getSectorCount"
<method name="getBlockCount"
 return="int"
 abstract="false"
 native="false"
@@ -118871,7 +118867,7 @@
 visibility="public"
>
</method>
<method name="getSectorSize"
<method name="getBlockCountInSector"
 return="int"
 abstract="false"
 native="false"
@@ -118881,10 +118877,10 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="sector" type="int">
<parameter name="sectorIndex" type="int">
</parameter>
</method>
<method name="getSize"
<method name="getSectorCount"
 return="int"
 abstract="false"
 native="false"
@@ -118895,7 +118891,7 @@
 visibility="public"
>
</method>
<method name="getTotalBlockCount"
<method name="getSize"
 return="int"
 abstract="false"
 native="false"
@@ -118927,22 +118923,11 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="block" type="int">
<parameter name="blockIndex" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="isEmulated"
 return="boolean"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
 deprecated="not deprecated"
 visibility="public"
>
</method>
<method name="readBlock"
 return="byte[]"
 abstract="false"
@@ -118953,15 +118938,13 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="sector" type="int">
</parameter>
<parameter name="block" type="int">
<parameter name="blockIndex" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="readBlock"
 return="byte[]"
<method name="restore"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
@@ -118970,13 +118953,13 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="block" type="int">
<parameter name="blockIndex" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="restore"
 return="void"
<method name="sectorToBlock"
 return="int"
 abstract="false"
 native="false"
 synchronized="false"
@@ -118985,10 +118968,8 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="block" type="int">
<parameter name="sectorIndex" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="transceive"
 return="byte[]"
@@ -119015,7 +118996,7 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="block" type="int">
<parameter name="blockIndex" type="int">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
@@ -119030,32 +119011,24 @@
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="block" type="int">
<parameter name="blockIndex" type="int">
</parameter>
<parameter name="data" type="byte[]">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
<method name="writeBlock"
 return="void"
 abstract="false"
 native="false"
 synchronized="false"
 static="false"
 final="false"
<field name="BLOCK_SIZE"
 type="int"
 transient="false"
 volatile="false"
 value="16"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
<parameter name="sector" type="int">
</parameter>
<parameter name="block" type="int">
</parameter>
<parameter name="data" type="byte[]">
</parameter>
<exception name="IOException" type="java.io.IOException">
</exception>
</method>
</field>
<field name="KEY_DEFAULT"
 type="byte[]"
 transient="false"
@@ -119133,7 +119106,7 @@
 visibility="public"
>
</field>
<field name="SIZE_UNKNOWN"
<field name="TYPE_CLASSIC"
 type="int"
 transient="false"
 volatile="false"
@@ -119144,11 +119117,11 @@
 visibility="public"
>
</field>
<field name="TYPE_CLASSIC"
<field name="TYPE_OTHER"
 type="int"
 transient="false"
 volatile="false"
 value="0"
 value="-1"
 static="true"
 final="true"
 deprecated="not deprecated"
@@ -119177,17 +119150,6 @@
 visibility="public"
>
</field>
<field name="TYPE_UNKNOWN"
 type="int"
 transient="false"
 volatile="false"
 value="5"
 static="true"
 final="true"
 deprecated="not deprecated"
 visibility="public"
>
</field>
</class>
<class name="MifareUltralight"
 extends="android.nfc.tech.BasicTagTechnology"
+186 −189
Original line number Diff line number Diff line
@@ -59,8 +59,8 @@ public final class MifareClassic extends BasicTagTechnology {
    public static final int TYPE_PLUS = 1;
    /** A MIFARE Pro tag */
    public static final int TYPE_PRO = 2;
    /** The tag type is unknown */
    public static final int TYPE_UNKNOWN = 5;
    /** A Mifare Classic compatible card that does not match the other types */
    public static final int TYPE_OTHER = -1;

    /** The tag contains 16 sectors, each holding 4 blocks. */
    public static final int SIZE_1K = 1024;
@@ -73,8 +73,12 @@ public final class MifareClassic extends BasicTagTechnology {
    public static final int SIZE_4K = 4096;
    /** The tag contains 5 sectors, each holding 4 blocks. */
    public static final int SIZE_MINI = 320;
    /** The capacity is unknown */
    public static final int SIZE_UNKNOWN = 0;

    /** Size of a Mifare Classic block (in bytes) */
    public static final int BLOCK_SIZE = 16;

    private static final int MAX_BLOCK_COUNT = 256;
    private static final int MAX_SECTOR_COUNT = 40;

    private boolean mIsEmulated;
    private int mType;
@@ -99,102 +103,76 @@ public final class MifareClassic extends BasicTagTechnology {
    public MifareClassic(Tag tag) throws RemoteException {
        super(tag, TagTechnology.MIFARE_CLASSIC);

        // Check if this could actually be a MIFARE Classic
        NfcA a = NfcA.get(tag);
        NfcA a = NfcA.get(tag);  // Mifare Classic is always based on NFC a

        mIsEmulated = false;
        mType = TYPE_UNKNOWN;
        mSize = SIZE_UNKNOWN;

        switch (a.getSak()) {
        case 0x08:
                // Type == classic
                // Size = 1K
            mType = TYPE_CLASSIC;
            mSize = SIZE_1K;
            break;
        case 0x09:
                // Type == classic mini
                // Size == ?
            mType = TYPE_CLASSIC;
            mSize = SIZE_MINI;
            break;
        case 0x10:
                // Type == MF+
                // Size == 2K
                // SecLevel = SL2
            mType = TYPE_PLUS;
            mSize = SIZE_2K;
            // SecLevel = SL2
            break;
        case 0x11:
                // Type == MF+
                // Size == 4K
                // Seclevel = SL2
            mType = TYPE_PLUS;
            mSize = SIZE_4K;
            // Seclevel = SL2
            break;
        case 0x18:
                // Type == classic
                // Size == 4k
            mType = TYPE_CLASSIC;
            mSize = SIZE_4K;
            break;
            case 0x20:
                // TODO this really should be a short, not byte
                if (a.getAtqa()[0] == 0x03) {
                    // Type == DESFIRE
                    break;
                } else {
                    // Type == MF+
                    // SL = SL3
                    mType = TYPE_PLUS;
                    mSize = SIZE_UNKNOWN;
                }
                break;
        case 0x28:
                // Type == MF Classic
                // Size == 1K
                // Emulated == true
            mType = TYPE_CLASSIC;
            mSize = SIZE_1K;
            mIsEmulated = true;
            break;
        case 0x38:
                // Type == MF Classic
                // Size == 4K
                // Emulated == true
            mType = TYPE_CLASSIC;
            mSize = SIZE_4K;
            mIsEmulated = true;
            break;
        case 0x88:
                // Type == MF Classic
                // Size == 1K
                // NXP-tag: false
            mType = TYPE_CLASSIC;
            mSize = SIZE_1K;
            // NXP-tag: false
            break;
        case 0x98:
        case 0xB8:
                // Type == MF Pro
                // Size == 4K
            mType = TYPE_PRO;
            mSize = SIZE_4K;
            break;
        default:
            // Stack incorrectly reported a MifareClassic. We cannot handle this
            // gracefully - we have no idea of the memory layout. Bail.
            throw new RuntimeException(
                    "Tag incorrectly enumerated as Mifare Classic, SAK = " + a.getSak());
        }
    }

    /** Returns the size of the tag, determined at discovery time */
    public int getSize() {
        return mSize;
    }

    /** Returns the size of the tag, determined at discovery time */
    /** Returns the type of the tag, determined at discovery time */
    public int getType() {
        return mType;
    }

    /** Returns true if the tag is emulated, determined at discovery time */
    /** Returns the size of the tag in bytes, determined at discovery time */
    public int getSize() {
        return mSize;
    }

    /** Returns true if the tag is emulated, determined at discovery time.
     * These are actually smart-cards that emulate a Mifare Classic interface.
     * They can be treated identically to a Mifare Classic tag.
     * @hide
     */
    public boolean isEmulated() {
        return mIsEmulated;
    }
@@ -202,67 +180,78 @@ public final class MifareClassic extends BasicTagTechnology {
    /** Returns the number of sectors on this tag, determined at discovery time */
    public int getSectorCount() {
        switch (mSize) {
            case SIZE_1K: {
        case SIZE_1K:
            return 16;
            }
            case SIZE_2K: {
        case SIZE_2K:
            return 32;
            }
            case SIZE_4K: {
        case SIZE_4K:
            return 40;
            }
            case SIZE_MINI: {
        case SIZE_MINI:
            return 5;
            }
            default: {
        default:
            return 0;
        }
    }
    }

    /** Returns the sector size, determined at discovery time */
    public int getSectorSize(int sector) {
        return getBlockCount(sector) * 16;
    }

    /** Returns the total block count, determined at discovery time */
    public int getTotalBlockCount() {
        int totalBlocks = 0;
        for (int sec = 0; sec < getSectorCount(); sec++) {
            totalBlocks += getSectorSize(sec);
        }

        return totalBlocks;
    public int getBlockCount() {
        return mSize / BLOCK_SIZE;
    }

    /** Returns the block count for the given sector, determined at discovery time */
    public int getBlockCount(int sector) {
        if (sector >= getSectorCount()) {
            throw new IllegalArgumentException("this card only has " + getSectorCount() +
                    " sectors");
        }
    public int getBlockCountInSector(int sectorIndex) {
        validateSector(sectorIndex);

        if (sector <= 32) {
        if (sectorIndex < 32) {
            return 4;
        } else {
            return 16;
        }
    }

    private byte firstBlockInSector(int sector) {
        if (sector < 32) {
            return (byte) ((sector * 4) & 0xff);
    /** Return the sector index of a given block */
    public int blockToSector(int blockIndex) {
        validateBlock(blockIndex);

        if (blockIndex < 32 * 4) {
            return blockIndex / 4;
        } else {
            return (byte) ((32 * 4 + ((sector - 32) * 16)) & 0xff);
            return 32 + (blockIndex - 32 * 4) / 16;
        }
    }

    /** Return the first block of a given sector */
    public int sectorToBlock(int sectorIndex) {
        if (sectorIndex < 32) {
            return sectorIndex * 4;
        } else {
            return 32 * 4 + (sectorIndex - 32) * 16;
        }
    }

    // Methods that require connect()
    /**
     * Authenticate the entire sector that the given block resides in.
     * Authenticate a sector.
     * <p>Every sector has an A and B key with different access privileges,
     * this method attempts to authenticate against the A key.
     * <p>This requires a that the tag be connected.
     */
    public boolean authenticateBlock(int block, byte[] key, boolean keyA) throws IOException {
    public boolean authenticateSectorWithKeyA(int sectorIndex, byte[] key) throws IOException {
        return authenticate(sectorIndex, key, true);
    }

    /**
     * Authenticate a sector.
     * <p>Every sector has an A and B key with different access privileges,
     * this method attempts to authenticate against the B key.
     * <p>This requires a that the tag be connected.
     */
    public boolean authenticateSectorWithKeyB(int sectorIndex, byte[] key) throws IOException {
        return authenticate(sectorIndex, key, false);
    }

    private boolean authenticate(int sector, byte[] key, boolean keyA) throws IOException {
        validateSector(sector);
        checkConnected();

        byte[] cmd = new byte[12];
@@ -275,7 +264,9 @@ public final class MifareClassic extends BasicTagTechnology {
        }

        // Second byte is block address
        cmd[1] = (byte) block;
        // Authenticate command takes a block address. Authenticating a block
        // of a sector will authenticate the entire sector.
        cmd[1] = (byte) sectorToBlock(sector);

        // Next 4 bytes are last 4 bytes of UID
        byte[] uid = getTag().getId();
@@ -285,7 +276,7 @@ public final class MifareClassic extends BasicTagTechnology {
        System.arraycopy(key, 0, cmd, 6, 6);

        try {
            if ((transceive(cmd, false) != null)) {
            if (transceive(cmd, false) != null) {
                return true;
            }
        } catch (TagLostException e) {
@@ -297,106 +288,92 @@ public final class MifareClassic extends BasicTagTechnology {
    }

    /**
     * Authenticate for a given sector.
     * Read 16-byte block.
     * <p>This requires a that the tag be connected.
     * @throws IOException
     */
    public boolean authenticateSector(int sector, byte[] key, boolean keyA) throws IOException {
    public byte[] readBlock(int blockIndex) throws IOException {
        validateBlock(blockIndex);
        checkConnected();

        byte addr = (byte) ((firstBlockInSector(sector)) & 0xff);

        // Note that authenticating a block of a sector, will authenticate
        // the entire sector.
        return authenticateBlock(addr, key, keyA);
        byte[] cmd = { 0x30, (byte) blockIndex };
        return transceive(cmd, false);
    }

    /**
     * Sector indexing starts at 0.
     * Block indexing starts at 0, and resets in each sector.
     * Write 16-byte block.
     * <p>This requires a that the tag be connected.
     * @throws IOException
     */
    public byte[] readBlock(int sector, int block) throws IOException {
    public void writeBlock(int blockIndex, byte[] data) throws IOException {
        validateBlock(blockIndex);
        checkConnected();
        if (data.length != 16) {
            throw new IllegalArgumentException("must write 16-bytes");
        }

        byte[] cmd = new byte[data.length + 2];
        cmd[0] = (byte) 0xA0; // MF write command
        cmd[1] = (byte) blockIndex;
        System.arraycopy(data, 0, cmd, 2, data.length);

        byte addr = (byte) ((firstBlockInSector(sector) + block) & 0xff);
        return readBlock(addr);
        transceive(cmd, false);
    }

    /**
     * Reads absolute block index.
     * <p>This requires a that the tag be connected.
     * Increment a value block, and store the result in temporary memory.
     * @param block
     * @throws IOException
     */
    public byte[] readBlock(int block) throws IOException {
    public void increment(int blockIndex) throws IOException {
        validateBlock(blockIndex);
        checkConnected();

        byte addr = (byte) block;
        byte[] blockread_cmd = { 0x30, addr };
        byte[] cmd = { (byte) 0xC1, (byte) blockIndex };

        return transceive(blockread_cmd, false);
        transceive(cmd, false);
    }

    /**
     * Writes absolute block index.
     * <p>This requires a that the tag be connected.
     * Decrement a value block, and store the result in temporary memory.
     * @param block
     * @throws IOException
     */
    public void writeBlock(int block, byte[] data) throws IOException {
    public void decrement(int blockIndex) throws IOException {
        validateBlock(blockIndex);
        checkConnected();

        byte addr = (byte) block;
        byte[] blockwrite_cmd = new byte[data.length + 2];
        blockwrite_cmd[0] = (byte) 0xA0; // MF write command
        blockwrite_cmd[1] = addr;
        System.arraycopy(data, 0, blockwrite_cmd, 2, data.length);
        byte[] cmd = { (byte) 0xC0, (byte) blockIndex };

        transceive(blockwrite_cmd, false);
        transceive(cmd, false);
    }

    /**
     * Writes relative block in sector.
     * <p>This requires a that the tag be connected.
     * Copy from temporary memory to value block.
     * @param block
     * @throws IOException
     */
    public void writeBlock(int sector, int block, byte[] data) throws IOException {
    public void transfer(int blockIndex) throws IOException {
        validateBlock(blockIndex);
        checkConnected();

        byte addr = (byte) ((firstBlockInSector(sector) + block) & 0xff);
        byte[] cmd = { (byte) 0xB0, (byte) blockIndex };

        writeBlock(addr, data);
        transceive(cmd, false);
    }

    public void increment(int block) throws IOException {
        checkConnected();

        byte[] incr_cmd = { (byte) 0xC1, (byte) block };

        transceive(incr_cmd, false);
    }

    public void decrement(int block) throws IOException {
        checkConnected();

        byte[] decr_cmd = { (byte) 0xC0, (byte) block };

        transceive(decr_cmd, false);
    }

    public void transfer(int block) throws IOException {
        checkConnected();

        byte[] trans_cmd = { (byte) 0xB0, (byte) block };

        transceive(trans_cmd, false);
    }

    public void restore(int block) throws IOException {
    /**
     * Copy from value block to temporary memory.
     * @param block
     * @throws IOException
     */
    public void restore(int blockIndex) throws IOException {
        validateBlock(blockIndex);
        checkConnected();

        byte[] rest_cmd = { (byte) 0xC2, (byte) block };
        byte[] cmd = { (byte) 0xC2, (byte) blockIndex };

        transceive(rest_cmd, false);
        transceive(cmd, false);
    }

    /**
@@ -414,4 +391,24 @@ public final class MifareClassic extends BasicTagTechnology {
    public byte[] transceive(byte[] data) throws IOException {
        return transceive(data, true);
    }

    private void validateSector(int sector) {
        // Do not be too strict on upper bounds checking, since some cards
        // have more addressable memory than they report. For example,
        // Mifare Plus 2k cards will appear as Mifare Classic 1k cards when in
        // Mifare Classic compatibility mode.
        // Note that issuing a command to an out-of-bounds block is safe - the
        // tag should report error causing IOException. This validation is a
        // helper to guard against obvious programming mistakes.
        if (sector < 0 || sector >= MAX_SECTOR_COUNT) {
            throw new IndexOutOfBoundsException("sector out of bounds: " + sector);
        }
    }

    private void validateBlock(int block) {
        // Just looking for obvious out of bounds...
        if (block < 0 || block >= MAX_BLOCK_COUNT) {
            throw new IndexOutOfBoundsException("block out of bounds: " + block);
        }
    }
}