問題描述
有沒有人知道如何解密從卡發(fā)送的第一條消息?我的意思是在身份驗(yàn)證成功之后,然后您發(fā)送一個(gè)命令(例如 0x51 (GetRealTagUID).它返回 00+random32bits(總是不同).我嘗試使用以下命令對其進(jìn)行解密:
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)調(diào)用它
And calling it with decrypt(sessionKey, response, iv)
IV = 全零(16 個(gè)字節(jié))
IV = all zeros (16 bytes)
response = 0x51 命令后的 32 個(gè)隨機(jī)位(只是去掉了兩個(gè)零)
response = that 32randombits after the 0x51 command (just removed the two zeros)
有人告訴我,IV 在第一次發(fā)送命令 (0x51) 后發(fā)生了變化.如何生成正確的 IV 來解密該響應(yīng)?我認(rèn)為全零是錯(cuò)誤的,因?yàn)榻饷芎蟮南⒖偸遣煌模粡埧☉?yīng)該總是相同的.
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.
-編輯-
應(yīng)用您的 (Michael Roland) 指令后,解密的響應(yīng)仍然只是隨機(jī)位.這是我的代碼(我認(rèn)為我做錯(cuò)了什么):
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-
仍然返回總是不同的值.我認(rèn)為問題可能出在此處:
Still returning always different values. I think the problem might lie here:
byte[] iv2 = encrypt(sessionKey, command, iv);
在創(chuàng)建用于解密響應(yīng)的新 IV 時(shí)使用什么 IV?那里全是零.
What IV to use when creating the new IV for decrypting the response? It is all zeros there.
推薦答案
身份驗(yàn)證后,IV 被重置為全零.當(dāng)您使用 AES 身份驗(yàn)證時(shí),您必須為每個(gè)后續(xù)命令計(jì)算 CMAC(即使 CMAC 實(shí)際上并未附加到命令中).因此,您的命令的 CMAC 計(jì)算將導(dǎo)致正確的 IV 初始化以解碼響應(yīng).IE.命令的 CMAC 等于解密響應(yīng)的 IV.同樣,對于所有進(jìn)一步的命令,IV 是來自先前加密/CMAC 的最后一個(gè)密碼塊.
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.
更新:
如何計(jì)算 CMAC pad XOR 值
- 使用會(huì)話密鑰(使用零的 IV)加密一個(gè)零塊(
0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
).->x[0..15]
- 將
x[0..15]
向左旋轉(zhuǎn)一位.->rx[0..15]
- 如果最后一位(
rx[15]
中的位 0)為 1:xorrx[15]
與0x86
.李> - 將
rx[0..15]
存儲(chǔ)為crc_k1[0..15]
. - 將
rx[0..15]
向左旋轉(zhuǎn)一位.->rrx[0..15]
- 如果最后一位(
rrx[15]
中的位 0)為 1:xorrrx[15]
與0x86
.李> - 將
rrx[0..15]
存儲(chǔ)為crc_k2[0..15]
.
- 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: xorrx[15]
with0x86
. - Store
rx[0..15]
ascrc_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: xorrrx[15]
with0x86
. - Store
rrx[0..15]
ascrc_k2[0..15]
.
如何計(jì)算 CMAC
- 您使用
0x80 0x00 0x00 ...
將命令填充到密碼的塊大小(AES 為 16 字節(jié)).如果命令長度與塊大小的倍數(shù)匹配,則不添加填充. - 對于您的命令 (
0x51
),如下所示:0x51 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
- 如果添加了填充,則將填充命令的最后 16 個(gè)字節(jié)與
crc_k2[0..15]
進(jìn)行異或. - 如果沒有添加填充,則將命令的最后 16 個(gè)字節(jié)與
crc_k1[0..15]
進(jìn)行異或. - 使用會(huì)話密鑰加密(在發(fā)送模式下,即
enc(IV xor datablock)
,前一個(gè)塊的密文是新IV)結(jié)果. - 最后一個(gè)區(qū)塊的密文是 CMAC 和新的 IV.
- 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.
更新 2:
如何將位向量向左旋轉(zhuǎn)一位
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);
}
這篇關(guān)于如何解密從 Mifare Desfire EV1 發(fā)送的第一條消息的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!