add initial Installer class

This commit is contained in:
Andrea Franz 2018-08-30 12:19:32 +02:00
parent d5301304eb
commit a8e2f27624
No known key found for this signature in database
GPG Key ID: 4F0D2F2D9DE7F29D
8 changed files with 136 additions and 4 deletions

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,7 @@
package im.status.applet_installer_test.appletinstaller;
import java.io.IOException;
public interface Channel {
byte[] transceive(byte[] data) throws IOException;
}

View File

@ -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) {

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}