Android:使用NXP MiFare Ultralight C进行身份验证 [英] Android: Authenticating with NXP MiFare Ultralight C

查看:119
本文介绍了Android:使用NXP MiFare Ultralight C进行身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经尝试了一个多星期,以使Android手机能够通过Mifare Ultralight C进行身份验证.我已经确认可以写入标签(通过写入不安全的内存页面,然后阅读我写的内容).我还可以写入密钥页面(44-47),并为所有16个密钥字节写入0x00.

I have been trying for more than a week to make an Android phone authenticate with a Mifare Ultralight C. I have confirmed I can write to the tag (by writing to an unsecured memory page and then reading what I wrote). I can also write to the key pages (44-47) and have written 0x00 for all 16 key bytes.

当我尝试进行身份验证时,以下是一次交换期间涉及的数据的示例-来自我的应用程序编写的日志.谁能告诉我我做错了什么吗?我 AM 未公开,可以访问完整数据表.请注意,下面的十六进制字符串显然是人类可读的正在发送和接收的数据版本,在代码中由字节数组组成.

When I try to authenticate, the following is an example of the data involved during one exchange - it is from a log written by my application. Can anyone tell me if I am doing something incorrect? I AM under non-disclosure and have access to the full data sheets. Note that the hexadecimal strings below are obviously human readable versions of the data being sent and received, which in the code consists of byte arrays.

发送身份验证命令

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代码,但老实说,我不知道自己在做什么错.

After sending 0xAF + E36C6C46FAAC60BA45DDF5F5A0802C79 I immediately lose the connection with the tag. I've gone through the data sheet and read every post I can find here. I have also looked at the libfreefare code and I honestly can't figure out what I'm doing wrong.

NXP技术支持完全没有响应.

NXP technical support had been completely unresponsive.

有什么想法吗?我很茫然.

Any ideas? I am at a loss.

推荐答案

下面是一个示例Java代码,用于执行

Below is an example java code to perform Ultralight-C authentication as described in MF0ICU2 / MIFARE Ultralight C - Contactless ticket IC document (chapter 7.5.5 -- 3DES Authentication, page 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 .

这篇关于Android:使用NXP MiFare Ultralight C进行身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆