如何解密从Mifare Desfire EV1发送的第一条消息 [英] How to decrypt the first message sent from Mifare Desfire EV1

查看:425
本文介绍了如何解密从Mifare Desfire EV1发送的第一条消息的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  private byte [] decrypt(byte [] raw,byte [] encrypted,byte [] iv)
throws Exception {
IvParameterSpec ivParameterSpec = new IvParameterSpec );
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字节) p>

response =在0x51命令之后有32个命令(只删除两个零)



有人告诉我,在第一次发送命令(0x51)后更改。如何生成解密该响应的正确的IV?我认为全零是错误的,因为解密的邮件总是不同的,它应该总是与同一张卡相同。



-EDIT -



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

  byte [] x = encrypt 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, )0x00,
(字节)0x00,(字节)0x00,(字节)0x00,(字节)0x00,
(字节)0x00,(字节)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会重置为全零。当您使用AES身份验证时,您必须为每个后续命令计算CMAC(即使CMAC实际上未附加到命令)。因此,您的命令的CMAC计算将导致正确的IV初始化以解码响应。也就是说该命令的CMAC等于用于解密响应的IV。类似地,对于所有其他命令,IV是来自先前加密/ CMAC的最后一个密码块。






UPDATE:



如何计算CMAC邮垫XOR值

  • 使用会话密钥加密一个零块( 0x00 0x00 0x00 0x00 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 ] )是一个:xor rx [15] 0x86
  • rx [0..15] 存储为 crc_k1 [0..15]

  • 向左旋转 rx [0..15] 一位。 - > rrx [0..15]

  • 如果最后一位( rrx [15 ] )是一个:xor rrx [15] 0x86
  • rrx [0..15] 存储为 crc_k2 [0..15]



  • 如何计算CMAC




    • 使用 0x80 0x00 0x00 ... 填充该命令到密码的块大小(AES为16字节)。如果命令长度与块大小的倍数匹配,则不添加填充。

    • 对于您的命令( 0x51 ), like: 0x51 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

    • 如果添加了填充, 16字节的填充命令与 crc_k2 [0..15]

    • 如果没有添加填充,xor最后16字节 crc_k1 [0..15]

    • 加密(在发送模式下,即 enc (IV xor数据块),前一个块的密文是新的。IV)会话密钥的结果。

    • 最后一个块的密文是CMAC新的IV。






    更新2: p>

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

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


    Does anyone have a clue how to decrypt the first message sent from the card? I mean after the authentication success and then you send a command (for example 0x51 (GetRealTagUID). It returns 00+random32bits (always different). I try to decrypt it with:

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

    And calling it with decrypt(sessionKey, response, iv)

    IV = all zeros (16 bytes)

    response = that 32randombits after the 0x51 command (just removed the two zeros)

    Someone told me, that the IV changes after the first sent command (0x51). How to generate the right IV for decrypting that response? I think the all zeros is wrong, because the decrypted message is always different and it should be always same with the same card.

    -EDIT-

    After applying your (Michael Roland) instructions, the decrypted response is still just random bits. Here is my code (I think I'm doing something wrong):

                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-

    Still returning always different values. I think the problem might lie here:

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

    What IV to use when creating the new IV for decrypting the response? It is all zeros there.

    解决方案

    After authentication, the IV is reset to all-zeros. As you use AES authentication, you then have to calculate the CMAC for every follow-up command (even if CMAC is not actually appended to the command). So the CMAC calculation for your command will lead to correct IV initialization for decoding the response. I.e. the CMAC for the command is equal to the IV for decrypting the response. Similarly, for all further commands, the IV is the last cipher block from the previous encryption/CMAC.


    UPDATE:

    How to calculate CMAC pad XOR value

    • Encrypt one block of zeros (0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00) with session key (using IV of zeros). -> x[0..15]
    • Rotate x[0..15] one bit to the left. -> rx[0..15]
    • If the last bit (bit 0 in rx[15]) is one: xor rx[15] with 0x86.
    • Store rx[0..15] as crc_k1[0..15].
    • Rotate rx[0..15] one bit to the left. -> rrx[0..15]
    • If the last bit (bit 0 in rrx[15]) is one: xor rrx[15] with 0x86.
    • Store rrx[0..15] as crc_k2[0..15].

    How to calculate CMAC

    • You pad the command using 0x80 0x00 0x00 ... to the block size of the cipher (16 bytes for AES). If the command length matches a multiple of the block size, no padding is added.
    • For your command (0x51) this would look like: 0x51 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
    • If padding was added, xor the last 16 bytes of the padded command with crc_k2[0..15].
    • If no padding was added, xor the last 16 bytes of the command with crc_k1[0..15].
    • Encrypt (in send mode, i.e. enc(IV xor datablock), cipher text of previous block is new IV) the result with the session key.
    • The ciphertext of the last block is the CMAC and the new IV.

    UPDATE 2:

    How to rotate a bit vector to the left for one bit

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

    这篇关于如何解密从Mifare Desfire EV1发送的第一条消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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