2013-10-17 44 views
38

我一直在尝试超过一个星期才能使Android手机通过Mifare Ultralight C进行身份验证。我已确认可以写入标记(通过写入不安全的内存页面和然后阅读我写的)。我还可以写入关键页面(44-47),并为所有16个关键字节写入0x00。Android:使用NXP进行身份验证MiFare Ultralight C

当我尝试进行身份验证时,以下是一个交换过程中涉及的数据示例 - 它来自我的应用程序编写的日志。任何人都可以告诉我,如果我做错了什么? I AM未披露,并有权访问完整数据表。请注意,下面的十六进制字符串显然是人们可读的数据发送和接收版本,其中代码由字节数组组成。

发送身份验证命令

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的代码,我真的不知道我做错了什么。

恩智浦技术支持完全没有响应。

任何想法?我很茫然。

+1

我在恩智浦应用笔记AN0945中找到了非常有益的实例,可用于调试我自己的代码。 –

+0

太好了,谢谢!我错过了,因为它是DESFire文档,我没有注意到DocStore中的文件夹。我刚下载,看起来很有希望。再次感谢 - 我非常感谢您的意见。 –

+1

NFCGuy - 您(或您认识的任何人)是否使用Android设备成功地通过Ultralight-C进行了端到端身份验证? –

回答

1

下面是一个例子的java代码作为MF0ICU2/MIFARE Ultralight C - Contactless ticket IC document(章节7.5.5 - 3DES认证,第15页)中所描述来执行超轻-C认证:

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