gpt4 book ai didi

java - 如何解密从 Mifare Desfire EV1 发送的第一条消息

转载 作者:行者123 更新时间:2023-11-30 07:12:15 25 4
gpt4 key购买 nike

有没有人知道如何解密从卡发送的第一条消息?我的意思是在身份验证成功之后,然后你发送一个命令(例如 0x51 (GetRealTagUID)。它返回 00+random32bits(总是不同的)。我尝试用以下方法解密它:

        private byte[] decrypt(byte[] raw, byte[] encrypted, byte[] iv)
throws Exception {
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParameterSpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}

并用 decrypt(sessionKey, response, iv) 调用它

IV = 全零(16 字节)

响应 = 0x51 命令后的 32 个随机位(只是删除了两个零)

有人告诉我,IV 在第一个发送命令 (0x51) 后发生变化。如何生成正确的 IV 来解密该响应?我认为全零是错误的,因为解密的消息总是不同的,并且对于同一张卡应该总是相同的。

-编辑-

应用您的(Michael Roland)指令后,解密的响应仍然只是随机位。这是我的代码(我想我做错了什么):

            byte[] x = encrypt(sessionKey, iv, iv);

byte[] rx = rotateBitsLeft(x);

if ((rx[15] & 0x01) == 0x01)
rx[15] = (byte) (rx[15] ^ 0x87);

if ((rx[15] & 0x01) == 0x00)
rx[15] = (byte) (rx[15] ^ 0x01);

byte[] crc_k1 = rx;

byte[] rrx = rotateBitsLeft(rx);

if ((rrx[15] & 0x01) == 0x01)
rrx[15] = (byte) (rrx[15] ^ 0x87);

if ((rrx[15] & 0x01) == 0x00)
rrx[15] = (byte) (rrx[15] ^ 0x01);

byte[] crc_k2 = rrx;

byte[] command = { (byte) 0x51, (byte) 0x80, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
(byte) 0x00 };

for (int i = 0; i < 16; i++){
command[i] = (byte) (command[i] ^ crc_k2[i]);
}

byte[] iv2 = encrypt(sessionKey, command, iv);

byte[] RealUID = decrypt(sessionKey, ReadDataParsed, iv2);

Log.e("RealUID", ByteArrayToHexString(RealUID));

-EDIT3-

仍然总是返回不同的值。我认为问题可能出在这里:

byte[] iv2 = encrypt(sessionKey, command, iv);

创建用于解密响应的新 IV 时使用什么 IV?那里全是零。

最佳答案

身份验证后,IV 重置为全零。当您使用 AES 身份验证时,您必须为每个后续命令计算 CMAC(即使 CMAC 实际上并未附加到该命令)。因此,您的命令的 CMAC 计算将导致正确的 IV 初始化以解码响应。 IE。命令的 CMAC 等于解密响应的 IV。同样,对于所有进一步的命令,IV 是来自先前加密/CMAC 的最后一个密码 block 。


更新:

如何计算CMAC pad异或值

  • 用 session key (使用零的 IV)加密一个零 block (0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00)。 -> x[0..15]
  • 旋转x[0..15]向左一点。 -> rx[0..15]
  • 如果最后一位(rx[15] 中的位 0)是一个:异或 rx[15]0x86 .
  • 商店 rx[0..15]作为crc_k1[0..15] .
  • 旋转rx[0..15]向左一点。 -> rrx[0..15]
  • 如果最后一位(rrx[15] 中的位 0)是一个:异或 rrx[15]0x86 .
  • 商店 rrx[0..15]作为crc_k2[0..15] .

如何计算CMAC

  • 您使用 0x80 0x00 0x00 ... 填充命令到密码的 block 大小(AES 为 16 字节)。如果命令长度匹配 block 大小的倍数,则不添加填充。
  • 对于你的命令(0x51),它看起来像:0x51 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  • 如果添加了填充,则用 crc_k2[0..15] 异或填充命令的最后 16 个字节.
  • 如果没有添加填充,则将命令的最后 16 个字节与 crc_k1[0..15] 异或.
  • 用 session key 加密(在发送模式下,即 enc(IV xor datablock),前一个 block 的密文是新 IV)结果。
  • 最后一个 block 的密文是CMAC和新的IV。

更新 2:

如何将位 vector 向左旋转一位

public void rotateLeft(byte[] data) {
byte t = (byte)((data[0] >>> 7) & 0x001);
for (int i = 0; i < (data.length - 1); ++i) {
data[i] = (byte)(((data[i] << 1) & 0x0FE) | ((data[i + 1] >>> 7) & 0x001));
}
data[data.length - 1] = (byte)(((data[data.length - 1] << 1) & 0x0FE) | t);
}

关于java - 如何解密从 Mifare Desfire EV1 发送的第一条消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20503060/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com