mirror of
https://github.com/status-im/react-native-status-keycard.git
synced 2025-02-28 12:00:36 +00:00
add deriveKey and exportKey
This commit is contained in:
parent
2354cffa7b
commit
17312ef467
@ -21,121 +21,143 @@ import java.security.spec.InvalidKeySpecException;
|
||||
import im.status.hardwallet_lite_android.io.APDUException;
|
||||
|
||||
public class RNStatusKeycardModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
|
||||
private static final String TAG = "StatusKeycard";
|
||||
private SmartCard smartCard;
|
||||
private final ReactApplicationContext reactContext;
|
||||
private static final String TAG = "StatusKeycard";
|
||||
private SmartCard smartCard;
|
||||
private final ReactApplicationContext reactContext;
|
||||
|
||||
public RNStatusKeycardModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
reactContext.addLifecycleEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNStatusKeycard";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
if (this.smartCard == null) {
|
||||
this.smartCard = new SmartCard(getCurrentActivity(), reactContext);
|
||||
public RNStatusKeycardModule(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
this.reactContext = reactContext;
|
||||
reactContext.addLifecycleEventListener(this);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHostDestroy() {
|
||||
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void nfcIsSupported(final Promise promise) {
|
||||
promise.resolve(smartCard.isNfcSupported());
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void nfcIsEnabled(final Promise promise) {
|
||||
promise.resolve(smartCard.isNfcEnabled());
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void openNfcSettings(final Promise promise) {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
currentActivity.startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
|
||||
promise.resolve(true);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void start(final Promise promise) {
|
||||
if (smartCard.start()) {
|
||||
promise.resolve(true);
|
||||
} else {
|
||||
promise.reject("Error", "Not supported on this device");
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void init(final Promise promise) {
|
||||
try {
|
||||
SmartCardSecrets s = smartCard.init();
|
||||
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putString("pin", s.getPin());
|
||||
params.putString("puk", s.getPuk());
|
||||
params.putString("password", s.getPairingPassword());
|
||||
|
||||
promise.resolve(params);
|
||||
} catch (IOException | APDUException | NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e.getClass().toString(), e.getMessage());
|
||||
@Override
|
||||
public String getName() {
|
||||
return "RNStatusKeycard";
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void pair(final String password, final Promise promise) {
|
||||
try {
|
||||
String pairing = smartCard.pair(password);
|
||||
Log.d(TAG, "pairing done");
|
||||
|
||||
promise.resolve(pairing);
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e.getClass().toString(), e.getMessage());
|
||||
@Override
|
||||
public void onHostResume() {
|
||||
if (this.smartCard == null) {
|
||||
this.smartCard = new SmartCard(getCurrentActivity(), reactContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void generateMnemonic(final String password, final Promise promise) {
|
||||
try {
|
||||
promise.resolve(smartCard.generateMnemonic(password));
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e.getClass().toString(), e.getMessage());
|
||||
@Override
|
||||
public void onHostPause() {
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void saveMnemonic(final String mnemonic, final String password, final String pin, final Promise promise) {
|
||||
try {
|
||||
smartCard.saveMnemonic(mnemonic, password, pin);
|
||||
promise.resolve(true);
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e.getClass().toString(), e.getMessage());
|
||||
@Override
|
||||
public void onHostDestroy() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getApplicationInfo(final Promise promise) {
|
||||
try {
|
||||
promise.resolve(smartCard.getApplicationInfo());
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e.getClass().toString(), e.getMessage());
|
||||
}
|
||||
}
|
||||
@ReactMethod
|
||||
public void nfcIsSupported(final Promise promise) {
|
||||
promise.resolve(smartCard.isNfcSupported());
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void nfcIsEnabled(final Promise promise) {
|
||||
promise.resolve(smartCard.isNfcEnabled());
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void openNfcSettings(final Promise promise) {
|
||||
Activity currentActivity = getCurrentActivity();
|
||||
currentActivity.startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
|
||||
promise.resolve(true);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void start(final Promise promise) {
|
||||
if (smartCard.start()) {
|
||||
promise.resolve(true);
|
||||
} else {
|
||||
promise.reject("Error", "Not supported on this device");
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void init(final Promise promise) {
|
||||
try {
|
||||
SmartCardSecrets s = smartCard.init();
|
||||
|
||||
WritableMap params = Arguments.createMap();
|
||||
params.putString("pin", s.getPin());
|
||||
params.putString("puk", s.getPuk());
|
||||
params.putString("password", s.getPairingPassword());
|
||||
|
||||
promise.resolve(params);
|
||||
} catch (IOException | APDUException | NoSuchAlgorithmException | InvalidKeySpecException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void pair(final String password, final Promise promise) {
|
||||
try {
|
||||
String pairing = smartCard.pair(password);
|
||||
Log.d(TAG, "pairing done");
|
||||
|
||||
promise.resolve(pairing);
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void generateMnemonic(final String pairing, final Promise promise) {
|
||||
try {
|
||||
promise.resolve(smartCard.generateMnemonic(pairing));
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void saveMnemonic(final String mnemonic, final String pairing, final String pin, final Promise promise) {
|
||||
try {
|
||||
smartCard.saveMnemonic(mnemonic, pairing, pin);
|
||||
promise.resolve(true);
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getApplicationInfo(final Promise promise) {
|
||||
try {
|
||||
promise.resolve(smartCard.getApplicationInfo());
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void deriveKey(final String path, final String pairing, final String pin, final Promise promise) {
|
||||
try {
|
||||
smartCard.deriveKey(path, pairing, pin);
|
||||
promise.resolve(path);
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void exportKey(final String pairing, final String pin, final Promise promise) {
|
||||
try {
|
||||
promise.resolve(smartCard.exportKey(pairing, pin));
|
||||
} catch (IOException | APDUException e) {
|
||||
Log.d(TAG, e.getMessage());
|
||||
promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,7 @@ import android.content.pm.PackageManager;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.*;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
|
||||
@ -27,6 +28,7 @@ import im.status.hardwallet_lite_android.wallet.RecoverableSignature;
|
||||
import im.status.hardwallet_lite_android.wallet.ApplicationInfo;
|
||||
import im.status.hardwallet_lite_android.wallet.ApplicationStatus;
|
||||
import im.status.hardwallet_lite_android.wallet.KeyPath;
|
||||
|
||||
import org.spongycastle.util.encoders.Hex;
|
||||
|
||||
public class SmartCard extends BroadcastReceiver implements CardListener {
|
||||
@ -151,11 +153,12 @@ public class SmartCard extends BroadcastReceiver implements CardListener {
|
||||
cmdSet.autoUnpair();
|
||||
}
|
||||
|
||||
public String generateMnemonic(String password) throws IOException, APDUException {
|
||||
public String generateMnemonic(String pairingBase64) throws IOException, APDUException {
|
||||
WalletAppletCommandSet cmdSet = new WalletAppletCommandSet(this.cardChannel);
|
||||
cmdSet.select().checkOK();
|
||||
|
||||
cmdSet.autoPair(password);
|
||||
Pairing pairing = new Pairing(pairingBase64);
|
||||
cmdSet.setPairing(pairing);
|
||||
|
||||
cmdSet.autoOpenSecureChannel();
|
||||
Log.i(TAG, "secure channel opened");
|
||||
@ -166,11 +169,12 @@ public class SmartCard extends BroadcastReceiver implements CardListener {
|
||||
return mnemonic.toMnemonicPhrase();
|
||||
}
|
||||
|
||||
public void saveMnemonic(String mnemonic, String password, String pin) throws IOException, APDUException {
|
||||
public void saveMnemonic(String mnemonic, String pairingBase64, String pin) throws IOException, APDUException {
|
||||
WalletAppletCommandSet cmdSet = new WalletAppletCommandSet(this.cardChannel);
|
||||
cmdSet.select().checkOK();
|
||||
|
||||
cmdSet.autoPair(password);
|
||||
Pairing pairing = new Pairing(pairingBase64);
|
||||
cmdSet.setPairing(pairing);
|
||||
|
||||
cmdSet.autoOpenSecureChannel();
|
||||
Log.i(TAG, "secure channel opened");
|
||||
@ -214,4 +218,44 @@ public class SmartCard extends BroadcastReceiver implements CardListener {
|
||||
|
||||
return cardInfo;
|
||||
}
|
||||
|
||||
public void deriveKey(final String path, final String pairingBase64, final String pin) throws IOException, APDUException {
|
||||
WalletAppletCommandSet cmdSet = new WalletAppletCommandSet(this.cardChannel);
|
||||
cmdSet.select().checkOK();
|
||||
|
||||
Pairing pairing = new Pairing(pairingBase64);
|
||||
cmdSet.setPairing(pairing);
|
||||
|
||||
cmdSet.autoOpenSecureChannel();
|
||||
Log.i(TAG, "secure channel opened");
|
||||
|
||||
cmdSet.verifyPIN(pin).checkOK();
|
||||
Log.i(TAG, "pin verified");
|
||||
|
||||
KeyPath currentPath = new KeyPath(cmdSet.getStatus(WalletAppletCommandSet.GET_STATUS_P1_KEY_PATH).checkOK().getData());
|
||||
Log.i(TAG, "Current key path: " + currentPath);
|
||||
|
||||
if (!currentPath.toString().equals("m/44'/0'/0'/0/0")) {
|
||||
cmdSet.deriveKey(path).checkOK();
|
||||
Log.i(TAG, "Derived m/44'/0'/0'/0/0");
|
||||
}
|
||||
}
|
||||
|
||||
public String exportKey(final String pairingBase64,final String pin) throws IOException, APDUException {
|
||||
WalletAppletCommandSet cmdSet = new WalletAppletCommandSet(this.cardChannel);
|
||||
cmdSet.select().checkOK();
|
||||
|
||||
Pairing pairing = new Pairing(pairingBase64);
|
||||
cmdSet.setPairing(pairing);
|
||||
|
||||
cmdSet.autoOpenSecureChannel();
|
||||
Log.i(TAG, "secure channel opened");
|
||||
|
||||
cmdSet.verifyPIN(pin).checkOK();
|
||||
Log.i(TAG, "pin verified");
|
||||
|
||||
byte[] key = cmdSet.exportKey(WalletAppletCommandSet.EXPORT_KEY_P1_ANY, true).checkOK().getData();
|
||||
|
||||
return Hex.toHexString(key);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user