add initial Installer class
This commit is contained in:
parent
d5301304eb
commit
a8e2f27624
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package im.status.applet_installer_test.appletinstaller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface Channel {
|
||||||
|
byte[] transceive(byte[] data) throws IOException;
|
||||||
|
}
|
|
@ -15,7 +15,6 @@ 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 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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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));
|
||||||
|
}
|
||||||
|
}
|
|
@ -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.APDUResponse;
|
||||||
import im.status.applet_installer_test.appletinstaller.Crypto;
|
import im.status.applet_installer_test.appletinstaller.Crypto;
|
||||||
import im.status.applet_installer_test.appletinstaller.HexUtils;
|
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 class InitializeUpdate {
|
||||||
public static final int CLA = 0x80;
|
public static final int CLA = 0x80;
|
||||||
|
@ -36,7 +38,7 @@ public class InitializeUpdate {
|
||||||
return challenge;
|
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) {
|
if (resp.getSw() == APDUResponse.SW_SECURITY_CONDITION_NOT_SATISFIED) {
|
||||||
throw new APDUException(resp.getSw(), "security confition not satisfied");
|
throw new APDUException(resp.getSw(), "security confition not satisfied");
|
||||||
}
|
}
|
||||||
|
@ -57,9 +59,17 @@ public class InitializeUpdate {
|
||||||
byte[] cardCryptogram = new byte[8];
|
byte[] cardCryptogram = new byte[8];
|
||||||
System.arraycopy(data, 20, cardCryptogram, 0, 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue