@onekeyfe/react-native-lite-card 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -0
- package/README.md +37 -0
- package/ReactNativeLiteCard.podspec +22 -0
- package/android/build.gradle +79 -0
- package/android/gradle.properties +5 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/config/command.json +205 -0
- package/android/src/main/cpp/CMakeLists.txt +19 -0
- package/android/src/main/cpp/validation.c +227 -0
- package/android/src/main/cpp/validation.h +19 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/LoggerManager.kt +35 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardModule.kt +420 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/ReactNativeLiteCardPackage.kt +33 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/keys/KeysNativeProvider.kt +13 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/Exceptions.kt +58 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/NfcUtils.kt +142 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/broadcast/NfcStatusChangeBroadcastReceiver.kt +56 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/nfc/gpchannel/GPChannelNatives.kt +32 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/NfcConstant.kt +38 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/OnekeyLiteCard.kt +236 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/APDUParam.kt +17 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardInfo.java +84 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardResponse.java +37 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/CardState.kt +10 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/ParsedCertInfo.java +39 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SecureChanelParam.java +113 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/entitys/SendResponse.kt +26 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/CommandGenerator.kt +178 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/Connection.kt +439 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/GPCAPDUGenerator.kt +56 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/EventUtils.kt +14 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/GpsUtil.kt +38 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/HexUtils.java +93 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/LogUtil.kt +11 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/MiUtil.kt +93 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/NfcPermissionUtils.kt +24 -0
- package/android/src/main/java/com/onekeyfe/reactnativelitecard/utils/Utils.java +437 -0
- package/android/src/main/jniLibs/arm64-v8a/libgpchannelNDK.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libgpchannelNDK.so +0 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandModal.h +39 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandModal.m +143 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandTool.h +28 -0
- package/ios/Classes/OKLiteCommand/OKLiteCommandTool.m +53 -0
- package/ios/Classes/OKNFCBridge.h +28 -0
- package/ios/Classes/OKNFCBridge.mm +221 -0
- package/ios/Classes/OKNFCLiteDefine.h +108 -0
- package/ios/Classes/OKNFTLite/OKLiteProtocol.h +37 -0
- package/ios/Classes/OKNFTLite/OKLiteV1.h +41 -0
- package/ios/Classes/OKNFTLite/OKLiteV1.m +609 -0
- package/ios/Classes/OKNFTLite/OKLiteV2.h +17 -0
- package/ios/Classes/OKNFTLite/OKLiteV2.m +132 -0
- package/ios/Classes/OKNFTLite/OKNFCManager.h +40 -0
- package/ios/Classes/OKNFTLite/OKNFCManager.m +330 -0
- package/ios/Classes/Utils/NFCConfig.h +19 -0
- package/ios/Classes/Utils/NFCConfig.m +18 -0
- package/ios/Classes/Utils/NSData+OKNFCHexData.h +17 -0
- package/ios/Classes/Utils/NSData+OKNFCHexData.m +24 -0
- package/ios/Classes/Utils/NSData+StringToData.h +12 -0
- package/ios/Classes/Utils/NSData+StringToData.m +25 -0
- package/ios/Classes/Utils/NSString+OKAdd.h +14 -0
- package/ios/Classes/Utils/NSString+OKAdd.m +40 -0
- package/ios/Classes/Utils/NSString+OKNFCHexStr.h +18 -0
- package/ios/Classes/Utils/NSString+OKNFCHexStr.m +38 -0
- package/ios/Classes/Utils/OKNFCUtility.h +18 -0
- package/ios/Classes/Utils/OKNFCUtility.m +22 -0
- package/ios/Classes/Utils/OKTools.h +17 -0
- package/ios/Classes/Utils/OKTools.m +21 -0
- package/ios/GPChannelSDKCore.xcframework/Info.plist +52 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/GPChannelSDKCore +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Headers/GPChannelSDK.h +315 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Headers/GPChannelSDKCore.h +19 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Info.plist +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/Modules/module.modulemap +7 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64/GPChannelSDKCore.framework/_CodeSignature/CodeResources +147 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/GPChannelSDKCore +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Headers/GPChannelSDK.h +315 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Headers/GPChannelSDKCore.h +19 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Info.plist +0 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/Modules/module.modulemap +7 -0
- package/ios/GPChannelSDKCore.xcframework/ios-arm64_x86_64-simulator/GPChannelSDKCore.framework/_CodeSignature/CodeResources +147 -0
- package/ios/ReactNativeLiteCard.h +5 -0
- package/ios/ReactNativeLiteCard.mm +222 -0
- package/lib/module/NativeReactNativeLiteCard.js +25 -0
- package/lib/module/NativeReactNativeLiteCard.js.map +1 -0
- package/lib/module/index.js +71 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeReactNativeLiteCard.d.ts +59 -0
- package/lib/typescript/src/NativeReactNativeLiteCard.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +23 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/package.json +168 -0
- package/src/NativeReactNativeLiteCard.ts +112 -0
- package/src/index.tsx +94 -0
package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/CommandGenerator.kt
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.onekeyLite.nfc
|
|
2
|
+
|
|
3
|
+
import com.google.gson.JsonObject
|
|
4
|
+
import com.google.gson.JsonParser
|
|
5
|
+
import org.haobtc.onekey.card.gpchannel.GPChannelNatives.nativeGPCParseAPDUResponse
|
|
6
|
+
import org.haobtc.onekey.card.gpchannel.GPChannelNatives.nativeGPCParseSafeAPDUResponse
|
|
7
|
+
import so.onekey.app.wallet.lite.nfc.NFCExceptions
|
|
8
|
+
import so.onekey.app.wallet.lite.onekeyLite.entitys.APDUParam
|
|
9
|
+
import so.onekey.app.wallet.lite.onekeyLite.entitys.CardResponse
|
|
10
|
+
import so.onekey.app.wallet.lite.onekeyLite.entitys.SendResponse
|
|
11
|
+
import so.onekey.app.wallet.lite.utils.Utils
|
|
12
|
+
|
|
13
|
+
enum class AppleCardType(val aid: String, val prefixSN: String) {
|
|
14
|
+
V1("D156000132834001", "OKLFT"),
|
|
15
|
+
V2("6f6e656b65792e6261636b757001", "OKLFB"),
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
enum class CommandArea(val code: String) {
|
|
19
|
+
None("none"), BackupApplet("backup"), PrimarySafety("master");
|
|
20
|
+
|
|
21
|
+
companion object {
|
|
22
|
+
fun parse(code: String): CommandArea {
|
|
23
|
+
return when (code) {
|
|
24
|
+
"backup" -> BackupApplet
|
|
25
|
+
"master" -> PrimarySafety
|
|
26
|
+
else -> None
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
enum class CommandType(val code: String) {
|
|
33
|
+
SELECT_BACKUP_APPLET("select_backup_applet"),
|
|
34
|
+
SELECT_PRIMARY_SAFETY("select_primary_safety"),
|
|
35
|
+
GET_BACKUP_STATUS("get_backup_status"),
|
|
36
|
+
GET_PIN_STATUS("get_pin_status"),
|
|
37
|
+
GET_SERIAL_NUMBER("get_serial_number"),
|
|
38
|
+
GET_PIN_RETRY_COUNT("get_pin_retry_count"),
|
|
39
|
+
RESET_CARD("reset_card"),
|
|
40
|
+
VERIFY_PIN("verify_pin"),
|
|
41
|
+
SETUP_NEW_PIN("setup_new_pin"),
|
|
42
|
+
CHANGE_PIN("change_pin"),
|
|
43
|
+
BACKUP_DATA("backup_data"),
|
|
44
|
+
EXPORT_DATA("export_data"),
|
|
45
|
+
VERIFY_CERTIFICATE("verify_certificate"),
|
|
46
|
+
VERIFY_AUTH_DATA("verify_auth_data"),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class Command(
|
|
50
|
+
private val cardType: AppleCardType,
|
|
51
|
+
val area: CommandArea,
|
|
52
|
+
val command: String,
|
|
53
|
+
private val ignoreSafeChannel: Boolean,
|
|
54
|
+
private val useSafeChannel: Boolean,
|
|
55
|
+
private val useSafeChannelWhenOpen: Boolean,
|
|
56
|
+
private val hasOpenSafeChannel: Boolean,
|
|
57
|
+
val data: String,
|
|
58
|
+
) {
|
|
59
|
+
private fun beforeConnecting(connection: Connection) {
|
|
60
|
+
val needOpenSafeChannel = useSafeChannel || (useSafeChannelWhenOpen && hasOpenSafeChannel)
|
|
61
|
+
val needCloseSafeChannel =
|
|
62
|
+
(!useSafeChannel && !(useSafeChannelWhenOpen && hasOpenSafeChannel))
|
|
63
|
+
|
|
64
|
+
if (!ignoreSafeChannel && needCloseSafeChannel) {
|
|
65
|
+
if (hasOpenSafeChannel) connection.resetSecureChannel()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (area == CommandArea.BackupApplet) {
|
|
69
|
+
if (connection.getCurrentCommandArea() != CommandArea.BackupApplet) {
|
|
70
|
+
connection.selectBackupApplet(cardType)
|
|
71
|
+
}
|
|
72
|
+
} else if (area == CommandArea.PrimarySafety) {
|
|
73
|
+
if (connection.getCurrentCommandArea() != CommandArea.PrimarySafety) {
|
|
74
|
+
connection.selectPrimarySafety()
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!ignoreSafeChannel && needOpenSafeChannel) {
|
|
79
|
+
val res = connection.openSafeChannel()
|
|
80
|
+
if (!res) throw NFCExceptions.InterruptException()
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
private fun splitHex(hex: String): List<String> {
|
|
85
|
+
val result = mutableListOf<String>()
|
|
86
|
+
for (i in hex.indices step 2) {
|
|
87
|
+
result.add(hex.substring(i, i + 2))
|
|
88
|
+
}
|
|
89
|
+
return result
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
private fun buildApdu(): String {
|
|
93
|
+
val commandByteArray = splitHex(command).map { it.toLong(16) }.toLongArray()
|
|
94
|
+
return GPCAPDUGenerator.buildGPCAPDU(
|
|
95
|
+
APDUParam(commandByteArray, data),
|
|
96
|
+
useSafeChannel || (useSafeChannelWhenOpen && hasOpenSafeChannel)
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
private fun parseResponse(response: String): String {
|
|
101
|
+
return if (useSafeChannel || (useSafeChannelWhenOpen && hasOpenSafeChannel)) {
|
|
102
|
+
nativeGPCParseSafeAPDUResponse(response)
|
|
103
|
+
} else {
|
|
104
|
+
nativeGPCParseAPDUResponse(response)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
fun send(connection: Connection): SendResponse {
|
|
109
|
+
beforeConnecting(connection)
|
|
110
|
+
// buildApdu && parseResponse Use in pairs
|
|
111
|
+
val apdu = buildApdu()
|
|
112
|
+
val result = Connection.send(connection.isoDep, apdu)
|
|
113
|
+
val resultObject = CardResponse.objectFromData(parseResponse(result.rawResponse))
|
|
114
|
+
result.result = resultObject?.response ?: ""
|
|
115
|
+
return result
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
class CommandGenerator {
|
|
120
|
+
companion object {
|
|
121
|
+
private fun readConfig(): JsonObject {
|
|
122
|
+
val context = Utils.getApp()
|
|
123
|
+
val config = context.assets.open("config/command.json")
|
|
124
|
+
config.use {
|
|
125
|
+
val json = it.bufferedReader().use { it.readText() }
|
|
126
|
+
return JsonParser.parseString(json).asJsonObject
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
val instanceConfig by lazy(LazyThreadSafetyMode.NONE) {
|
|
131
|
+
readConfig()
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
fun generalCommand(
|
|
136
|
+
cardType: AppleCardType,
|
|
137
|
+
type: CommandType,
|
|
138
|
+
hasOpenSafeChannel: Boolean,
|
|
139
|
+
data: String? = null
|
|
140
|
+
): Command {
|
|
141
|
+
|
|
142
|
+
val config = when (cardType) {
|
|
143
|
+
AppleCardType.V1 -> instanceConfig.getAsJsonObject(type.code).getAsJsonObject("v1")
|
|
144
|
+
AppleCardType.V2 -> instanceConfig.getAsJsonObject(type.code).getAsJsonObject("v2")
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
val area = if (config.has("area")) {
|
|
148
|
+
CommandArea.parse(config["area"].asString)
|
|
149
|
+
} else {
|
|
150
|
+
CommandArea.None
|
|
151
|
+
}
|
|
152
|
+
val ignoreSafeChannel =
|
|
153
|
+
config.has("ignoreSafeChannel") && config["ignoreSafeChannel"].asBoolean
|
|
154
|
+
val useSafeChannel = config.has("useSafeChannel") && config["useSafeChannel"].asBoolean
|
|
155
|
+
val useSafeChannelWhenOpen =
|
|
156
|
+
config.has("useSafeChannelWhenOpen") && config["useSafeChannelWhenOpen"].asBoolean
|
|
157
|
+
val needData = config.has("needData") && config["needData"].asBoolean
|
|
158
|
+
val command = if (config.has("command")) {
|
|
159
|
+
config["command"].asString
|
|
160
|
+
} else {
|
|
161
|
+
throw Exception("command not found")
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (needData && data == null) throw Exception("data is null")
|
|
165
|
+
|
|
166
|
+
return Command(
|
|
167
|
+
cardType = cardType,
|
|
168
|
+
area = area,
|
|
169
|
+
command = command,
|
|
170
|
+
ignoreSafeChannel = ignoreSafeChannel,
|
|
171
|
+
useSafeChannel = useSafeChannel,
|
|
172
|
+
useSafeChannelWhenOpen = useSafeChannelWhenOpen,
|
|
173
|
+
hasOpenSafeChannel = hasOpenSafeChannel,
|
|
174
|
+
data = data ?: ""
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
}
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.onekeyLite.nfc
|
|
2
|
+
|
|
3
|
+
import android.nfc.TagLostException
|
|
4
|
+
import android.nfc.tech.IsoDep
|
|
5
|
+
import org.haobtc.onekey.card.gpchannel.GPChannelNatives
|
|
6
|
+
import org.haobtc.onekey.card.gpchannel.GPChannelNatives.nativeGPCFinalize
|
|
7
|
+
import so.onekey.app.wallet.lite.keys.KeysNativeProvider
|
|
8
|
+
import so.onekey.app.wallet.lite.nfc.NFCExceptions
|
|
9
|
+
import so.onekey.app.wallet.lite.onekeyLite.NfcConstant
|
|
10
|
+
import so.onekey.app.wallet.lite.onekeyLite.entitys.*
|
|
11
|
+
import so.onekey.app.wallet.lite.onekeyLite.nfc.GPCAPDUGenerator.buildGPCAPDU
|
|
12
|
+
import so.onekey.app.wallet.lite.onekeyLite.nfc.GPCAPDUGenerator.combCommand
|
|
13
|
+
import so.onekey.app.wallet.lite.utils.HexUtils
|
|
14
|
+
import so.onekey.app.wallet.lite.utils.HexUtils.byteArr2HexStr
|
|
15
|
+
import so.onekey.app.wallet.lite.utils.HexUtils.hexString2Bytes
|
|
16
|
+
import so.onekey.app.wallet.lite.utils.LogUtil.printLog
|
|
17
|
+
import so.onekey.app.wallet.lite.utils.Utils
|
|
18
|
+
import java.io.IOException
|
|
19
|
+
|
|
20
|
+
class Connection(val isoDep: IsoDep, private val mCommandGenerator: CommandGenerator) {
|
|
21
|
+
companion object {
|
|
22
|
+
private const val TAG = "Connection"
|
|
23
|
+
|
|
24
|
+
@JvmStatic
|
|
25
|
+
private fun connect(isoDep: IsoDep?) {
|
|
26
|
+
val isConnected: Boolean = try {
|
|
27
|
+
isoDep?.isConnected ?: false
|
|
28
|
+
} catch (e: Exception) {
|
|
29
|
+
false
|
|
30
|
+
}
|
|
31
|
+
if (isConnected == false) {
|
|
32
|
+
isoDep?.connect()
|
|
33
|
+
isoDep?.timeout = 15000
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@JvmStatic
|
|
38
|
+
fun send(isoDep: IsoDep, request: String?): SendResponse {
|
|
39
|
+
try {
|
|
40
|
+
connect(isoDep)
|
|
41
|
+
val response = isoDep.transceive(hexString2Bytes(request)) ?: byteArrayOf(
|
|
42
|
+
0xFF.toByte(), 0xFF.toByte()
|
|
43
|
+
)
|
|
44
|
+
val resp: ByteArray = if (response.size > 2) {
|
|
45
|
+
response.copyOfRange(0, response.size - 2)
|
|
46
|
+
} else byteArrayOf()
|
|
47
|
+
val sw1 = response[response.size - 2]
|
|
48
|
+
val sw2 = response[response.size - 1]
|
|
49
|
+
|
|
50
|
+
return SendResponse(byteArr2HexStr(response), sw1, sw2, byteArr2HexStr(resp))
|
|
51
|
+
} catch (e: TagLostException) {
|
|
52
|
+
// throw NFCExceptions.InterruptException()
|
|
53
|
+
return SendResponse("0xFFFF", 0xFF.toByte(), 0xFF.toByte())
|
|
54
|
+
} catch (e: IOException) {
|
|
55
|
+
// e.printStackTrace()
|
|
56
|
+
return SendResponse("0xFFFF", 0xFF.toByte(), 0xFF.toByte())
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private var mCardType: AppleCardType = AppleCardType.V2
|
|
62
|
+
private var mCardSerialNumber: String = NfcConstant.NOT_MATCH_DEVICE
|
|
63
|
+
private var hasOpenSafeChannel: Boolean = false
|
|
64
|
+
private var hasSetupPin: Boolean = false
|
|
65
|
+
private var hasBackup: Boolean = false
|
|
66
|
+
private var mCommandArea = CommandArea.None
|
|
67
|
+
|
|
68
|
+
init {
|
|
69
|
+
readCardInfo()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
fun getCardType(): AppleCardType {
|
|
73
|
+
return mCardType
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
fun getCurrentCommandArea(): CommandArea {
|
|
77
|
+
return mCommandArea
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
fun selectPrimarySafety(): Boolean {
|
|
81
|
+
printLog(TAG, "---> selectPrimarySafety begin")
|
|
82
|
+
val command = mCommandGenerator.generalCommand(
|
|
83
|
+
mCardType, CommandType.SELECT_PRIMARY_SAFETY, hasOpenSafeChannel,
|
|
84
|
+
)
|
|
85
|
+
val res = command.send(this)
|
|
86
|
+
printLog(
|
|
87
|
+
TAG, "<--- selectPrimarySafety end: ${res.getCode()} ${res.data} area:${mCommandArea}"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
if (res.isSuccess() && !res.isEmptyData()) {
|
|
91
|
+
mCommandArea = CommandArea.PrimarySafety
|
|
92
|
+
return true
|
|
93
|
+
}
|
|
94
|
+
return false
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fun selectBackupApplet(cardType: AppleCardType?): Boolean {
|
|
98
|
+
printLog(TAG, "---> selectApplet begin")
|
|
99
|
+
val command = mCommandGenerator.generalCommand(
|
|
100
|
+
cardType ?: mCardType,
|
|
101
|
+
CommandType.SELECT_BACKUP_APPLET,
|
|
102
|
+
hasOpenSafeChannel,
|
|
103
|
+
cardType?.aid ?: mCardType.aid
|
|
104
|
+
)
|
|
105
|
+
val res = command.send(this)
|
|
106
|
+
|
|
107
|
+
printLog(TAG, "<--- selectApplet end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
108
|
+
|
|
109
|
+
if (res.isSuccess()) {
|
|
110
|
+
mCommandArea = CommandArea.BackupApplet
|
|
111
|
+
return true
|
|
112
|
+
}
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private fun getDeviceCertificate(): ParsedCertInfo? {
|
|
117
|
+
printLog(TAG, "---> getDeviceCertificate begin")
|
|
118
|
+
// #1.NFC:GET CERT.SD.ECKA 获取智能卡证书
|
|
119
|
+
val apdu = buildGPCAPDU(APDUParam(0x80, 0xCA, 0xBF, 0x21, "A60483021518"))
|
|
120
|
+
val rawCert = send(isoDep, apdu)
|
|
121
|
+
printLog(
|
|
122
|
+
TAG,
|
|
123
|
+
"<--- getDeviceCertificate end: ${rawCert.getCode()} ${rawCert.data} area:${mCommandArea}"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
val cert = GPChannelNatives.nativeGPCTLVDecode(rawCert.data)
|
|
127
|
+
val certificate = CardResponse.objectFromData(cert).response
|
|
128
|
+
|
|
129
|
+
val certInfo = GPChannelNatives.nativeGPCParseCertificate(certificate)
|
|
130
|
+
return ParsedCertInfo.objectFromData(certInfo)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
fun openSafeChannel(): Boolean {
|
|
134
|
+
printLog(TAG, "---> openSafeChannel begin")
|
|
135
|
+
|
|
136
|
+
if (hasOpenSafeChannel) {
|
|
137
|
+
printLog(TAG, "<--- has open safe channel")
|
|
138
|
+
return true
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
printLog(TAG, "0. ---> getDeviceCertificate begin")
|
|
142
|
+
val certInfo = getDeviceCertificate() ?: return false
|
|
143
|
+
printLog(TAG, "0. <--- getDeviceCertificate end: ${certInfo.subjectID}")
|
|
144
|
+
|
|
145
|
+
printLog(TAG, "1. ---> nativeGPCInitialize begin")
|
|
146
|
+
val param = SecureChanelParam.objectFromData(
|
|
147
|
+
KeysNativeProvider().getLiteSecureChannelInitParams(Utils.getApp())
|
|
148
|
+
)
|
|
149
|
+
param.cardGroupID = certInfo.subjectID
|
|
150
|
+
printLog(TAG, "nativeGPCInitialize read param done")
|
|
151
|
+
val initializeStatus = GPChannelNatives.nativeGPCInitialize(param.toString())
|
|
152
|
+
if (initializeStatus != 0) {
|
|
153
|
+
return false
|
|
154
|
+
}
|
|
155
|
+
printLog(TAG, "1. <--- nativeGPCInitialize end")
|
|
156
|
+
|
|
157
|
+
printLog(TAG, "2. ---> Perform security operation begin")
|
|
158
|
+
val command = mCommandGenerator.generalCommand(
|
|
159
|
+
mCardType, CommandType.VERIFY_CERTIFICATE, hasOpenSafeChannel, param.crt
|
|
160
|
+
)
|
|
161
|
+
val securityRes = command.send(this)
|
|
162
|
+
printLog(
|
|
163
|
+
TAG,
|
|
164
|
+
"2. <--- Perform security operation end: ${securityRes.getCode()} ${securityRes.data}"
|
|
165
|
+
)
|
|
166
|
+
if (!securityRes.isSuccess()) {
|
|
167
|
+
return false
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
printLog(TAG, "3. ---> mutual authenticate begin")
|
|
171
|
+
val authData = GPChannelNatives.nativeGPCBuildMutualAuthData()
|
|
172
|
+
printLog(TAG, "mutual authenticate data")
|
|
173
|
+
val authCommand = mCommandGenerator.generalCommand(
|
|
174
|
+
mCardType, CommandType.VERIFY_AUTH_DATA, hasOpenSafeChannel, authData
|
|
175
|
+
)
|
|
176
|
+
val authRes = authCommand.send(this)
|
|
177
|
+
printLog(TAG, "3. <--- mutual authenticate end")
|
|
178
|
+
if (authRes.isEmptyData() || !authRes.isSuccess()) {
|
|
179
|
+
return false
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
printLog(TAG, "4. ---> open secure channel begin")
|
|
183
|
+
val openStatus = GPChannelNatives.nativeGPCOpenSecureChannel(authRes.result)
|
|
184
|
+
if (openStatus != 0) {
|
|
185
|
+
return false
|
|
186
|
+
}
|
|
187
|
+
printLog(TAG, "4. <--- open secure channel end")
|
|
188
|
+
|
|
189
|
+
printLog(TAG, "<--- openSafeChannel end: Open Secure Channel OK")
|
|
190
|
+
|
|
191
|
+
hasOpenSafeChannel = true
|
|
192
|
+
return true
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
fun resetSecureChannel(): Boolean {
|
|
196
|
+
printLog(TAG, "---> resetSecureChannel begin")
|
|
197
|
+
nativeGPCFinalize()
|
|
198
|
+
hasOpenSafeChannel = false
|
|
199
|
+
printLog(TAG, "<--- resetSecureChannel end")
|
|
200
|
+
return true
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
private fun loadBackupStatus(): Boolean {
|
|
204
|
+
printLog(TAG, "---> getBackupStatus begin")
|
|
205
|
+
val command = mCommandGenerator.generalCommand(
|
|
206
|
+
mCardType, CommandType.GET_BACKUP_STATUS, hasOpenSafeChannel
|
|
207
|
+
)
|
|
208
|
+
val res = command.send(this)
|
|
209
|
+
printLog(TAG, "<--- getBackupStatus end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
210
|
+
|
|
211
|
+
if (!res.isSuccess()) {
|
|
212
|
+
return false
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return (res.data == "02").also { hasBackup = it }
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
private fun loadPinStatus(): Boolean {
|
|
219
|
+
printLog(TAG, "---> getPinStatus begin")
|
|
220
|
+
val command = mCommandGenerator.generalCommand(
|
|
221
|
+
mCardType, CommandType.GET_PIN_STATUS, hasOpenSafeChannel, "DFFF028105"
|
|
222
|
+
)
|
|
223
|
+
val res = command.send(this)
|
|
224
|
+
printLog(TAG, "<--- getPinStatus end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
225
|
+
|
|
226
|
+
if (!res.isSuccess()) {
|
|
227
|
+
return false
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
val notSetPin = res.data == "02"
|
|
231
|
+
hasSetupPin = !notSetPin
|
|
232
|
+
return notSetPin
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private fun loadSerialNumber(cardType: AppleCardType? = null): String {
|
|
236
|
+
printLog(TAG, "---> getSerialNumber begin")
|
|
237
|
+
val command = mCommandGenerator.generalCommand(
|
|
238
|
+
cardType ?: mCardType, CommandType.GET_SERIAL_NUMBER, hasOpenSafeChannel, "DFFF028101"
|
|
239
|
+
)
|
|
240
|
+
val res = command.send(this)
|
|
241
|
+
|
|
242
|
+
printLog(TAG, "<--- getSerialNumber end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
243
|
+
if (!res.isSuccess()) {
|
|
244
|
+
return NfcConstant.NOT_MATCH_DEVICE
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return String(hexString2Bytes(res.data)).also {
|
|
248
|
+
mCardSerialNumber = it
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private fun getRetryCount(): Int {
|
|
253
|
+
printLog(TAG, "---> getRetryNum begin")
|
|
254
|
+
val command = mCommandGenerator.generalCommand(
|
|
255
|
+
mCardType, CommandType.GET_PIN_RETRY_COUNT, hasOpenSafeChannel, "DFFF028102"
|
|
256
|
+
)
|
|
257
|
+
val res = command.send(this)
|
|
258
|
+
|
|
259
|
+
printLog(TAG, "<--- getRetryNum end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
260
|
+
|
|
261
|
+
if (res.isEmptyData() || !res.isSuccess()) {
|
|
262
|
+
return NfcConstant.GET_RETRY_NUM_INTERRUPT_STATUS
|
|
263
|
+
}
|
|
264
|
+
return res.data?.toInt(16) ?: NfcConstant.GET_RETRY_NUM_INTERRUPT_STATUS
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
private fun readCardInfo() {
|
|
268
|
+
printLog(TAG, "---> initCard begin")
|
|
269
|
+
try {
|
|
270
|
+
val cardTypes = arrayOf(AppleCardType.V1, AppleCardType.V2)
|
|
271
|
+
for (cardType in cardTypes) {
|
|
272
|
+
printLog(TAG, "---->> selectApplet: $cardType")
|
|
273
|
+
val serialNumber = loadSerialNumber(cardType)
|
|
274
|
+
if (serialNumber.startsWith(cardType.prefixSN)) {
|
|
275
|
+
mCardType = cardType
|
|
276
|
+
break
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
} catch (e: NFCExceptions) {
|
|
280
|
+
printLog(TAG, " init_channel NFCExceptions-->$e")
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
loadPinStatus()
|
|
284
|
+
if (mCardType == AppleCardType.V2) {
|
|
285
|
+
loadBackupStatus()
|
|
286
|
+
} else {
|
|
287
|
+
hasBackup = hasSetupPin
|
|
288
|
+
}
|
|
289
|
+
printLog(TAG, "<--- initCard end")
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
fun getCardInfo(): CardState {
|
|
293
|
+
val retryCount = getRetryCount()
|
|
294
|
+
return CardState(hasBackup, !hasSetupPin, mCardSerialNumber, retryCount)
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
fun getSerialNumber() = mCardSerialNumber
|
|
298
|
+
|
|
299
|
+
fun setupNewPin(pin: String): Boolean {
|
|
300
|
+
printLog(TAG, "---> setupNewPin begin")
|
|
301
|
+
val pinHex = HexUtils.stringToHexString(pin)
|
|
302
|
+
val command = mCommandGenerator.generalCommand(
|
|
303
|
+
mCardType, CommandType.SETUP_NEW_PIN, hasOpenSafeChannel, "DFFE0B8204080006$pinHex"
|
|
304
|
+
)
|
|
305
|
+
val res = command.send(this)
|
|
306
|
+
printLog(TAG, "<--- setupNewPin end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
307
|
+
|
|
308
|
+
if (!res.isSuccess()) {
|
|
309
|
+
return false
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return true
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
fun changePin(oldPin: String, newPin: String?): Int {
|
|
316
|
+
printLog(TAG, "---> changePin begin")
|
|
317
|
+
val oldPinHex = HexUtils.stringToHexString(oldPin)
|
|
318
|
+
val newPinHex = HexUtils.stringToHexString(newPin)
|
|
319
|
+
val changePinCommand = combCommand(
|
|
320
|
+
hexString2Bytes("8204"), hexString2Bytes(oldPinHex), hexString2Bytes(newPinHex)
|
|
321
|
+
)
|
|
322
|
+
val execCommand = combCommand(hexString2Bytes("DFFE"), changePinCommand)
|
|
323
|
+
|
|
324
|
+
val command = mCommandGenerator.generalCommand(
|
|
325
|
+
mCardType, CommandType.CHANGE_PIN, hasOpenSafeChannel, byteArr2HexStr(execCommand)
|
|
326
|
+
)
|
|
327
|
+
val res = command.send(this)
|
|
328
|
+
|
|
329
|
+
printLog(TAG, "<--- changePin end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
330
|
+
|
|
331
|
+
return if (res.isConnectFailure()) {
|
|
332
|
+
NfcConstant.INTERRUPT_STATUS
|
|
333
|
+
} else if (res.isSuccess()) {
|
|
334
|
+
printLog(TAG, "--- verify success")
|
|
335
|
+
NfcConstant.CHANGE_PIN_SUCCESS
|
|
336
|
+
} else if (res.getCode() == "9B01") {
|
|
337
|
+
// V1 Lite Pin error
|
|
338
|
+
printLog(TAG, "--- verify error")
|
|
339
|
+
retryNumCommandAndReset()
|
|
340
|
+
} else if (res.getCode() == "6983") {
|
|
341
|
+
// V2 Lite Locked
|
|
342
|
+
printLog(TAG, "--- verify Too many errors, Locked")
|
|
343
|
+
resetCard()
|
|
344
|
+
} else {
|
|
345
|
+
if (res.getCode().startsWith("63C")) {
|
|
346
|
+
return res.sw2.toInt() and 0x0F
|
|
347
|
+
}
|
|
348
|
+
retryNumCommandAndReset()
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
fun startVerifyPin(pin: String): Int {
|
|
353
|
+
printLog(TAG, "---> startVerifyPin begin")
|
|
354
|
+
val pinHex = HexUtils.stringToHexString(pin)
|
|
355
|
+
val command = mCommandGenerator.generalCommand(
|
|
356
|
+
mCardType, CommandType.VERIFY_PIN, hasOpenSafeChannel, "06$pinHex"
|
|
357
|
+
)
|
|
358
|
+
val res = command.send(this)
|
|
359
|
+
printLog(TAG, "<--- startVerifyPin end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
360
|
+
|
|
361
|
+
return if (res.isConnectFailure()) {
|
|
362
|
+
NfcConstant.INTERRUPT_STATUS
|
|
363
|
+
} else if (res.isSuccess()) {
|
|
364
|
+
printLog(TAG, "--- verify success")
|
|
365
|
+
NfcConstant.VERIFY_SUCCESS
|
|
366
|
+
} else if (res.getCode() == "9B01") {
|
|
367
|
+
// V1 Lite Pin error
|
|
368
|
+
printLog(TAG, "--- verify error")
|
|
369
|
+
retryNumCommandAndReset()
|
|
370
|
+
} else if (res.getCode() == "6983") {
|
|
371
|
+
// V2 Lite Locked
|
|
372
|
+
printLog(TAG, "--- verify Too many errors, Locked")
|
|
373
|
+
resetCard()
|
|
374
|
+
} else {
|
|
375
|
+
if (res.getCode().startsWith("63C")) {
|
|
376
|
+
return res.sw2.toInt() and 0x0F
|
|
377
|
+
}
|
|
378
|
+
retryNumCommandAndReset()
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
fun backupData(mnemonic: String): Boolean {
|
|
383
|
+
printLog(TAG, "---> backupData begin")
|
|
384
|
+
val command = mCommandGenerator.generalCommand(
|
|
385
|
+
mCardType, CommandType.BACKUP_DATA, hasOpenSafeChannel, mnemonic
|
|
386
|
+
)
|
|
387
|
+
val res = command.send(this)
|
|
388
|
+
printLog(TAG, "<--- backupData end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
389
|
+
|
|
390
|
+
if (!res.isSuccess()) {
|
|
391
|
+
return false
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
return true
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
fun exportData(): String? {
|
|
398
|
+
printLog(TAG, "---> exportData begin")
|
|
399
|
+
val command = mCommandGenerator.generalCommand(
|
|
400
|
+
mCardType, CommandType.EXPORT_DATA, hasOpenSafeChannel
|
|
401
|
+
)
|
|
402
|
+
val res = command.send(this)
|
|
403
|
+
printLog(
|
|
404
|
+
TAG,
|
|
405
|
+
"<--- exportData end: ${res.getCode()} emptyData:${res.isEmptyData()} area:${mCommandArea}"
|
|
406
|
+
)
|
|
407
|
+
|
|
408
|
+
if (res.isEmptyData() || !res.isSuccess()) {
|
|
409
|
+
return null
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
return res.result
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
private fun retryNumCommandAndReset(): Int {
|
|
416
|
+
val leftRetryNum = getRetryCount()
|
|
417
|
+
return if (leftRetryNum == 0) {
|
|
418
|
+
resetCard()
|
|
419
|
+
} else {
|
|
420
|
+
leftRetryNum
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
fun resetCard(): Int {
|
|
425
|
+
printLog(TAG, "---> resetCard begin")
|
|
426
|
+
val command = mCommandGenerator.generalCommand(
|
|
427
|
+
mCardType, CommandType.RESET_CARD, hasOpenSafeChannel, "DFFE028205"
|
|
428
|
+
)
|
|
429
|
+
val res = command.send(this)
|
|
430
|
+
|
|
431
|
+
printLog(TAG, "<--- resetCard end: ${res.getCode()} ${res.data} area:${mCommandArea}")
|
|
432
|
+
|
|
433
|
+
return if (res.isConnectFailure()) {
|
|
434
|
+
NfcConstant.RESET_INTERRUPT_STATUS
|
|
435
|
+
} else {
|
|
436
|
+
NfcConstant.RESET_PIN_SUCCESS
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
package/android/src/main/java/com/onekeyfe/reactnativelitecard/onekeyLite/nfc/GPCAPDUGenerator.kt
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.onekeyLite.nfc
|
|
2
|
+
|
|
3
|
+
import com.google.gson.Gson
|
|
4
|
+
import org.haobtc.onekey.card.gpchannel.GPChannelNatives
|
|
5
|
+
import so.onekey.app.wallet.lite.onekeyLite.entitys.APDUParam
|
|
6
|
+
import so.onekey.app.wallet.lite.utils.LogUtil.printLog
|
|
7
|
+
|
|
8
|
+
object GPCAPDUGenerator {
|
|
9
|
+
private const val TAG = "GPCAPDUGenerator"
|
|
10
|
+
|
|
11
|
+
@JvmStatic
|
|
12
|
+
fun buildGPCAPDU(param: APDUParam, safeChannel: Boolean = false): String {
|
|
13
|
+
printLog(TAG, " --->> BuildGPCAPDU begin")
|
|
14
|
+
return if (safeChannel) {
|
|
15
|
+
GPChannelNatives.nativeGPCBuildSafeAPDU(
|
|
16
|
+
param.cla,
|
|
17
|
+
param.ins,
|
|
18
|
+
param.p1,
|
|
19
|
+
param.p2,
|
|
20
|
+
param.data
|
|
21
|
+
)
|
|
22
|
+
} else {
|
|
23
|
+
GPChannelNatives.nativeGPCBuildAPDU(
|
|
24
|
+
param.cla,
|
|
25
|
+
param.ins,
|
|
26
|
+
param.p1,
|
|
27
|
+
param.p2,
|
|
28
|
+
param.data
|
|
29
|
+
)
|
|
30
|
+
}.also {
|
|
31
|
+
printLog(TAG, " <<--- BuildGPCAPDU done: safeChannel:$safeChannel")
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@JvmStatic
|
|
36
|
+
fun combCommand(command: ByteArray? = null, vararg params: ByteArray?): ByteArray {
|
|
37
|
+
var combParam = byteArrayOf()
|
|
38
|
+
params.forEach { param ->
|
|
39
|
+
param?.let {
|
|
40
|
+
combParam = combParam.plus(it.size.toByte())
|
|
41
|
+
combParam = combParam.plus(it)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
var combCommand = byteArrayOf()
|
|
46
|
+
command?.let {
|
|
47
|
+
combCommand = combCommand.plus(it)
|
|
48
|
+
if (params.size != 1) {
|
|
49
|
+
// params 只有一个的时候就不再次拼接长度了
|
|
50
|
+
combCommand = combCommand.plus(combParam.size.toByte())
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
combCommand = combCommand.plus(combParam)
|
|
54
|
+
return combCommand
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
package so.onekey.app.wallet.lite.utils
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.bridge.ReactContext
|
|
4
|
+
import com.facebook.react.modules.core.DeviceEventManagerModule
|
|
5
|
+
|
|
6
|
+
fun sendEvent(
|
|
7
|
+
reactContext: ReactContext,
|
|
8
|
+
eventName: String,
|
|
9
|
+
params: String? = null
|
|
10
|
+
) {
|
|
11
|
+
reactContext
|
|
12
|
+
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
|
|
13
|
+
.emit(eventName, params)
|
|
14
|
+
}
|