11 Commits
Author SHA1 Message Date
Michele Balistreri 086cc77f67 add installation without init 2019-01-11 13:56:26 +03:00
Michele Balistreri 5ea1a2397b applet can now be loaded also on "fresh" JCOP cards 2018-12-29 11:53:13 +03:00
Michele Balistreri 7511d3ea6c version 2.0.0 2018-12-14 14:44:18 +03:00
Michele Balistreri a9982c5fdc add iml file back to ignored files 2018-12-12 10:26:48 +03:00
Michele Balistreri 73192b3ba0 update README 2018-12-12 10:22:28 +03:00
Bitgamma a22528dc0f Merge pull request #13 from status-im/nfc-spot
bump version to 0.0.7
2018-12-12 10:12:36 +03:00
Andrea Franz ffd5b1a83f bump version to 0.0.7 2018-12-11 15:59:30 +01:00
Bitgamma dc2171f1dd Merge pull request #12 from status-im/nfc-spot
add button to show nfc spot
2018-12-11 17:59:03 +03:00
Andrea Franz c91e4d7848 check if NFCSpot is available 2018-12-11 15:48:12 +01:00
Andrea Franz c8f13db627 add button to show nfc spot 2018-12-11 14:57:55 +01:00
Bitgamma 98caa6106e rename to keycard (#11)
* rename to keycard

* clean imports

* update to latest SDK

* use unified SDK
2018-12-11 14:30:01 +01:00
20 changed files with 202 additions and 402 deletions
+2 -11
View File
@@ -1,6 +1,7 @@
/local.properties
/.idea/modules.xml
/.idea
/build
*.iml
# Built application files
*.apk
@@ -36,16 +37,6 @@ proguard/
# Android Studio captures folder
captures/
# IntelliJ
*.iml
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/assetWizardSettings.xml
.idea/dictionaries
.idea/libraries
.idea/caches
# Keystore files
# Uncomment the following line if you do not want to check your keystore files in.
#*.jks
-29
View File
@@ -1,29 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C-extensions>
<file>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" />
</file>
<class>
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" />
<option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" />
</class>
<extensions>
<pair source="cpp" header="h" fileNamingConvention="NONE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
</code_scheme>
</component>
-45
View File
@@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="android.support.annotation.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
<item index="9" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="javax.validation.constraints.NotNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
<item index="9" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
Generated
-6
View File
@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
+7 -7
View File
@@ -1,11 +1,11 @@
# smartcard-cap-installer-test
# Keycard Installer for Android
This is an android application that implements the basic APDU commands and secure channel to be able to install our [hardware wallet cap](https://github.com/status-im/hardware-wallet)
to a smartcard via NFC.
This is an Android application to install the [keycard applet](https://github.com/status-im/status-keycard) to a
smartcard via NFC. The compiled cap file of the applet is bundled in the application. Currently, version 2.0 of the
applet is installed.
The Purpose of it is to be able to start testing smartcards and NFC connection with different cards and readers.
This can help with UX/UI design while we implement the final solution in `status-react` and `status-go`.
If you work with the Status Keycard this is a quick utility to reinstall the applet.
[Download APK](https://github.com/status-im/smartcard-cap-installer-test/releases/download/0.0.1/app-debug.apk)
[Download APK](https://github.com/status-im/keycard-installer-android/releases/download/2.0.0/keycard-installer-debug.apk)
![https://github.com/status-im/smartcard-cap-installer-test/blob/master/docs/demo.gif?raw=true](https://github.com/status-im/smartcard-cap-installer-test/blob/master/docs/demo.gif?raw=true)
![https://github.com/status-im/keycard-installer-android/blob/master/docs/demo.gif?raw=true](https://github.com/status-im/keycard-installer-android/blob/master/docs/demo.gif?raw=true)
+5 -6
View File
@@ -3,11 +3,11 @@ apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "im.status.applet_installer_test.appletinstaller"
applicationId "im.status.keycard_installer.installer"
minSdkVersion 19
targetSdkVersion 27
versionCode 6
versionName "0.0.6"
versionCode 202
versionName "2.0.2"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
@@ -22,9 +22,8 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
implementation 'com.madgag.spongycastle:core:1.58.0.0'
implementation 'com.madgag.spongycastle:prov:1.58.0.0'
implementation 'com.github.status-im:hardwallet-lite-android:c749e5a'
implementation 'com.github.status-im.status-keycard-java:android:2.0.0'
implementation 'de.cotech:nfc-sweetspot:1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
@@ -1,26 +0,0 @@
package im.status.applet_installer_test.appletinstaller;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("im.status.applet_installer_test.appletinstaller", appContext.getPackageName());
}
}
+7 -2
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="im.status.applet_installer_test.appletinstaller">
package="im.status.keycard.installer">
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce"
@@ -13,13 +13,18 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<activity android:name="im.status.keycard.installer.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="de.cotech.sweetspot.ShowNfcSweetspotActivity"
android:exported="false"
/>
</application>
</manifest>
@@ -1,30 +0,0 @@
package im.status.applet_installer_test.appletinstaller;
public class HexUtils {
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len/2];
for(int i = 0; i < len; i+=2){
data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
}
return data;
}
final protected static char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
public static String byteArrayToHexString(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
int v;
for(int j=0; j < bytes.length; j++) {
v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v>>>4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
@@ -1,103 +0,0 @@
package im.status.applet_installer_test.appletinstaller;
import android.content.res.AssetManager;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import im.status.hardwallet_lite_android.globalplatform.Load;
import im.status.hardwallet_lite_android.io.APDUException;
import im.status.hardwallet_lite_android.io.APDUResponse;
import im.status.hardwallet_lite_android.io.CardChannel;
import im.status.hardwallet_lite_android.globalplatform.ApplicationID;
import im.status.hardwallet_lite_android.globalplatform.GlobalPlatformCommandSet;
import im.status.hardwallet_lite_android.wallet.WalletAppletCommandSet;
public class Installer {
private CardChannel plainChannel;
private AssetManager assets;
private String capPath;
static final byte[] PACKAGE_AID = HexUtils.hexStringToByteArray("53746174757357616C6C6574");
static final byte[] WALLET_AID = HexUtils.hexStringToByteArray("53746174757357616C6C6574417070");
static final byte[] NDEF_APPLET_AID = HexUtils.hexStringToByteArray("53746174757357616C6C65744E4643");
static final byte[] NDEF_INSTANCE_AID = HexUtils.hexStringToByteArray("D2760000850101");
private GlobalPlatformCommandSet cmdSet;
private boolean testSecrets;
public Installer(CardChannel channel, AssetManager assets, String capPath, boolean testSecrets) {
this.plainChannel = channel;
this.assets = assets;
this.capPath = capPath;
this.testSecrets = testSecrets;
}
public void start() throws IOException, APDUException, NoSuchAlgorithmException, InvalidKeySpecException {
Logger.i("installation started...");
long startTime = System.currentTimeMillis();
Logger.i("auto select sdaid...");
cmdSet = new GlobalPlatformCommandSet(this.plainChannel);
ApplicationID sdaid = new ApplicationID(cmdSet.select().checkOK().getData());
SecureRandom random = new SecureRandom();
byte hostChallenge[] = new byte[8];
random.nextBytes(hostChallenge);
Logger.i("initialize update...");
cmdSet.initializeUpdate(hostChallenge).checkOK();
Logger.i("external authenticate...");
cmdSet.externalAuthenticate(hostChallenge).checkOK();
Logger.i("delete NDEF instance AID...");
cmdSet.delete(NDEF_INSTANCE_AID).checkSW(APDUResponse.SW_OK, APDUResponse.SW_REFERENCED_DATA_NOT_FOUND);
Logger.i("delete wallet AID...");
cmdSet.delete(WALLET_AID).checkSW(APDUResponse.SW_OK, APDUResponse.SW_REFERENCED_DATA_NOT_FOUND);
Logger.i("delete package AID...");
cmdSet.delete(PACKAGE_AID).checkSW(APDUResponse.SW_OK, APDUResponse.SW_REFERENCED_DATA_NOT_FOUND);
Logger.i("install for load...");
cmdSet.installForLoad(PACKAGE_AID, sdaid.getAID()).checkSW(APDUResponse.SW_OK, APDUResponse.SW_REFERENCED_DATA_NOT_FOUND);
InputStream in = this.assets.open(this.capPath);
Load load = new Load(in);
byte[] block;
int steps = load.blocksCount();
while((block = load.nextDataBlock()) != null) {
int count = load.getCount() - 1;
Logger.i(String.format("load %d/%d...", count + 1, steps));
cmdSet.load(block, count, load.hasMore()).checkOK();
}
Logger.i("install for install ndef...");
byte[] params = HexUtils.hexStringToByteArray("0024d40f12616e64726f69642e636f6d3a706b67696d2e7374617475732e657468657265756d");
cmdSet.installForInstall(PACKAGE_AID, NDEF_APPLET_AID, NDEF_INSTANCE_AID, params).checkOK();
Logger.i("install for install wallet...");
cmdSet.installForInstall(PACKAGE_AID, WALLET_AID, WALLET_AID, new byte[0]).checkOK();
this.personalizeApplet();
long duration = System.currentTimeMillis() - startTime;
Logger.i(String.format("\n\ninstallation completed in %d seconds", duration / 1000));
}
private void personalizeApplet() throws NoSuchAlgorithmException, InvalidKeySpecException, APDUException, IOException {
Secrets secrets = testSecrets ? Secrets.testSecrets() : Secrets.generate();
WalletAppletCommandSet cmdSet = new WalletAppletCommandSet(this.plainChannel);
cmdSet.select().checkOK();
cmdSet.init(secrets.getPin(), secrets.getPuk(), secrets.getPairingToken()).checkOK();
Logger.i(String.format("PIN: %s\nPUK: %s\nPairing password: %s\nPairing token: %s", secrets.getPin(), secrets.getPuk(), secrets.getPairingPassword(), HexUtils.byteArrayToHexString(secrets.getPairingToken())));
}
}
@@ -1,90 +0,0 @@
package im.status.applet_installer_test.appletinstaller;
import android.support.annotation.NonNull;
import android.util.Base64;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import static android.util.Base64.NO_PADDING;
public class Secrets {
private String pin;
private String puk;
private String pairingPassword;
private byte[] pairingToken;
private static long PIN_BOUND = 999999L;
private static long PUK_BOUND = 999999999999L;
public Secrets(String pin, String puk, String pairingPassword, byte[] pairingToken) {
this.pin = pin;
this.puk = puk;
this.pairingPassword = pairingPassword;
this.pairingToken = pairingToken;
}
@NonNull
public static Secrets generate() throws NoSuchAlgorithmException, InvalidKeySpecException {
String pairingPassword = randomToken(12);
byte[] pairingToken = generatePairingKey(pairingPassword.toCharArray());
long pinNumber = randomLong(PIN_BOUND);
long pukNumber = randomLong(PUK_BOUND);
String pin = String.format("%06d", pinNumber);
String puk = String.format("%012d", pukNumber);
return new Secrets(pin, puk, pairingPassword, pairingToken);
}
public static Secrets testSecrets() throws NoSuchAlgorithmException, InvalidKeySpecException {
String pairingPassword = "WalletAppletTest";
byte[] pairingToken = generatePairingKey(pairingPassword.toCharArray());
return new Secrets("000000", "123456789012", pairingPassword, pairingToken);
}
public String getPin() {
return pin;
}
public String getPuk() {
return puk;
}
public String getPairingPassword() {
return pairingPassword;
}
public byte[] getPairingToken() {
return pairingToken;
}
public static byte[] randomBytes(int length) {
SecureRandom random = new SecureRandom();
byte data[] = new byte[length];
random.nextBytes(data);
return data;
}
public static String randomToken(int length) {
return Base64.encodeToString(randomBytes(length), NO_PADDING);
}
public static long randomLong(long bound) {
SecureRandom random = new SecureRandom();
return Math.abs(random.nextLong()) % bound;
}
public static byte[] generatePairingKey(char[] pairing) throws NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
String salt = "Status Hardware Wallet Lite";
PBEKeySpec spec = new PBEKeySpec(pairing, salt.getBytes(), 50000, 32*8);
SecretKey key = skf.generateSecret(spec);
return key.getEncoded();
}
}
@@ -1,12 +1,9 @@
package im.status.applet_installer_test.appletinstaller;
package im.status.keycard.installer;
import android.content.res.AssetManager;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import im.status.hardwallet_lite_android.io.APDUException;
import im.status.hardwallet_lite_android.io.CardChannel;
import im.status.hardwallet_lite_android.io.CardListener;
import im.status.keycard.io.APDUException;
import im.status.keycard.io.CardChannel;
import im.status.keycard.io.CardListener;
import java.io.IOException;
import java.util.Timer;
@@ -0,0 +1,75 @@
package im.status.keycard.installer;
import android.content.res.AssetManager;
import im.status.keycard.applet.KeycardCommandSet;
import im.status.keycard.globalplatform.GlobalPlatformCommandSet;
import im.status.keycard.globalplatform.LoadCallback;
import im.status.keycard.io.APDUException;
import im.status.keycard.io.CardChannel;
import org.bouncycastle.util.encoders.Hex;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
public class Installer {
private CardChannel plainChannel;
private AssetManager assets;
private String capPath;
private GlobalPlatformCommandSet cmdSet;
private boolean testSecrets;
public Installer(CardChannel channel, AssetManager assets, String capPath, boolean testSecrets) {
this.plainChannel = channel;
this.assets = assets;
this.capPath = capPath;
this.testSecrets = testSecrets;
}
public void start() throws IOException, APDUException, NoSuchAlgorithmException, InvalidKeySpecException {
Logger.i("installation started...");
long startTime = System.currentTimeMillis();
Logger.i("select ISD...");
cmdSet = new GlobalPlatformCommandSet(this.plainChannel);
cmdSet.select().checkOK();
Logger.i("opening secure channel...");
cmdSet.openSecureChannel();
Logger.i("deleting old version (if present)...");
cmdSet.deleteKeycardInstancesAndPackage();
Logger.i("loading package...");
cmdSet.loadKeycardPackage(this.assets.open(this.capPath), new LoadCallback() {
public void blockLoaded(int loadedBlock, int blockCount) {
Logger.i(String.format("load %d/%d...", loadedBlock, blockCount));
}
});
Logger.i("installing NDEF applet...");
cmdSet.installNDEFApplet(Hex.decode("0024d40f12616e64726f69642e636f6d3a706b67696d2e7374617475732e657468657265756d")).checkOK();
Logger.i("installing Keycard applet...");
cmdSet.installKeycardApplet().checkOK();
if (testSecrets) {
this.personalizeApplet();
}
long duration = System.currentTimeMillis() - startTime;
Logger.i(String.format("\n\ninstallation completed in %d seconds", duration / 1000));
}
private void personalizeApplet() throws NoSuchAlgorithmException, InvalidKeySpecException, APDUException, IOException {
Secrets secrets = Secrets.testSecrets();
KeycardCommandSet cmdSet = new KeycardCommandSet(this.plainChannel);
cmdSet.select().checkOK();
cmdSet.init(secrets.getPin(), secrets.getPuk(), secrets.getPairingPassword()).checkOK();
Logger.i(String.format("PIN: %s\nPUK: %s\nPairing password: %s", secrets.getPin(), secrets.getPuk(), secrets.getPairingPassword()));
}
}
@@ -1,4 +1,4 @@
package im.status.applet_installer_test.appletinstaller;
package im.status.keycard.installer;
import android.util.Log;
@@ -1,24 +1,21 @@
package im.status.applet_installer_test.appletinstaller;
package im.status.keycard.installer;
import android.content.Intent;
import android.content.res.AssetManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.nfc.NfcAdapter;
import android.text.method.ScrollingMovementMethod;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;
import im.status.hardwallet_lite_android.io.CardManager;
import java.security.Security;
import de.cotech.sweetspot.NfcSweetspotData;
import im.status.keycard.android.NFCCardManager;
import de.cotech.sweetspot.ShowNfcSweetspotActivity;
public class MainActivity extends AppCompatActivity implements UILogger {
static {
Security.insertProviderAt(new org.spongycastle.jce.provider.BouncyCastleProvider(), 1);
}
private NfcAdapter nfcAdapter;
private TextView textView;
private ScrollView textViewScroll;
@@ -26,8 +23,9 @@ public class MainActivity extends AppCompatActivity implements UILogger {
private Button buttonInstall;
private Button buttonInstallTest;
private Button buttonPerfTest;
private Button buttonNFCSpot;
private ActionRunner actionRunner;
private CardManager cardManager;
private NFCCardManager cardManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -37,8 +35,8 @@ public class MainActivity extends AppCompatActivity implements UILogger {
Logger.setUILogger(this);
AssetManager assets = this.getAssets();
this.actionRunner = new ActionRunner(assets, "wallet.cap");
this.cardManager = new CardManager();
this.actionRunner = new ActionRunner(assets, "keycard.cap");
this.cardManager = new NFCCardManager();
this.cardManager.setCardListener(this.actionRunner);
cardManager.start();
@@ -68,6 +66,18 @@ public class MainActivity extends AppCompatActivity implements UILogger {
requestAction(ActionRunner.ACTION_PERFTEST);
}
});
buttonNFCSpot = (Button) findViewById(R.id.buttonNFCSpot);
buttonNFCSpot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent(MainActivity.this, ShowNfcSweetspotActivity.class);
startActivity(i);
}
});
if (NfcSweetspotData.hasSweetspotData()) {
buttonNFCSpot.setEnabled(true);
}
//Logger.setUILevel(Log.INFO);
//Logger.setLevel(Log.INFO);
@@ -1,19 +1,15 @@
package im.status.applet_installer_test.appletinstaller;
package im.status.keycard.installer;
import android.util.Log;
import im.status.hardwallet_lite_android.io.CardChannel;
import im.status.hardwallet_lite_android.wallet.WalletAppletCommandSet;
import org.spongycastle.jce.ECNamedCurveTable;
import org.spongycastle.jce.spec.ECParameterSpec;
import im.status.keycard.io.CardChannel;
import im.status.keycard.applet.KeycardCommandSet;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Random;
import java.security.SecureRandom;
public class PerfTest {
private CardChannel cardChannel;
private WalletAppletCommandSet cmdSet;
private KeycardCommandSet cmdSet;
private long openSecureChannelTime = 0;
private long loadKeysTime = 0;
@@ -28,11 +24,10 @@ public class PerfTest {
}
public void test() throws Exception {
cmdSet = new WalletAppletCommandSet(cardChannel);
cmdSet = new KeycardCommandSet(cardChannel);
cmdSet.select().checkOK();
String pairingPassword = "WalletAppletTest";
cmdSet.autoPair(cmdSet.pairingPasswordToSecret(pairingPassword));
cmdSet.autoPair(cmdSet.pairingPasswordToSecret(Secrets.testSecrets().getPairingPassword()));
openSecureChannelTime = System.currentTimeMillis();
cmdSet.autoOpenSecureChannel();
openSecureChannelTime = System.currentTimeMillis() - openSecureChannelTime;
@@ -69,7 +64,7 @@ public class PerfTest {
long time = System.currentTimeMillis();
cmdSet.select().checkOK();
cmdSet.autoOpenSecureChannel();
cmdSet.getStatus(WalletAppletCommandSet.GET_STATUS_P1_APPLICATION).checkOK();
cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_APPLICATION).checkOK();
getStatusTime = System.currentTimeMillis() - time;
}
@@ -84,12 +79,10 @@ public class PerfTest {
}
private void loadKeys() throws Exception {
KeyPairGenerator g = keypairGenerator();
KeyPair keyPair = g.generateKeyPair();
byte[] chainCode = new byte[32];
new Random().nextBytes(chainCode);
byte[] seed = new byte[64];
new SecureRandom().nextBytes(seed);
cmdSet.loadKey(keyPair, false, chainCode).checkOK();
cmdSet.loadKey(seed).checkOK();
long time = System.currentTimeMillis();
cmdSet.deriveKey(BIP44_WALLET_PATH).checkOK();
@@ -104,12 +97,4 @@ public class PerfTest {
cmdSet.sign("any32bytescanbeahashyouknowthat!".getBytes()).checkOK();
signTime = System.currentTimeMillis() - time;
}
private KeyPairGenerator keypairGenerator() throws Exception {
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
KeyPairGenerator g = KeyPairGenerator.getInstance("ECDH");
g.initialize(ecSpec);
return g;
}
}
@@ -0,0 +1,60 @@
package im.status.keycard.installer;
import android.util.Base64;
import im.status.keycard.globalplatform.Crypto;
import java.security.SecureRandom;
import static android.util.Base64.NO_PADDING;
import static im.status.keycard.globalplatform.Crypto.randomLong;
public class Secrets {
private String pin;
private String puk;
private String pairingPassword;
public Secrets(String pin, String puk, String pairingPassword) {
this.pin = pin;
this.puk = puk;
this.pairingPassword = pairingPassword;
}
public static Secrets generate() {
String pairingPassword = randomToken(12);
long pinNumber = randomLong(Crypto.PIN_BOUND);
long pukNumber = randomLong(Crypto.PUK_BOUND);
String pin = String.format("%06d", pinNumber);
String puk = String.format("%012d", pukNumber);
return new Secrets(pin, puk, pairingPassword);
}
public static Secrets testSecrets() {
String pairingPassword = "KeycardTest";
return new Secrets("000000", "123456789012", pairingPassword);
}
public String getPin() {
return pin;
}
public String getPuk() {
return puk;
}
public String getPairingPassword() {
return pairingPassword;
}
public static byte[] randomBytes(int length) {
SecureRandom random = new SecureRandom();
byte data[] = new byte[length];
random.nextBytes(data);
return data;
}
public static String randomToken(int length) {
return Base64.encodeToString(randomBytes(length), NO_PADDING);
}
}
+8 -1
View File
@@ -27,7 +27,7 @@
android:id="@+id/buttonInstall"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Install Secure"/>
android:text="Install w/o INIT"/>
<Button
android:id="@+id/buttonInstallTest"
@@ -40,4 +40,11 @@
android:layout_height="wrap_content"
android:text="Perf Test" />
<Button
android:id="@+id/buttonNFCSpot"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="NFC Spot"
android:enabled="false" />
</LinearLayout>
+1 -1
View File
@@ -1,3 +1,3 @@
<resources>
<string name="app_name">AppletInstaller</string>
<string name="app_name">KeycardInstaller</string>
</resources>