簡體   English   中英

Android:使用恩智浦MiFare Ultralight C進行身份驗證

[英]Android: Authenticating with NXP MiFare Ultralight C

我已經嘗試了一個多星期的時間來使用Mifare Ultralight C對Android手機進行身份驗證。我已經確認我可以寫入標簽(通過寫入不安全的內存頁然后閱讀我寫的內容)。 我也可以寫入關鍵頁面(44-47)並為所有16個關鍵字節寫入0x00。

當我嘗試進行身份驗證時,以下是一次交換過程中涉及的數據示例 - 它來自我的應用程序編寫的日志。 誰能告訴我,如果我做錯了什么? 不泄露,並有機會獲得完整的數據表。 請注意,下面的十六進制字符串顯然是發送和接收的數據的人類可讀版本,在代碼中由字節數組組成。

發送身份驗證命令

Received rndB: 8A5735694D9D7542

Key: 00000000000000000000000000000000

IV: 0000000000000000

Decrypted rndB: EF340C62E1B866D4

rndB': 340C62E1B866D4EF

rndA: 6E262630E299F94F

rndA+rndB': 6E262630E299F94F340C62E1B866D4EF

Key: 00000000000000000000000000000000

IV: 8A5735694D9D7542

ek(RndA+rndB'): E36C6C46FAAC60BA45DDF5F5A0802C79

發送0xAF + E36C6C46FAAC60BA45DDF5F5A0802C79我立即失去與標簽的連接。 我已經閱讀了數據表並閱讀了我在這里找到的每篇文章。 我也查看了libfreefare代碼,老實說,我無法弄清楚我做錯了什么。

恩智浦的技術支持完全沒有反應。

有任何想法嗎? 我很茫然。

下面是執行Ultralight-C身份驗證的示例java代碼,如MF0ICU2 / MIFARE Ultralight C - 非接觸式故障單IC文檔 (第7.5.5節 - 3DES身份驗證,第15頁)中所述:

public void authenticate(byte[] key) throws CardException {
    System.out.println("AUTHENTICATE");
    byte[] encRndB = transmitRaw(new byte[] { 0x1A, 0x00 });
    if((encRndB.length!=9)||(encRndB[0]!=AF)) {
        throw new RuntimeException("Invalid response!");
    }
    encRndB=Arrays.copyOfRange(encRndB, 1, 9);
    System.out.println(" - EncRndB: " + toHex(encRndB));
    byte[] rndB = desDecrypt(key, encRndB);
    System.out.println(" - RndB: " + toHex(rndB));
    byte[] rndBrot = rotateLeft(rndB);
    System.out.println(" - RndBrot: " + toHex(rndBrot));
    byte[] rndA = new byte[8];
    generateRandom(rndA);
    System.out.println(" - RndA: " + toHex(rndA));
    byte[] encRndArotPrime = transmitRaw(ArrayUtils.addAll(new byte[] {AF}, desEncrypt(key, ArrayUtils.addAll(rndA, rndBrot))));
    if((encRndArotPrime.length!=9)||(encRndArotPrime[0]!=0x00)) {
        throw new RuntimeException("Invalid response!");
    }
    encRndArotPrime=Arrays.copyOfRange(encRndArotPrime, 1, 9);
    System.out.println(" - EncRndArot': " + toHex(encRndArotPrime));
    byte[] rndArotPrime = desDecrypt(key, encRndArotPrime);
    System.out.println(" - RndArot': " + toHex(rndArotPrime));
    if(!Arrays.equals(rotateLeft(rndA), rndArotPrime)) {
        throw new RuntimeException("Card authentication failed");
    }
}

protected static SecureRandom rnd = new SecureRandom();
protected static void generateRandom(byte[] rndA) {
    rnd.nextBytes(rndA);
}

protected byte[] desEncrypt(byte[] key, byte[] data) {
    return performDes(Cipher.ENCRYPT_MODE, key, data);
}
protected byte[] desDecrypt(byte[] key, byte[] data) {
    return performDes(Cipher.DECRYPT_MODE, key, data);
}
private byte[] iv = new byte[8];
protected byte[] performDes(int opMode, byte[] key, byte[] data) {
    try {
        Cipher des = Cipher.getInstance("DESede/CBC/NoPadding");
        SecretKeyFactory desKeyFactory = SecretKeyFactory.getInstance("DESede");
        Key desKey = desKeyFactory.generateSecret(new DESedeKeySpec(ArrayUtils.addAll(key, Arrays.copyOf(key, 8))));
        des.init(opMode, desKey, new IvParameterSpec(iv));
        byte[] ret = des.doFinal(data);
        if(opMode==Cipher.ENCRYPT_MODE) {
            iv=Arrays.copyOfRange(ret, ret.length-8, ret.length);
        } else {
            iv=Arrays.copyOfRange(data, data.length-8, data.length);
        }
        return ret;
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException | InvalidAlgorithmParameterException e) {
        throw new RuntimeException(e);
    }
}

protected static byte[] rotateLeft(byte[] in) {
    return ArrayUtils.add(Arrays.copyOfRange(in, 1, 8), in[0]);
}

注意:此代碼使用Apache Commons Lang

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM