add cryptogram verification

This commit is contained in:
Andrea Franz 2018-08-27 17:07:47 +02:00
parent 184f7bca80
commit 01af228057
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
3 changed files with 60 additions and 15 deletions

View File

@ -1,8 +1,11 @@
package im.status.applet_installer_test.appletinstaller; package im.status.applet_installer_test.appletinstaller;
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException; import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.BadPaddingException; import javax.crypto.BadPaddingException;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException; import javax.crypto.IllegalBlockSizeException;
@ -12,10 +15,11 @@ import javax.crypto.spec.SecretKeySpec;
public class Crypto { public class Crypto {
public static final byte[] NullBytes8 = new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
public static byte[] deriveKey(byte[] cardKey, byte[] seq, byte[] purposeData) { public static byte[] deriveKey(byte[] cardKey, byte[] seq, byte[] purposeData) {
byte[] key24 = new byte[24]; byte[] key24 = resizeKey24(cardKey);
System.arraycopy(cardKey, 0, key24, 0, 16);
System.arraycopy(cardKey, 0, key24, 16, 8);
try { try {
byte[] derivationData = new byte[16]; byte[] derivationData = new byte[16];
@ -24,10 +28,10 @@ public class Crypto {
// 2 bytes sequence counter + 12 bytes 0x00 // 2 bytes sequence counter + 12 bytes 0x00
System.arraycopy(seq, 0, derivationData, 2, 2); System.arraycopy(seq, 0, derivationData, 2, 2);
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
IvParameterSpec iv = new IvParameterSpec(new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
SecretKeySpec tmpKey = new SecretKeySpec(key24, "DESede"); SecretKeySpec tmpKey = new SecretKeySpec(key24, "DESede");
cipher.init(Cipher.ENCRYPT_MODE, tmpKey, iv);
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, tmpKey, new IvParameterSpec(NullBytes8));
return cipher.doFinal(derivationData); return cipher.doFinal(derivationData);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) { } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
@ -39,11 +43,51 @@ public class Crypto {
public static byte[] appendDESPadding(byte[] data) { public static byte[] appendDESPadding(byte[] data) {
int length = data.length + 1; int length = data.length + 1;
for (; length % 8 != 0; length++){} for (; length % 8 != 0; length++){
}
byte[] newData = new byte[length]; byte[] newData = new byte[length];
System.arraycopy(data, 0, newData, 0, data.length); System.arraycopy(data, 0, newData, 0, data.length);
newData[data.length] = (byte)0x80; newData[data.length] = (byte)0x80;
return newData; return newData;
} }
public static boolean verifyCryptogram(byte[] key, byte[] hostChallenge, byte[] cardChallenge, byte[] cardCryptogram) {
byte[] data = new byte[hostChallenge.length + cardChallenge.length];
System.arraycopy(hostChallenge, 0, data, 0, hostChallenge.length);
System.arraycopy(cardChallenge, 0, data, hostChallenge.length, cardChallenge.length);
byte[] paddedData = appendDESPadding(data);
byte[] calculated = mac3des(key, paddedData, NullBytes8);
return Arrays.equals(calculated , cardCryptogram);
}
public static byte[] mac3des(byte[] keyData, byte[] data, byte[] iv) {
try {
SecretKeySpec key = new SecretKeySpec(resizeKey24(keyData), "DESede");
Cipher cipher = Cipher.getInstance("DESede/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] result = cipher.doFinal(data, 0, 24);
byte[] tail = new byte[8];
System.arraycopy(result, 16, tail, 0, 8);
return tail;
} catch (GeneralSecurityException e) {
throw new RuntimeException("error calculating mac.", e);
}
}
public static byte[] resizeKey24(byte[] keyData) {
byte[] key = new byte[24];
System.arraycopy(keyData, 0, key, 0, 16);
System.arraycopy(keyData, 0, key, 16, 8);
return key;
}
public static byte[] resizeKey8(byte[] keyData) {
byte[] key = new byte[8];
System.arraycopy(keyData, 0, key, 0, 8);
return key;
}
} }

View File

@ -31,4 +31,13 @@ public class CryptoTest {
String expected = "AABB800000000000"; String expected = "AABB800000000000";
assertEquals(expected, HexUtils.byteArrayToHexString(result)); assertEquals(expected, HexUtils.byteArrayToHexString(result));
} }
@Test
public void verifyCryptogram() {
byte[] encKey = HexUtils.hexStringToByteArray("16B5867FF50BE7239C2BF1245B83A362");
byte[] hostChallenge = HexUtils.hexStringToByteArray("32da078d7aac1cff");
byte[] cardChallenge = HexUtils.hexStringToByteArray("007284f64a7d6465");
byte[] cardCryptogram = HexUtils.hexStringToByteArray("05c4bb8a86014e22");
assertTrue(Crypto.verifyCryptogram(encKey, hostChallenge, cardChallenge, cardCryptogram));
}
} }

View File

@ -23,14 +23,6 @@ public class InitializeUpdateTest {
assertEquals(challenge, cmd.getData()); assertEquals(challenge, cmd.getData());
} }
@Test
public void verifyCryptogram() {
byte[] encKey = HexUtils.hexStringToByteArray("A08DF4027BD8ACC9BD89DA2760909D09");
byte[] cardCryptogram = HexUtils.hexStringToByteArray("1cd15bd25265c990");
byte[] hostChallenge = HexUtils.hexStringToByteArray("13e7a37b30ef2c22");
byte[] cardChallenge = HexUtils.hexStringToByteArray("0066ef6b33b04b11");
}
@Test @Test
public void validateResponse_BadResponse() throws APDUException { public void validateResponse_BadResponse() throws APDUException {
byte[] apdu = HexUtils.hexStringToByteArray("000002650183039536622002003b5e508f751c0af3016e3fbc23d3a66982"); byte[] apdu = HexUtils.hexStringToByteArray("000002650183039536622002003b5e508f751c0af3016e3fbc23d3a66982");