Mat*_*ond 37 authentication android rfid nfc mifare
我已经尝试了一个多星期的时间来使用Mifare Ultralight C对Android手机进行身份验证.我已经确认我可以写入标签(通过写入不安全的内存页然后阅读我写的内容).我也可以写入关键页面(44-47)并为所有16个关键字节写入0x00.
当我尝试进行身份验证时,以下是一次交换过程中涉及的数据示例 - 它来自我的应用程序编写的日志.谁能告诉我,如果我做错了什么?我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
Run Code Online (Sandbox Code Playgroud)
发送后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]);
}
Run Code Online (Sandbox Code Playgroud)
注意:此代码使用Apache Commons Lang。
| 归档时间: |
|
| 查看次数: |
3401 次 |
| 最近记录: |