Android:使用恩智浦MiFare Ultralight C进行身份validation

我已经尝试了一个多星期的时间来制作Android手机的Mifare Ultralight C进行身份validation。我已经确认我可以写入标签(通过写入一个不安全的内存页面,然后阅读我写的内容)。 我还可以写入关键页面(44-47),并为所有16个关键字节写入0x00。

当我尝试进行身份validation时,以下是一个交换过程中涉及的数据示例 – 它来自我的应用程序编写的日志。 任何人都可以告诉我,如果我做错了什么? 我处于保密状态,可以访问完整的数据表。 请注意,下面的hexstring显然是发送和接收的数据的人类可读版本,其中代码由字节数组组成。

发送validation命令

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我立即失去与标签的连接。 我已经通过数据表阅读每一个post,我可以在这里find。 我也看了libfreefare代码,我真的不知道我做错了什么。

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

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

以下是用于执行MF0ICU2 / MIFARE Ultralight C – 非接触式IC卡文档 (章节7.5.5 – 3DESauthentication,第15页)中所述的Ultralight-Cauthentication的示例java代码:

 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 。