diff --git a/ACardEmulator/app/app.iml b/ACardEmulator/app/app.iml index 37d5d64..abc25a2 100644 --- a/ACardEmulator/app/app.iml +++ b/ACardEmulator/app/app.iml @@ -90,9 +90,7 @@ - - @@ -108,14 +106,12 @@ - - @@ -127,8 +123,8 @@ - + diff --git a/ACardEmulator/app/build.gradle b/ACardEmulator/app/build.gradle index a1eb2b5..380911f 100644 --- a/ACardEmulator/app/build.gradle +++ b/ACardEmulator/app/build.gradle @@ -53,8 +53,8 @@ dependencies { compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:support-v4:23.0.1' compile 'com.android.support:design:23.2.1' - compile 'com.journeyapps:zxing-android-embedded:3.2.0@aar' compile 'com.google.zxing:core:3.2.1' - compile group: 'com.madgag.spongycastle', name: 'core', version: '1.51.0.0' + compile 'com.madgag.spongycastle:core:1.51.0.0' + compile files('libs/sdk-v1.0.0.jar') } diff --git a/ACardEmulator/app/libs/accessory-v2.3.2.jar b/ACardEmulator/app/libs/accessory-v2.3.2.jar new file mode 100644 index 0000000..107a3f5 Binary files /dev/null and b/ACardEmulator/app/libs/accessory-v2.3.2.jar differ diff --git a/ACardEmulator/app/libs/sdk-v1.0.0.jar b/ACardEmulator/app/libs/sdk-v1.0.0.jar new file mode 100644 index 0000000..070d65d Binary files /dev/null and b/ACardEmulator/app/libs/sdk-v1.0.0.jar differ diff --git a/ACardEmulator/app/src/main/AndroidManifest.xml b/ACardEmulator/app/src/main/AndroidManifest.xml index a78ad84..9cd3a62 100644 --- a/ACardEmulator/app/src/main/AndroidManifest.xml +++ b/ACardEmulator/app/src/main/AndroidManifest.xml @@ -6,6 +6,13 @@ + + + + + + + - @@ -47,6 +54,24 @@ + + + + + + + + + + + + + + diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorHostApduService.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorHostApduService.java new file mode 100644 index 0000000..a0fe639 --- /dev/null +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorHostApduService.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Frank Morgner + * + * This file is part of ACardEmulator. + * + * ACardEmulator is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * ACardEmulator is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * ACardEmulator. If not, see . + */ + +package com.vsmartcard.acardemulator; + +import android.content.Intent; +import android.nfc.cardemulation.HostApduService; +import android.os.Bundle; +import android.support.v4.content.LocalBroadcastManager; +import android.util.Log; + +import com.vsmartcard.acardemulator.emulators.EmulatorSingleton; + +public class EmulatorHostApduService extends HostApduService { + + @Override + public void onCreate() { + super.onCreate(); + EmulatorSingleton.createEmulator(this); + } + + @Override + public void onDestroy() { + super.onDestroy(); + } + + @Override + public byte[] processCommandApdu(byte[] capdu, Bundle extras) { + return EmulatorSingleton.process(this, capdu); + } + + @Override + public void onDeactivated(int reason) { + Intent i = new Intent(EmulatorSingleton.TAG); + + Log.d("", "End transaction"); + switch (reason) { + case DEACTIVATION_LINK_LOSS: + i.putExtra(EmulatorSingleton.EXTRA_DESELECT, "link lost"); + EmulatorSingleton.deactivate(); + break; + case DEACTIVATION_DESELECTED: + EmulatorSingleton.deactivate(); + break; + } + + LocalBroadcastManager.getInstance(this).sendBroadcast(i); + } +} diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java index e151d6e..28f9789 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/MainActivity.java @@ -41,6 +41,8 @@ import android.view.View; import android.widget.TextView; import android.widget.Toast; +import com.vsmartcard.acardemulator.emulators.EmulatorSingleton; + public class MainActivity extends AppCompatActivity { @@ -48,12 +50,12 @@ public class MainActivity extends AppCompatActivity { private BroadcastReceiver bReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(EmulatorService.TAG)) { - String capdu = intent.getStringExtra(EmulatorService.EXTRA_CAPDU); - String rapdu = intent.getStringExtra(EmulatorService.EXTRA_RAPDU); - String error = intent.getStringExtra(EmulatorService.EXTRA_ERROR); - String deselect = intent.getStringExtra(EmulatorService.EXTRA_DESELECT); - String install = intent.getStringExtra(EmulatorService.EXTRA_INSTALL); + if (intent.getAction().equals(EmulatorSingleton.TAG)) { + String capdu = intent.getStringExtra(EmulatorSingleton.EXTRA_CAPDU); + String rapdu = intent.getStringExtra(EmulatorSingleton.EXTRA_RAPDU); + String error = intent.getStringExtra(EmulatorSingleton.EXTRA_ERROR); + String deselect = intent.getStringExtra(EmulatorSingleton.EXTRA_DESELECT); + String install = intent.getStringExtra(EmulatorSingleton.EXTRA_INSTALL); if (install != null) textViewVPCDStatus.append(getResources().getString(R.string.status_install) + ":" + install + "\n"); if (capdu != null) @@ -102,7 +104,7 @@ public class MainActivity extends AppCompatActivity { if (emulator != getString(R.string.vicc)) { Snackbar.make(view, "Scheduled re-installation of all applets...", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); - EmulatorService.destroySimulator(getApplicationContext()); + EmulatorSingleton.destroyEmulator(); } } }); @@ -116,7 +118,7 @@ public class MainActivity extends AppCompatActivity { LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this); IntentFilter intentFilter = new IntentFilter(); - intentFilter.addAction(EmulatorService.TAG); + intentFilter.addAction(EmulatorSingleton.TAG); bManager.registerReceiver(bReceiver, intentFilter); } diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java index a108105..f7e7c94 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SettingsActivity.java @@ -200,6 +200,8 @@ public class SettingsActivity extends AppCompatPreferenceActivity { return true; } }); + + bindPreferenceSummaryToValue(findPreference("nfc")); } @Override diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SmartcardProviderService.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SmartcardProviderService.java new file mode 100644 index 0000000..2f8d948 --- /dev/null +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/SmartcardProviderService.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. All rights reserved. + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * Neither the name of Samsung Electronics Co., Ltd. nor the names of its contributors may be used to endorse + * or promote products derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +package com.vsmartcard.acardemulator; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.GregorianCalendar; + +import android.content.Intent; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.widget.Toast; +import android.util.Log; + +import com.samsung.android.sdk.SsdkUnsupportedException; +import com.samsung.android.sdk.accessory.*; +import com.vsmartcard.acardemulator.emulators.EmulatorSingleton; + +public class SmartcardProviderService extends SAAgent { + private static final String TAG = "HelloAccessory(P)"; + private static final int HELLOACCESSORY_CHANNEL_ID = 104; + private static final Class SASOCKET_CLASS = ServiceConnection.class; + private final IBinder mBinder = new LocalBinder(); + private ServiceConnection mConnectionHandler = null; + Handler mHandler = new Handler(); + + public SmartcardProviderService() { + super(TAG, SASOCKET_CLASS); + } + + @Override + public void onCreate() { + super.onCreate(); + SA mAccessory = new SA(); + try { + mAccessory.initialize(this); + EmulatorSingleton.createEmulator(this); + } catch (SsdkUnsupportedException e) { + // try to handle SsdkUnsupportedException + if (processUnsupportedException(e) == true) { + EmulatorSingleton.createEmulator(this); + return; + } + } catch (Exception e1) { + e1.printStackTrace(); + /* + * Your application can not use Samsung Accessory SDK. Your application should work smoothly + * without using this SDK, or you may want to notify user and close your application gracefully + * (release resources, stop Service threads, close UI thread, etc.) + */ + stopSelf(); + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + protected void onFindPeerAgentsResponse(SAPeerAgent[] peerAgents, int result) { + Log.d(TAG, "onFindPeerAgentResponse : result =" + result); + } + + @Override + protected void onServiceConnectionRequested(SAPeerAgent peerAgent) { + if (peerAgent != null) { + Toast.makeText(getBaseContext(), "connection accepted", Toast.LENGTH_SHORT).show(); + acceptServiceConnectionRequest(peerAgent); + } + } + + @Override + protected void onServiceConnectionResponse(SAPeerAgent peerAgent, SASocket socket, int result) { + if (result == SAAgent.CONNECTION_SUCCESS) { + if (socket != null) { + mConnectionHandler = (ServiceConnection) socket; + } + } else if (result == SAAgent.CONNECTION_ALREADY_EXIST) { + Log.e(TAG, "onServiceConnectionResponse, CONNECTION_ALREADY_EXIST"); + } + } + + @Override + protected void onAuthenticationResponse(SAPeerAgent peerAgent, SAAuthenticationToken authToken, int error) { + /* + * The authenticatePeerAgent(peerAgent) API may not be working properly depending on the firmware + * version of accessory device. Please refer to another sample application for Security. + */ + } + + @Override + protected void onError(SAPeerAgent peerAgent, String errorMessage, int errorCode) { + super.onError(peerAgent, errorMessage, errorCode); + } + + private boolean processUnsupportedException(SsdkUnsupportedException e) { + e.printStackTrace(); + int errType = e.getType(); + if (errType == SsdkUnsupportedException.VENDOR_NOT_SUPPORTED + || errType == SsdkUnsupportedException.DEVICE_NOT_SUPPORTED) { + /* + * Your application can not use Samsung Accessory SDK. You application should work smoothly + * without using this SDK, or you may want to notify user and close your app gracefully (release + * resources, stop Service threads, close UI thread, etc.) + */ + stopSelf(); + } else if (errType == SsdkUnsupportedException.LIBRARY_NOT_INSTALLED) { + Log.e(TAG, "You need to install Samsung Accessory SDK to use this application."); + } else if (errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_REQUIRED) { + Log.e(TAG, "You need to update Samsung Accessory SDK to use this application."); + } else if (errType == SsdkUnsupportedException.LIBRARY_UPDATE_IS_RECOMMENDED) { + Log.e(TAG, "We recommend that you update your Samsung Accessory SDK before using this application."); + return false; + } + return true; + } + + public class LocalBinder extends Binder { + public SmartcardProviderService getService() { + return SmartcardProviderService.this; + } + } + + public class ServiceConnection extends SASocket { + public ServiceConnection() { + super(ServiceConnection.class.getName()); + } + + @Override + public void onError(int channelId, String errorMessage, int errorCode) { + } + + @Override + public void onReceive(int channelId, byte[] data) { + if (mConnectionHandler == null) { + return; + } + final byte[] response = EmulatorSingleton.process(getApplicationContext(), data); + new Thread(new Runnable() { + public void run() { + try { + mConnectionHandler.send(HELLOACCESSORY_CHANNEL_ID, response); + } catch (IOException e) { + e.printStackTrace(); + } + } + }).start(); + } + + @Override + protected void onServiceConnectionLost(int reason) { + mConnectionHandler = null; + EmulatorSingleton.deactivate(); + mHandler.post(new Runnable() { + @Override + public void run() { + Toast.makeText(getBaseContext(), "connection lost", Toast.LENGTH_SHORT).show(); + } + }); + } + } +} diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorService.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/EmulatorSingleton.java similarity index 64% rename from ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorService.java rename to ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/EmulatorSingleton.java index d462bb0..b8b725f 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/EmulatorService.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/EmulatorSingleton.java @@ -17,28 +17,19 @@ * ACardEmulator. If not, see . */ -package com.vsmartcard.acardemulator; +package com.vsmartcard.acardemulator.emulators; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.nfc.cardemulation.HostApduService; -import android.os.Bundle; -import android.os.StrictMode; import android.preference.PreferenceManager; import android.support.v4.content.LocalBroadcastManager; import android.util.Log; -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; - -import com.vsmartcard.acardemulator.emulators.Emulator; -import com.vsmartcard.acardemulator.emulators.JCEmulator; -import com.vsmartcard.acardemulator.emulators.VICCEmulator; - -public class EmulatorService extends HostApduService { +import com.vsmartcard.acardemulator.R; +import com.vsmartcard.acardemulator.Util; +public class EmulatorSingleton { public static final String TAG = "com.vsmartcard.acardemulator.EmulatorService"; public static final String EXTRA_CAPDU = "MSG_CAPDU"; public static final String EXTRA_RAPDU = "MSG_RAPDU"; @@ -49,22 +40,35 @@ public class EmulatorService extends HostApduService { private static Emulator emulator = null; private static boolean do_destroy = false; - @Override - public void onCreate () { - super.onCreate(); + private static void destroyEmulatorIfRequested(Context context) { + if (do_destroy) { + emulator.destroy(); + emulator = null; + do_destroy = false; + Intent i = new Intent(TAG); + i.putExtra(EXTRA_DESELECT, "Uninstalled all applets."); + LocalBroadcastManager.getInstance(context).sendBroadcast(i); + } + } + + public static void destroyEmulator() { + do_destroy = true; + } + + public static void createEmulator(Context context) { // force reloading applets if requested - do_destroy(); + destroyEmulatorIfRequested(context); if (emulator == null) { Log.d("", "Begin transaction"); - SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(this); + SharedPreferences SP = PreferenceManager.getDefaultSharedPreferences(context); String str_emulator = SP.getString("emulator", ""); - if (str_emulator.equals(getString(R.string.vicc))) { + if (str_emulator.equals(context.getString(R.string.vicc))) { emulator = new VICCEmulator( SP.getString("hostname", VICCEmulator.DEFAULT_HOSTNAME), Integer.parseInt(SP.getString("port", Integer.toString(VICCEmulator.DEFAULT_PORT)))); } else { - emulator = new JCEmulator(this, + emulator = new JCEmulator(context, SP.getBoolean("activate_helloworld", false), SP.getBoolean("activate_openpgp", false), SP.getBoolean("activate_oath", false), @@ -74,55 +78,19 @@ public class EmulatorService extends HostApduService { } } - public static void destroySimulator(Context context) { - do_destroy = true; - } - - private void do_destroy() { - if (do_destroy) { - emulator.destroy(); - emulator = null; - do_destroy = false; - Intent i = new Intent(TAG); - i.putExtra(EXTRA_DESELECT, "Uninstalled all applets."); - LocalBroadcastManager.getInstance(this).sendBroadcast(i); - } - } - - @Override - public void onDestroy() { - do_destroy(); - super.onDestroy(); - } - - @Override - public byte[] processCommandApdu(byte[] capdu, Bundle extras) { + public static byte[] process(Context context, byte[] capdu) { byte[] rapdu = emulator.process(capdu); Intent i = new Intent(TAG); i.putExtra(EXTRA_CAPDU, Util.byteArrayToHexString(capdu)); if (rapdu != null) i.putExtra(EXTRA_RAPDU, Util.byteArrayToHexString(rapdu)); - LocalBroadcastManager.getInstance(this).sendBroadcast(i); + LocalBroadcastManager.getInstance(context).sendBroadcast(i); return rapdu; } - @Override - public void onDeactivated(int reason) { - Intent i = new Intent(TAG); - - Log.d("", "End transaction"); - switch (reason) { - case DEACTIVATION_LINK_LOSS: - i.putExtra(EXTRA_DESELECT, "link lost"); - emulator.deactivate(); - break; - case DEACTIVATION_DESELECTED: - emulator.deactivate(); - break; - } - - LocalBroadcastManager.getInstance(this).sendBroadcast(i); + public static void deactivate() { + emulator.deactivate(); } -} +} \ No newline at end of file diff --git a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java index 99470d4..1ff6967 100644 --- a/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java +++ b/ACardEmulator/app/src/main/java/com/vsmartcard/acardemulator/emulators/JCEmulator.java @@ -9,7 +9,6 @@ import com.licel.jcardsim.base.SimulatorRuntime; import com.licel.jcardsim.samples.HelloWorldApplet; import com.licel.jcardsim.utils.AIDUtil; import com.mysmartlogon.gidsApplet.GidsApplet; -import com.vsmartcard.acardemulator.EmulatorService; import com.vsmartcard.acardemulator.R; import com.vsmartcard.acardemulator.Util; @@ -100,11 +99,11 @@ public class JCEmulator implements Emulator { } } - Intent i = new Intent(EmulatorService.TAG); + Intent i = new Intent(EmulatorSingleton.TAG); if (!extra_error.isEmpty()) - i.putExtra(EmulatorService.EXTRA_ERROR, extra_error); + i.putExtra(EmulatorSingleton.EXTRA_ERROR, extra_error); if (!extra_install.isEmpty()) - i.putExtra(EmulatorService.EXTRA_INSTALL, extra_install); + i.putExtra(EmulatorSingleton.EXTRA_INSTALL, extra_install); LocalBroadcastManager.getInstance(context).sendBroadcast(i); } diff --git a/ACardEmulator/app/src/main/res/values/strings.xml b/ACardEmulator/app/src/main/res/values/strings.xml index 159204f..6d3d63a 100644 --- a/ACardEmulator/app/src/main/res/values/strings.xml +++ b/ACardEmulator/app/src/main/res/values/strings.xml @@ -44,6 +44,14 @@ Builtin Java Card Simulator Remote Virtual Smart Card + + + @string/nfc + @string/gear + + Builtin NFC + Samsung Accessory + If you choose the virtual smart card (VICC) as emulator, you need to start the it on your computer with the `--reversed` flag and configure the connection parameters here accordingly. VICC Port VICC Hostname diff --git a/ACardEmulator/app/src/main/res/xml/accessoryservices.xml b/ACardEmulator/app/src/main/res/xml/accessoryservices.xml new file mode 100644 index 0000000..746d229 --- /dev/null +++ b/ACardEmulator/app/src/main/res/xml/accessoryservices.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + ]> + + + + + + + + + + + + + \ No newline at end of file diff --git a/ACardEmulator/app/src/main/res/xml/settings.xml b/ACardEmulator/app/src/main/res/xml/settings.xml index ed95cc3..17148a2 100644 --- a/ACardEmulator/app/src/main/res/xml/settings.xml +++ b/ACardEmulator/app/src/main/res/xml/settings.xml @@ -81,4 +81,11 @@ + + \ No newline at end of file