mirror of
https://github.com/status-im/react-native-status-keycard.git
synced 2025-03-01 12:30:32 +00:00
531 lines
22 KiB
Swift
531 lines
22 KiB
Swift
import Foundation
|
|
import Keycard
|
|
import os.log
|
|
|
|
enum SmartCardError: Error {
|
|
case invalidBase64
|
|
}
|
|
|
|
class SmartCard {
|
|
func initialize(channel: CardChannel, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
let puk = self.randomPUK()
|
|
let pairingPassword = self.randomPairingPassword();
|
|
|
|
let cmdSet = KeycardCommandSet(cardChannel: channel)
|
|
try cmdSet.select().checkOK()
|
|
try cmdSet.initialize(pin: pin, puk: puk, pairingPassword: pairingPassword).checkOK();
|
|
|
|
resolve(["pin": pin, "puk": puk, "password": pairingPassword])
|
|
}
|
|
|
|
func pair(channel: CardChannel, pairingPassword: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
let cmdSet = KeycardCommandSet(cardChannel: channel)
|
|
let info = try ApplicationInfo(cmdSet.select().checkOK().data)
|
|
|
|
logAppInfo(info)
|
|
|
|
try cmdSet.autoPair(password: pairingPassword)
|
|
|
|
resolve(Data(cmdSet.pairing!.bytes).base64EncodedString())
|
|
}
|
|
|
|
func generateMnemonic(channel: CardChannel, pairingBase64: String, words: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
let cmdSet = try securedCommandSet(channel: channel, pairingBase64: pairingBase64)
|
|
|
|
let mnemonic = try Mnemonic(rawData: cmdSet.generateMnemonic(length: GenerateMnemonicP1.length12Words).checkOK().data)
|
|
mnemonic.wordList = words.components(separatedBy: .newlines)
|
|
|
|
resolve(mnemonic.toMnemonicPhrase())
|
|
}
|
|
|
|
func generateAndLoadKey(channel: CardChannel, mnemonic: String, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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[] seed = Mnemonic.toBinarySeed(mnemonic, "");
|
|
BIP32KeyPair keyPair = BIP32KeyPair.fromBinarySeed(seed);
|
|
|
|
cmdSet.loadKey(keyPair).checkOK();
|
|
log("keypair loaded to card");
|
|
|
|
byte[] tlvRoot = cmdSet.exportKey(ROOT_PATH, false, true).checkOK().getData();
|
|
Log.i(TAG, "Derived " + ROOT_PATH);
|
|
BIP32KeyPair rootKeyPair = BIP32KeyPair.fromTLV(tlvRoot);
|
|
|
|
byte[] tlvWhisper = cmdSet.exportKey(WHISPER_PATH, false, false).checkOK().getData();
|
|
Log.i(TAG, "Derived " + WHISPER_PATH);
|
|
BIP32KeyPair whisperKeyPair = BIP32KeyPair.fromTLV(tlvWhisper);
|
|
|
|
byte[] tlvEncryption = cmdSet.exportKey(ENCRYPTION_PATH, false, false).checkOK().getData();
|
|
Log.i(TAG, "Derived " + ENCRYPTION_PATH);
|
|
BIP32KeyPair encryptionKeyPair = BIP32KeyPair.fromTLV(tlvEncryption);
|
|
|
|
byte[] tlvWallet = cmdSet.exportKey(WALLET_PATH, true, true).checkOK().getData();
|
|
Log.i(TAG, "Derived " + WALLET_PATH);
|
|
BIP32KeyPair walletKeyPair = BIP32KeyPair.fromTLV(tlvWallet);
|
|
|
|
ApplicationInfo info = new ApplicationInfo(cmdSet.select().checkOK().getData());
|
|
|
|
WritableMap data = Arguments.createMap();
|
|
data.putString("address", Hex.toHexString(keyPair.toEthereumAddress()));
|
|
data.putString("public-key", Hex.toHexString(keyPair.getPublicKey()));
|
|
data.putString("wallet-root-address", Hex.toHexString(rootKeyPair.toEthereumAddress()));
|
|
data.putString("wallet-root-public-key", Hex.toHexString(rootKeyPair.getPublicKey()));
|
|
data.putString("wallet-address", Hex.toHexString(walletKeyPair.toEthereumAddress()));
|
|
data.putString("wallet-public-key", Hex.toHexString(walletKeyPair.getPublicKey()));
|
|
data.putString("whisper-address", Hex.toHexString(whisperKeyPair.toEthereumAddress()));
|
|
data.putString("whisper-public-key", Hex.toHexString(whisperKeyPair.getPublicKey()));
|
|
data.putString("whisper-private-key", Hex.toHexString(whisperKeyPair.getPrivateKey()));
|
|
data.putString("encryption-public-key", Hex.toHexString(encryptionKeyPair.getPublicKey()));
|
|
data.putString("instance-uid", Hex.toHexString(info.getInstanceUID()));
|
|
data.putString("key-uid", Hex.toHexString(info.getKeyUID()));
|
|
|
|
return data;*/
|
|
}
|
|
|
|
func saveMnemonic(channel: CardChannel, mnemonic: String, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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[] seed = Mnemonic.toBinarySeed(mnemonic, "");
|
|
cmdSet.loadKey(seed);
|
|
|
|
log("seed loaded to card");*/
|
|
}
|
|
|
|
func getApplicationInfo(channel: CardChannel, pairingBase64: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/* KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel);
|
|
ApplicationInfo info = new ApplicationInfo(cmdSet.select().checkOK().getData());
|
|
|
|
Log.i(TAG, "Card initialized? " + info.isInitializedCard());
|
|
|
|
WritableMap cardInfo = Arguments.createMap();
|
|
cardInfo.putBoolean("initialized?", info.isInitializedCard());
|
|
|
|
if (info.isInitializedCard()) {
|
|
Log.i(TAG, "Instance UID: " + Hex.toHexString(info.getInstanceUID()));
|
|
Log.i(TAG, "Key UID: " + Hex.toHexString(info.getKeyUID()));
|
|
Log.i(TAG, "Secure channel public key: " + Hex.toHexString(info.getSecureChannelPubKey()));
|
|
Log.i(TAG, "Application version: " + info.getAppVersionString());
|
|
Log.i(TAG, "Free pairing slots: " + info.getFreePairingSlots());
|
|
|
|
Boolean isPaired = false;
|
|
|
|
if (pairingBase64.length() > 0) {
|
|
Pairing pairing = new Pairing(pairingBase64);
|
|
cmdSet.setPairing(pairing);
|
|
|
|
try {
|
|
cmdSet.autoOpenSecureChannel();
|
|
Log.i(TAG, "secure channel opened");
|
|
isPaired = true;
|
|
} catch(APDUException e) {
|
|
Log.i(TAG, "autoOpenSecureChannel failed: " + e.getMessage());
|
|
}
|
|
|
|
if (isPaired) {
|
|
ApplicationStatus status = new ApplicationStatus(cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_APPLICATION).checkOK().getData());
|
|
|
|
Log.i(TAG, "PIN retry counter: " + status.getPINRetryCount());
|
|
Log.i(TAG, "PUK retry counter: " + status.getPUKRetryCount());
|
|
|
|
cardInfo.putInt("pin-retry-counter", status.getPINRetryCount());
|
|
cardInfo.putInt("puk-retry-counter", status.getPUKRetryCount());
|
|
}
|
|
}
|
|
|
|
cardInfo.putBoolean("has-master-key?", info.hasMasterKey());
|
|
cardInfo.putBoolean("paired?", isPaired);
|
|
cardInfo.putString("instance-uid", Hex.toHexString(info.getInstanceUID()));
|
|
cardInfo.putString("key-uid", Hex.toHexString(info.getKeyUID()));
|
|
cardInfo.putString("secure-channel-pub-key", Hex.toHexString(info.getSecureChannelPubKey()));
|
|
cardInfo.putString("app-version", info.getAppVersionString());
|
|
cardInfo.putInt("free-pairing-slots", info.getFreePairingSlots());
|
|
}
|
|
|
|
return cardInfo;*/
|
|
}
|
|
|
|
func deriveKey(channel: CardChannel, path: String, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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(KeycardCommandSet.GET_STATUS_P1_KEY_PATH).checkOK().getData());
|
|
Log.i(TAG, "Current key path: " + currentPath);
|
|
|
|
if (!currentPath.toString().equals(path)) {
|
|
cmdSet.deriveKey(path).checkOK();
|
|
Log.i(TAG, "Derived " + path);
|
|
}*/
|
|
}
|
|
|
|
func exportKey(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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.exportCurrentKey(true).checkOK().getData();
|
|
|
|
return Hex.toHexString(key);*/
|
|
}
|
|
|
|
func exportKeyWithPath(channel: CardChannel, pairingBase64: String, pin: String, path: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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 = BIP32KeyPair.fromTLV(cmdSet.exportKey(path, false, true).checkOK().getData()).getPublicKey();
|
|
|
|
return Hex.toHexString(key);*/
|
|
}
|
|
|
|
func getKeys(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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[] tlvEncryption = cmdSet.exportKey(ENCRYPTION_PATH, false, false).checkOK().getData();
|
|
BIP32KeyPair encryptionKeyPair = BIP32KeyPair.fromTLV(tlvEncryption);
|
|
|
|
byte[] tlvMaster = cmdSet.exportKey(MASTER_PATH, false, true).checkOK().getData();
|
|
BIP32KeyPair masterPair = BIP32KeyPair.fromTLV(tlvMaster);
|
|
|
|
byte[] tlvRoot = cmdSet.exportKey(ROOT_PATH, false, true).checkOK().getData();
|
|
BIP32KeyPair keyPair = BIP32KeyPair.fromTLV(tlvRoot);
|
|
|
|
byte[] tlvWhisper = cmdSet.exportKey(WHISPER_PATH, false, false).checkOK().getData();
|
|
BIP32KeyPair whisperKeyPair = BIP32KeyPair.fromTLV(tlvWhisper);
|
|
|
|
byte[] tlvWallet = cmdSet.exportKey(WALLET_PATH, true, true).checkOK().getData();
|
|
BIP32KeyPair walletKeyPair = BIP32KeyPair.fromTLV(tlvWallet);
|
|
|
|
ApplicationInfo info = new ApplicationInfo(cmdSet.select().checkOK().getData());
|
|
|
|
WritableMap data = Arguments.createMap();
|
|
data.putString("address", Hex.toHexString(masterPair.toEthereumAddress()));
|
|
data.putString("public-key", Hex.toHexString(masterPair.getPublicKey()));
|
|
data.putString("wallet-root-address", Hex.toHexString(keyPair.toEthereumAddress()));
|
|
data.putString("wallet-root-public-key", Hex.toHexString(keyPair.getPublicKey()));
|
|
data.putString("wallet-address", Hex.toHexString(walletKeyPair.toEthereumAddress()));
|
|
data.putString("wallet-public-key", Hex.toHexString(walletKeyPair.getPublicKey()));
|
|
data.putString("whisper-address", Hex.toHexString(whisperKeyPair.toEthereumAddress()));
|
|
data.putString("whisper-public-key", Hex.toHexString(whisperKeyPair.getPublicKey()));
|
|
data.putString("whisper-private-key", Hex.toHexString(whisperKeyPair.getPrivateKey()));
|
|
data.putString("encryption-public-key", Hex.toHexString(encryptionKeyPair.getPublicKey()));
|
|
data.putString("instance-uid", Hex.toHexString(info.getInstanceUID()));
|
|
data.putString("key-uid", Hex.toHexString(info.getKeyUID()));
|
|
|
|
return data;*/
|
|
}
|
|
|
|
func sign(channel: CardChannel, pairingBase64: String, pin: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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[] hash = Hex.decode(message);
|
|
RecoverableSignature signature = new RecoverableSignature(hash, cmdSet.sign(hash).checkOK().getData());
|
|
|
|
Log.i(TAG, "Signed hash: " + Hex.toHexString(hash));
|
|
Log.i(TAG, "Recovery ID: " + signature.getRecId());
|
|
Log.i(TAG, "R: " + Hex.toHexString(signature.getR()));
|
|
Log.i(TAG, "S: " + Hex.toHexString(signature.getS()));
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
out.write(signature.getR());
|
|
out.write(signature.getS());
|
|
out.write(signature.getRecId());
|
|
|
|
String sig = Hex.toHexString(out.toByteArray());
|
|
Log.i(TAG, "Signature: " + sig);
|
|
|
|
return sig;*/
|
|
}
|
|
|
|
func signWithPath(channel: CardChannel, pairingBase64: String, pin: String, path: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/* KeycardCommandSet cmdSet = new KeycardCommandSet(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[] hash = Hex.decode(message);
|
|
|
|
RecoverableSignature signature;
|
|
|
|
if (cmdSet.getApplicationInfo().getAppVersion() < 0x0202) {
|
|
String actualPath = new KeyPath(cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_KEY_PATH).checkOK().getData()).toString();
|
|
if (!actualPath.equals(path)) {
|
|
cmdSet.deriveKey(path).checkOK();
|
|
}
|
|
signature = new RecoverableSignature(hash, cmdSet.sign(hash).checkOK().getData());
|
|
} else {
|
|
signature = new RecoverableSignature(hash, cmdSet.signWithPath(hash, path, false).checkOK().getData());
|
|
}
|
|
|
|
Log.i(TAG, "Signed hash: " + Hex.toHexString(hash));
|
|
Log.i(TAG, "Recovery ID: " + signature.getRecId());
|
|
Log.i(TAG, "R: " + Hex.toHexString(signature.getR()));
|
|
Log.i(TAG, "S: " + Hex.toHexString(signature.getS()));
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
out.write(signature.getR());
|
|
out.write(signature.getS());
|
|
out.write(signature.getRecId());
|
|
|
|
String sig = Hex.toHexString(out.toByteArray());
|
|
Log.i(TAG, "Signature: " + sig);
|
|
|
|
return sig;*/
|
|
}
|
|
|
|
func signPinless(channel: CardChannel, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
let cmdSet = CashCommandSet(cardChannel: channel)
|
|
try cmdSet.select().checkOK()
|
|
|
|
let hash = hexToBytes(message)
|
|
let res = try cmdSet.sign(data: hash).checkOK()
|
|
|
|
/* RecoverableSignature signature = new RecoverableSignature(hash, cmdSet.sign(hash).checkOK().getData());
|
|
|
|
Log.i(TAG, "Signed hash: " + Hex.toHexString(hash));
|
|
Log.i(TAG, "Recovery ID: " + signature.getRecId());
|
|
Log.i(TAG, "R: " + Hex.toHexString(signature.getR()));
|
|
Log.i(TAG, "S: " + Hex.toHexString(signature.getS()));
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
out.write(signature.getR());
|
|
out.write(signature.getS());
|
|
out.write(signature.getRecId());
|
|
|
|
String sig = Hex.toHexString(out.toByteArray());
|
|
Log.i(TAG, "Signature: " + sig);
|
|
return sig;
|
|
*/
|
|
|
|
resolve(res.data.toHexString())
|
|
}
|
|
|
|
func verifyPin(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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");
|
|
|
|
ApplicationStatus status = new ApplicationStatus(cmdSet.getStatus(KeycardCommandSet.GET_STATUS_P1_APPLICATION).checkOK().getData());
|
|
|
|
return status.getPINRetryCount();*/
|
|
}
|
|
|
|
func changePin(channel: CardChannel, pairingBase64: String, currentPin: String, newPin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel);
|
|
cmdSet.select().checkOK();
|
|
|
|
Pairing pairing = new Pairing(pairingBase64);
|
|
cmdSet.setPairing(pairing);
|
|
|
|
cmdSet.autoOpenSecureChannel();
|
|
Log.i(TAG, "secure channel opened");
|
|
|
|
cmdSet.verifyPIN(currentPin).checkOK();
|
|
Log.i(TAG, "pin verified");
|
|
|
|
cmdSet.changePIN(0, newPin);
|
|
Log.i(TAG, "pin changed");*/
|
|
}
|
|
|
|
func unblockPin(channel: CardChannel, pairingBase64: String, puk: String, newPin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(this.cardChannel);
|
|
cmdSet.select().checkOK();
|
|
|
|
Pairing pairing = new Pairing(pairingBase64);
|
|
cmdSet.setPairing(pairing);
|
|
|
|
cmdSet.autoOpenSecureChannel();
|
|
Log.i(TAG, "secure channel opened");
|
|
|
|
cmdSet.unblockPIN(puk, newPin).checkOK();
|
|
Log.i(TAG, "pin unblocked");*/
|
|
}
|
|
|
|
func unpair(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/* KeycardCommandSet cmdSet = new KeycardCommandSet(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");
|
|
|
|
cmdSet.autoUnpair();
|
|
Log.i(TAG, "card unpaired");*/
|
|
}
|
|
|
|
func removeKey(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*KeycardCommandSet cmdSet = new KeycardCommandSet(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");
|
|
|
|
cmdSet.removeKey();
|
|
Log.i(TAG, "key removed");*/
|
|
}
|
|
|
|
func removeKeyWithUnpair(channel: CardChannel, pairingBase64: String, pin: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) throws -> Void {
|
|
/*removeKey(pairingBase64, pin);
|
|
unpair(pairingBase64, pin);*/
|
|
}
|
|
|
|
func randomPUK() -> String {
|
|
return String(format: "%012d", Int.random(in: 0..<999999999999))
|
|
}
|
|
|
|
func randomPairingPassword() -> String {
|
|
let letters = "23456789ABCDEFGHJKLMNPRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
|
return String((0..<16).map{ _ in letters.randomElement()! })
|
|
}
|
|
|
|
func authenticatedCommandSet(channel: CardChannel, pairingBase64: String, pin: String) throws -> KeycardCommandSet {
|
|
let cmdSet = try securedCommandSet(channel: channel, pairingBase64: pairingBase64)
|
|
try cmdSet.verifyPIN(pin: pin).checkOK()
|
|
return cmdSet;
|
|
}
|
|
|
|
func securedCommandSet(channel: CardChannel, pairingBase64: String) throws -> KeycardCommandSet {
|
|
let cmdSet = KeycardCommandSet(cardChannel: channel)
|
|
try openSecureChannel(cmdSet: cmdSet, pairingBase64: pairingBase64)
|
|
|
|
return cmdSet
|
|
}
|
|
|
|
func openSecureChannel(cmdSet: KeycardCommandSet, pairingBase64: String) throws -> Void {
|
|
cmdSet.pairing = try base64ToPairing(pairingBase64)
|
|
|
|
try cmdSet.autoOpenSecureChannel()
|
|
os_log("secure channel opened")
|
|
}
|
|
|
|
func base64ToPairing(_ base64: String) throws -> Pairing {
|
|
if let data = Data(base64Encoded: base64) {
|
|
return Pairing(pairingData: [UInt8](data))
|
|
} else {
|
|
throw SmartCardError.invalidBase64
|
|
}
|
|
}
|
|
|
|
func logAppInfo(_ info: ApplicationInfo) -> Void {
|
|
os_log("Instance UID: %@", bytesToHex(info.instanceUID))
|
|
os_log("Key UID: %@", bytesToHex(info.keyUID))
|
|
os_log("Secure channel public key: %@", bytesToHex(info.secureChannelPubKey))
|
|
os_log("Application version: %@", info.appVersionString)
|
|
os_log("Free pairing slots: %d", info.freePairingSlots)
|
|
}
|
|
|
|
func bytesToHex(_ bytes: [UInt8]) -> String {
|
|
return bytes.map { String(format: "%02hhx", $0) }.joined()
|
|
}
|
|
|
|
func hexToBytes(_ hex: String) -> [UInt8] {
|
|
var last = hex.first
|
|
return hex.dropFirst().compactMap {
|
|
guard
|
|
let lastHexDigitValue = last?.hexDigitValue,
|
|
let hexDigitValue = $0.hexDigitValue
|
|
else {
|
|
last = $0
|
|
return nil
|
|
}
|
|
defer {
|
|
last = nil
|
|
}
|
|
return UInt8(lastHexDigitValue * 16 + hexDigitValue)
|
|
}
|
|
}
|
|
}
|