2015-12-22 27 views
0

我嘗試使用ISO 7816-4 APDU在DESFire卡(常駐卡)上執行驗證過程。但它總是失敗。我想念任何東西嗎?使用ISO 7816-4 APDU的DESFire卡中的外部驗證

>>>00 84 00 00 00(挑戰請求 - 5個字節)

< < < 15 29 84 E3 6A AA A6 B7 90 00(的挑戰10字節響應 - OK)

>>>00 82 00 00 10 B5 02 0B 80 4F 95 CB E7 8C A6 4D E9 C1 B1 23 A7 00(外部auth請求 - 22個字節)

< < < 67 00(外部認證的響應 - 檢查錯誤:長度錯誤)

代碼:

// STEP Authentication 
// send initial authentication request 
byte[] reqRnbEnc = new byte[]{ 
     (byte) 0x00, 
     (byte) 0x84, 
     (byte) 0x00, (byte) 0x00, 
     (byte) 0x00}; 

// get encrypted RndB 
byte[] resRnbEnc = _isoDep.transceive(reqRnbEnc); 
_responseTextView.append(String.format("reqRnbEnc: %s length:%d\n", BytesToHexStr(reqRnbEnc), reqRnbEnc.length)); 
_responseTextView.append(String.format("resRnbEnc: %s length:%d\n", BytesToHexStr(resRnbEnc), resRnbEnc.length)); 

// remove 2 last characters 
byte[] resRnbEncT = new byte[8]; 
System.arraycopy(resRnbEnc, 0, resRnbEncT, 0, 8); 
_responseTextView.append(String.format("-resRnbEncT: %s length:%d\n", BytesToHexStr(resRnbEncT), resRnbEncT.length)); 

// decrypt RndB 
byte[] resRnbDec = MyDES.decrypt(resRnbEncT); 
_responseTextView.append(String.format("-resRnbDec: %s length:%d\n", BytesToHexStr(resRnbDec), resRnbDec.length)); 

// generate RndA 
byte[] Rna = new byte[8]; 
new SecureRandom().nextBytes(Rna); 
_responseTextView.append(String.format("-Rna: %s length:%d\n", BytesToHexStr(Rna), Rna.length)); 

// plain = concate RndA with resRnbDec 
byte[] plain = new byte[16]; 
System.arraycopy(Rna, 0, plain, 0, 8); 
System.arraycopy(resRnbDec, 0, plain, 8, 8); 
_responseTextView.append(String.format("-plain: %s length:%d\n", BytesToHexStr(plain), plain.length)); 

// cipher = encrypt plain 
byte[] cipher = MyDES.encrypt(plain); 
_responseTextView.append(String.format("-cipher: %s length:%d\n", BytesToHexStr(cipher), cipher.length)); 

// send cipher request 
byte[] reqCipher = new byte[22]; 
reqCipher[0] = (byte) 0x00; 
reqCipher[1] = (byte) 0x82; 
reqCipher[2] = (byte) 0x00; 
reqCipher[3] = (byte) 0x00; 
reqCipher[4] = (byte) cipher.length; 
System.arraycopy(cipher, 0, reqCipher, 5, cipher.length); 
reqCipher[21] = (byte) 0x00; 

// get response 
byte[] resCipher = _isoDep.transceive(reqCipher); 
_responseTextView.append(String.format("reqCipher: %s length:%d\n", BytesToHexStr(reqCipher), reqCipher.length)); 
_responseTextView.append(String.format("resCipher: %s length:%d\n", BytesToHexStr(resCipher), resCipher.length)); 

加密:

public class MyDES { 
private static String ENCRYPTION_KEY_TYPE = "DESede"; 
private static String ENCRYPTION_ALGORITHM = "DESede/CBC/NoPadding"; 

private static byte[] key = new byte[]{ 
     (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, (byte) 0x00, (byte) 0x00}; 

private static byte[] iv = new byte[]{ 
     (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}; 

public static byte[] encrypt(byte[] plainText) { 
    try { 
     IvParameterSpec ivSpec = new IvParameterSpec(iv); 
     SecretKey secretKey = new SecretKeySpec(key, ENCRYPTION_KEY_TYPE); 
     Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM); 
     cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec); 
     byte[] encrypted = cipher.doFinal(plainText); 
     return encrypted; 
    } catch (InvalidKeyException e) { 
     e.printStackTrace(); 
    } catch (InvalidAlgorithmParameterException e) { 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     e.printStackTrace(); 
    } catch (BadPaddingException e) { 
     e.printStackTrace(); 
    } catch (IllegalBlockSizeException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

public static byte[] decrypt(byte[] cipherText) { 
    try { 
     IvParameterSpec ivSpec = new IvParameterSpec(iv); 
     SecretKey secretKey = new SecretKeySpec(key, ENCRYPTION_KEY_TYPE); 
     Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM); 
     cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec); 
     byte[] decrypted = cipher.doFinal(cipherText); 
     return decrypted; 
    } catch (InvalidKeyException e) { 
     e.printStackTrace(); 
    } catch (InvalidAlgorithmParameterException e) { 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     e.printStackTrace(); 
    } catch (BadPaddingException e) { 
     e.printStackTrace(); 
    } catch (IllegalBlockSizeException e) { 
     e.printStackTrace(); 
    } 
    return null; 
} 

回答

0

外部鑑別命令必須不包含Le字段。由於您包含Le字段(編碼爲0x00的最後一個字節),您將收到錯誤的長度錯誤。所以,你的命令應該是:

00 82 00 00 10 B5 02 0B 80 4F 95 CB E7 8C A6 4D E9 C1 B1 23 A7 

而在代碼:

byte[] reqCipher = new byte[5 + cipher.length]; 
reqCipher[0] = (byte) 0x00; 
reqCipher[1] = (byte) 0x82; 
reqCipher[2] = (byte) 0x00; 
reqCipher[3] = (byte) 0x00; 
reqCipher[4] = (byte) (cipher.length & 0x0ff); 
System.arraycopy(cipher, 0, reqCipher, 5, cipher.length); 

ASLO確保你開始與人保財險主密鑰驗證之前選擇的主文件(主應用程序)(P2 = 0)。特別是Android可能先前選擇了另一個應用程序。

+0

謝謝先生。如何選擇PICC主密鑰(p2 = 0)?我不明白,我是nfc環境中的新人。 – sams

+0

P2是你寫入'reqCipher [3]'的東西。您當前使用0x00,因此使用PICC主密鑰。 –

+0

我在00 00 A4 04 00 07 D2 76 00 00 85 01 00認證過程中選擇了主應用程序。我收到錯誤6B00 – sams