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

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

问题描述

一个多星期以来,我一直在尝试使用 Mifare Ultralight C 对 Android 手机进行身份验证.我已经确认我可以写入标签(通过写入不安全的内存页面,然后读取我写的内容).我还可以写入关键页面 (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 technical support had been completely unresponsive.

有什么想法吗?我不知所措.

Any ideas? I am at a loss.

推荐答案

以下是执行 Ultralight-C 身份验证的示例 Java 代码,如 MF0ICU2/MIFARE Ultralight C - 非接触式票证 IC 文档(第 7.5.5 章 -- 3DES 身份验证,第 15 页):

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天全站免登陆