有没有人知道如何解密从卡发送的第一条消息?我的意思是在身份验证成功之后,然后您发送一个命令(例如 0x51 (GetRealTagUID).它返回 00+random32bits(总是不同).我尝试使用以下命令对其进行解密:
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;
}
并用decrypt(sessionKey, response, iv)调用它
And calling it with decrypt(sessionKey, response, iv)
IV = 全零(16 个字节)
IV = all zeros (16 bytes)
response = 0x51 命令后的 32 个随机位(只是去掉了两个零)
response = that 32randombits after the 0x51 command (just removed the two zeros)
有人告诉我,IV 在第一次发送命令 (0x51) 后发生了变化.如何生成正确的 IV 来解密该响应?我认为全零是错误的,因为解密后的消息总是不同的,同一张卡应该总是相同的.
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.
-编辑-
应用您的 (Michael Roland) 指令后,解密的响应仍然只是随机位.这是我的代码(我认为我做错了什么):
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);
在创建用于解密响应的新 IV 时使用什么 IV?那里全是零.
What IV to use when creating the new IV for decrypting the response? It is all zeros there.
身份验证后,IV 被重置为全零.当您使用 AES 身份验证时,您必须为每个后续命令计算 CMAC(即使 CMAC 实际上并未附加到命令中).因此,您的命令的 CMAC 计算将导致正确的 IV 初始化以解码响应.IE.命令的 CMAC 等于解密响应的 IV.同样,对于所有进一步的命令,IV 是来自先前加密/CMAC 的最后一个密码块.
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.
更新:
如何计算 CMAC pad XOR 值
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)为 1:xor rx[15]
与 0x86
.李>rx[0..15]
存储为 crc_k1[0..15]
.rx[0..15]
向左旋转一位.-> rrx[0..15]
rrx[15]
中的位 0)为 1:xor rrx[15]
与 0x86
.李>rrx[0..15]
存储为 crc_k2[0..15]
.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]
x[0..15]
one bit to the left. -> rx[0..15]
rx[15]
) is one: xor rx[15]
with 0x86
.rx[0..15]
as crc_k1[0..15]
.rx[0..15]
one bit to the left. -> rrx[0..15]
rrx[15]
) is one: xor rrx[15]
with 0x86
.rrx[0..15]
as 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
crc_k2[0..15]
进行异或.crc_k1[0..15]
进行异或.enc(IV xor datablock)
,前一个块的密文是新IV)结果.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.0x51
) this would look like: 0x51 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
crc_k2[0..15]
.crc_k1[0..15]
.enc(IV xor datablock)
, cipher text of previous block is new IV) the result with the session key.更新 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);
}
这篇关于如何解密从 Mifare Desfire EV1 发送的第一条消息的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持html5模板网!