当前位置: 首页 > 面试题库 >

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

隗昀
2023-03-14
问题内容

有人知道如何解密从卡发送的第一条消息吗?我的意思是,在身份验证成功之后,然后您发送命令(例如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;
    }

并使用解密(sessionKey,响应,iv)调用

IV =全零(16字节)

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

有人告诉我,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));

-编辑3-

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

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

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


问题答案:

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

更新:

如何计算CMAC填充XOR值

  • 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00使用会话密钥(使用零的IV)加密一个零块()。->x[0..15]
  • x[0..15]向左旋转一位。->rx[0..15]
  • 如果最后一位(中的位0 rx[15])为1:rx[15]与或0x86
  • 储存rx[0..15]crc_k1[0..15]
  • rx[0..15]向左旋转一位。->rrx[0..15]
  • 如果最后一位(中的位0 rrx[15])为1:rrx[15]与或0x86
  • 储存rrx[0..15]crc_k2[0..15]

如何计算CMAC

  • 使用0x80 0x00 0x00 ...密码的块大小填充命令(AES为16字节)。如果命令长度与块大小的倍数匹配,则不添加填充。
  • 对于您的命令(0x51),它看起来像:0x51 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
  • 如果添加了填充,请使用来对填充命令的最后16个字节进行xor运算crc_k2[0..15]
  • 如果未添加填充,请使用来对命令的最后16个字节进行xor运算crc_k1[0..15]
  • enc(IV xor datablock)用会话密钥加密(在发送模式下,即前一个块的密文为新的IV)结果。
  • 最后一块的密文是CMAC和新的IV。

更新2:

如何将位向量向左旋转一位

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);
}


 类似资料:
  • 20.3. 发送一条消息 JmsTemplate包含许多方便的方法来发送消息。有些发送方法可以使用 javax.jms.Destination对象指定目的地,也可以使用字符串在JNDI中查找目的地。没有目的地参数的发送方法使用默认的目的地。这里有个例子使用1.0.2版的JMS实现发送消息到一个队列。 import javax.jms.ConnectionFactory; import javax.

  • 我试图在不和谐的情况下每隔x秒发送一条消息。js机器人。我知道如何做到这一点,但我遇到的问题是,即使我启用了slowmode,它也会发送垃圾邮件。我怎样才能解决这个问题?

  • 我已在中创建了我的应用程序并配置为云消息传递。当我从控制台发送通知时,设备会收到通知,但如果我尝试通过Rest API(使用PostMan)发送。然后通知不会到达设备,但响应显示为成功。 这是我的邮差请求 URI-https://fcm.googleapis.com/fcm/send 标题:内容类型:应用程序/json授权:密钥=MY_SERVER_KEY 正文:{“数据”:{“标题”:“火力基地

  • 问题内容: 如何从Java发送SMTP消息? 问题答案: 这是Gmail smtp的示例: 现在,仅当您希望将项目依赖关系降至最低时,才可以这样做,否则我可以热烈推荐使用apache中的类 http://commons.apache.org/email/ 问候 托雷·雅各布森

  • 嗨,我正在使用twilio API发送一个消息到whatsapp号码,我需要的是从表单中获得号码和消息,并将数据放在twilio API中,我现在不知道如何构建逻辑,但我做到了这一点,但没有工作,我得到了这个错误 这就是我写的逻辑init的控制器文件 我希望我准确地解释了我需要什么

  • 我有一个简单的camel MINA服务器,使用JAVA DSL,我的运行方式与这里记录的示例类似: 独立运行骆驼并让它在JAVA中继续运行 MINA 2组件 我正在尝试创建一个托管在mina:tcp://localhost:9991(又名MyApp_B)的示例应用程序,该应用程序向托管在mina:tcp://localhost:9990(又名MyApp_A)的服务器发送一个非常简单的消息。 我想发