diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/CardChannel.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/CardChannel.java new file mode 100644 index 0000000..ad8db5e --- /dev/null +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/CardChannel.java @@ -0,0 +1,22 @@ +package im.status.applet_installer_test.appletinstaller; + +import android.nfc.tech.IsoDep; + +import java.io.IOException; + +import im.status.applet_installer_test.appletinstaller.CardManager; + +public class CardChannel implements Channel { + private IsoDep isoDep; + + public CardChannel(IsoDep isoDep) { + this.isoDep = isoDep; + } + + public byte[] transceive(byte[] data) throws IOException { + Logger.log(String.format("COMMAND %s %n", HexUtils.byteArrayToHexString(data))); + byte[] resp = this.isoDep.transceive(data); + Logger.log(String.format("RESPONSE %s %n", HexUtils.byteArrayToHexString(resp))); + return resp; + } +} diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/CardManager.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/CardManager.java new file mode 100644 index 0000000..47c3fa5 --- /dev/null +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/CardManager.java @@ -0,0 +1,26 @@ +package im.status.applet_installer_test.appletinstaller; + +import android.nfc.Tag; +import android.nfc.tech.IsoDep; + +import java.io.IOException; + +public class CardManager { + private Tag tag; + private IsoDep isoDep; + + public CardManager(Tag tag) { + this.tag = tag; + } + + public void connect() throws IOException { + this.isoDep = IsoDep.get(tag); + this.isoDep.connect(); + } + + public void install() throws IOException, APDUException { + CardChannel ch = new CardChannel(this.isoDep); + Installer installer = new Installer(ch); + installer.start(); + } +} diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/Channel.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Channel.java new file mode 100644 index 0000000..ee049bb --- /dev/null +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Channel.java @@ -0,0 +1,7 @@ +package im.status.applet_installer_test.appletinstaller; + +import java.io.IOException; + +public interface Channel { + byte[] transceive(byte[] data) throws IOException; +} diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/Crypto.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Crypto.java index cfd1ba1..6c5fb36 100644 --- a/app/src/main/java/im/status/applet_installer_test/appletinstaller/Crypto.java +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Crypto.java @@ -15,7 +15,6 @@ import javax.crypto.spec.SecretKeySpec; 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) { diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/Installer.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Installer.java new file mode 100644 index 0000000..950c828 --- /dev/null +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Installer.java @@ -0,0 +1,36 @@ +package im.status.applet_installer_test.appletinstaller; + +import java.io.IOException; +import java.security.SecureRandom; + +import im.status.applet_installer_test.appletinstaller.apducommands.InitializeUpdate; + +public class Installer { + private Channel channel; + + static final byte[] cardKeyData = HexUtils.hexStringToByteArray("404142434445464748494a4b4c4d4e4f"); + + private Keys cardKeys; + + public Installer(Channel channel) { + this.channel = channel; + this.cardKeys = new Keys(cardKeyData, cardKeyData); + } + + public void start() throws IOException, APDUException { + SecureRandom random = new SecureRandom(); + byte hostChallenge[] = new byte[8]; + random.nextBytes(hostChallenge); + InitializeUpdate init = new InitializeUpdate(hostChallenge); + byte[] data = init.getCommand().serialize(); + + // get data + //byte[] data = new byte[]{(byte) 0x80, (byte) 0xCA, 0x00, (byte) 0x66}; + + byte[] respData = this.channel.transceive(data); + APDUResponse resp = new APDUResponse(respData); + Logger.log(respData); + + Keys keys = init.verifyResponse(this.cardKeys, resp); + } +} diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/Keys.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Keys.java new file mode 100644 index 0000000..c6f9e76 --- /dev/null +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Keys.java @@ -0,0 +1,19 @@ +package im.status.applet_installer_test.appletinstaller; + +public class Keys { + public byte[] encKeyData; + public byte[] macKeyData; + + public Keys(byte[] encKeyData, byte[] macKeyData) { + this.encKeyData = encKeyData; + this.macKeyData = macKeyData; + } + + public byte[] getEncKeyData() { + return encKeyData; + } + + public byte[] getMacKeyData() { + return macKeyData; + } +} diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/Logger.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Logger.java new file mode 100644 index 0000000..2b5d7f0 --- /dev/null +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/Logger.java @@ -0,0 +1,13 @@ +package im.status.applet_installer_test.appletinstaller; + +import android.util.Log; + +public class Logger { + public static void log(String m) { + Log.d("installer-debug", m); + } + + public static void log(byte[] m) { + Log.d("installer-debug", HexUtils.byteArrayToHexString(m)); + } +} diff --git a/app/src/main/java/im/status/applet_installer_test/appletinstaller/apducommands/InitializeUpdate.java b/app/src/main/java/im/status/applet_installer_test/appletinstaller/apducommands/InitializeUpdate.java index 7361c08..6879ae0 100644 --- a/app/src/main/java/im/status/applet_installer_test/appletinstaller/apducommands/InitializeUpdate.java +++ b/app/src/main/java/im/status/applet_installer_test/appletinstaller/apducommands/InitializeUpdate.java @@ -7,6 +7,8 @@ import im.status.applet_installer_test.appletinstaller.APDUException; import im.status.applet_installer_test.appletinstaller.APDUResponse; import im.status.applet_installer_test.appletinstaller.Crypto; import im.status.applet_installer_test.appletinstaller.HexUtils; +import im.status.applet_installer_test.appletinstaller.Keys; +import im.status.applet_installer_test.appletinstaller.Logger; public class InitializeUpdate { public static final int CLA = 0x80; @@ -36,7 +38,7 @@ public class InitializeUpdate { return challenge; } - public boolean validateResponse(byte[] encKeyData, APDUResponse resp) throws APDUException { + public Keys verifyResponse(Keys cardKeys, APDUResponse resp) throws APDUException { if (resp.getSw() == APDUResponse.SW_SECURITY_CONDITION_NOT_SATISFIED) { throw new APDUException(resp.getSw(), "security confition not satisfied"); } @@ -57,9 +59,17 @@ public class InitializeUpdate { byte[] cardCryptogram = new byte[8]; System.arraycopy(data, 20, cardCryptogram, 0, 8); - return Crypto.verifyCryptogram(encKeyData, this.hostChallenge, cardChallenge, cardCryptogram); + byte[] seq = new byte[2]; + System.arraycopy(data, 12, seq, 0, 2); - //System.out.printf("key data: %s, %n", HexUtils.byteArrayToHexString(keyData)); + byte[] sessionEncKey = Crypto.deriveKey(cardKeys.getEncKeyData(), seq, DERIVATION_PURPOSE_ENC); + byte[] sessionMacKey = Crypto.deriveKey(cardKeys.getMacKeyData(), seq, DERIVATION_PURPOSE_MAC); + Keys sessionKeys = new Keys(sessionEncKey, sessionMacKey); + + boolean x = Crypto.verifyCryptogram(sessionKeys.getEncKeyData(), this.hostChallenge, cardChallenge, cardCryptogram); + Logger.log("VERIFIED: " + x); + + return sessionKeys; } }