15 Commits
Author SHA1 Message Date
Andrea Franz e2e7f698ac Update README.md 2019-05-01 16:37:08 +02:00
Andrea Franz 0801636e78 Update README.md 2019-04-10 00:48:30 +02:00
Michele Balistreri 5975f1d02d update the Android installer with newer applet and SDK 2019-04-05 16:20:19 +03:00
Michele Balistreri 83b418d73f bundle version 2.1.0 of the applet 2019-02-13 12:24:55 +03:00
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
21 changed files with 197 additions and 405 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>
+2 -10
View File
@@ -1,11 +1,3 @@
# 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.
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`.
[Download APK](https://github.com/status-im/smartcard-cap-installer-test/releases/download/0.0.1/app-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)
discountinued - use [https://github.com/status-im/keycard-cli](https://github.com/status-im/keycard-cli)
+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 220
versionName "2.2.0"
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:7ce0136'
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>
Binary file not shown.
Binary file not shown.
@@ -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>