@onekeyfe/react-native-lite-card 1.0.0

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