diff --git a/chameleonultragui/android/.gitignore b/chameleonultragui/android/.gitignore index 6f568019..55afd919 100644 --- a/chameleonultragui/android/.gitignore +++ b/chameleonultragui/android/.gitignore @@ -7,7 +7,7 @@ gradle-wrapper.jar GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/chameleonultragui/android/app/build.gradle b/chameleonultragui/android/app/build.gradle index 8caef025..58d87ded 100644 --- a/chameleonultragui/android/app/build.gradle +++ b/chameleonultragui/android/app/build.gradle @@ -1,30 +1,10 @@ -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterRoot = localProperties.getProperty('flutter.sdk') -if (flutterRoot == null) { - throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' +plugins { + id "com.android.application" + id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id "dev.flutter.flutter-gradle-plugin" } -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" - def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') if (keystorePropertiesFile.exists()) { @@ -32,31 +12,28 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion Math.max(flutter.compileSdkVersion, 34) - ndkVersion flutter.ndkVersion + namespace = "io.chameleon.ultra" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + jvmTarget = JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "io.chameleon.ultra" + applicationId = "io.chameleon.ultra" // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion 21 - targetSdkVersion Math.max(flutter.targetSdkVersion, 34) - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName } signingConfigs { @@ -66,19 +43,20 @@ android { storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null storePassword keystoreProperties['storePassword'] } - } - buildTypes { - release { - if (keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']).exists() : false) { - println "Info: upload-keystore.jks found. Signing for release." - signingConfig signingConfigs.release - } - else { - println "Warning: upload-keystore.jks not found. Signing for debug." - signingConfig signingConfigs.debug - } - } - } + } + + buildTypes { + release { + if (keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']).exists() : false) { + println "Info: upload-keystore.jks found. Signing for release." + signingConfig signingConfigs.release + } + else { + println "Warning: upload-keystore.jks not found. Signing for debug." + signingConfig signingConfigs.debug + } + } + } externalNativeBuild { cmake { @@ -88,10 +66,9 @@ android { } flutter { - source '../..' + source = "../.." } dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "com.polidea.rxandroidble2:rxandroidble:1.17.2" -} +} \ No newline at end of file diff --git a/chameleonultragui/android/build.gradle b/chameleonultragui/android/build.gradle index 674e96f4..d2ffbffa 100644 --- a/chameleonultragui/android/build.gradle +++ b/chameleonultragui/android/build.gradle @@ -1,16 +1,3 @@ -buildscript { - ext.kotlin_version = '1.9.0' - repositories { - google() - mavenCentral() - } - - dependencies { - classpath 'com.android.tools.build:gradle:7.2.0' - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - } -} - allprojects { repositories { google() @@ -18,12 +5,12 @@ allprojects { } } -rootProject.buildDir = '../build' +rootProject.buildDir = "../build" subprojects { project.buildDir = "${rootProject.buildDir}/${project.name}" } subprojects { - project.evaluationDependsOn(':app') + project.evaluationDependsOn(":app") } tasks.register("clean", Delete) { diff --git a/chameleonultragui/android/gradle.properties b/chameleonultragui/android/gradle.properties index 94adc3a3..25971708 100644 --- a/chameleonultragui/android/gradle.properties +++ b/chameleonultragui/android/gradle.properties @@ -1,3 +1,3 @@ -org.gradle.jvmargs=-Xmx1536M +org.gradle.jvmargs=-Xmx4G -XX:MaxMetaspaceSize=2G -XX:+HeapDumpOnOutOfMemoryError android.useAndroidX=true android.enableJetifier=true diff --git a/chameleonultragui/android/gradle/wrapper/gradle-wrapper.properties b/chameleonultragui/android/gradle/wrapper/gradle-wrapper.properties index 3c472b99..e1ca574e 100644 --- a/chameleonultragui/android/gradle/wrapper/gradle-wrapper.properties +++ b/chameleonultragui/android/gradle/wrapper/gradle-wrapper.properties @@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip diff --git a/chameleonultragui/android/settings.gradle b/chameleonultragui/android/settings.gradle index 44e62bcf..264db3c0 100644 --- a/chameleonultragui/android/settings.gradle +++ b/chameleonultragui/android/settings.gradle @@ -1,11 +1,25 @@ -include ':app' +pluginManagement { + def flutterSdkPath = { + def properties = new Properties() + file("local.properties").withInputStream { properties.load(it) } + def flutterSdkPath = properties.getProperty("flutter.sdk") + assert flutterSdkPath != null, "flutter.sdk not set in local.properties" + return flutterSdkPath + }() -def localPropertiesFile = new File(rootProject.projectDir, "local.properties") -def properties = new Properties() + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") -assert localPropertiesFile.exists() -localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) } + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} -def flutterSdkPath = properties.getProperty("flutter.sdk") -assert flutterSdkPath != null, "flutter.sdk not set in local.properties" -apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle" +plugins { + id "dev.flutter.flutter-plugin-loader" version "1.0.0" + id "com.android.application" version "7.3.0" apply false + id "org.jetbrains.kotlin.android" version "2.0.21" apply false +} + +include ":app" diff --git a/chameleonultragui/ios/Flutter/AppFrameworkInfo.plist b/chameleonultragui/ios/Flutter/AppFrameworkInfo.plist index 9625e105..7c569640 100644 --- a/chameleonultragui/ios/Flutter/AppFrameworkInfo.plist +++ b/chameleonultragui/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/chameleonultragui/ios/Podfile b/chameleonultragui/ios/Podfile index 17b3c5a1..842bb4a7 100644 --- a/chameleonultragui/ios/Podfile +++ b/chameleonultragui/ios/Podfile @@ -1,4 +1,4 @@ -platform :ios, '11.0' +platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/chameleonultragui/ios/Podfile.lock b/chameleonultragui/ios/Podfile.lock new file mode 100644 index 00000000..8e02bf6b --- /dev/null +++ b/chameleonultragui/ios/Podfile.lock @@ -0,0 +1,214 @@ +PODS: + - DKImagePickerController/Core (4.3.9): + - DKImagePickerController/ImageDataManager + - DKImagePickerController/Resource + - DKImagePickerController/ImageDataManager (4.3.9) + - DKImagePickerController/PhotoGallery (4.3.9): + - DKImagePickerController/Core + - DKPhotoGallery + - DKImagePickerController/Resource (4.3.9) + - DKPhotoGallery (0.0.19): + - DKPhotoGallery/Core (= 0.0.19) + - DKPhotoGallery/Model (= 0.0.19) + - DKPhotoGallery/Preview (= 0.0.19) + - DKPhotoGallery/Resource (= 0.0.19) + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Core (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Preview + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Model (0.0.19): + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Preview (0.0.19): + - DKPhotoGallery/Model + - DKPhotoGallery/Resource + - SDWebImage + - SwiftyGif + - DKPhotoGallery/Resource (0.0.19): + - SDWebImage + - SwiftyGif + - file_picker (0.0.1): + - DKImagePickerController/PhotoGallery + - Flutter + - file_saver (0.0.1): + - Flutter + - Flutter (1.0.0) + - GoogleDataTransport (9.4.1): + - GoogleUtilities/Environment (~> 7.7) + - nanopb (< 2.30911.0, >= 2.30908.0) + - PromisesObjC (< 3.0, >= 1.2) + - GoogleMLKit/BarcodeScanning (6.0.0): + - GoogleMLKit/MLKitCore + - MLKitBarcodeScanning (~> 5.0.0) + - GoogleMLKit/MLKitCore (6.0.0): + - MLKitCommon (~> 11.0.0) + - GoogleToolboxForMac/Defines (4.2.1) + - GoogleToolboxForMac/Logger (4.2.1): + - GoogleToolboxForMac/Defines (= 4.2.1) + - "GoogleToolboxForMac/NSData+zlib (4.2.1)": + - GoogleToolboxForMac/Defines (= 4.2.1) + - GoogleUtilities/Environment (7.13.3): + - GoogleUtilities/Privacy + - PromisesObjC (< 3.0, >= 1.2) + - GoogleUtilities/Logger (7.13.3): + - GoogleUtilities/Environment + - GoogleUtilities/Privacy + - GoogleUtilities/Privacy (7.13.3) + - GoogleUtilities/UserDefaults (7.13.3): + - GoogleUtilities/Logger + - GoogleUtilities/Privacy + - GoogleUtilitiesComponents (1.1.0): + - GoogleUtilities/Logger + - GTMSessionFetcher/Core (3.5.0) + - MLImage (1.0.0-beta5) + - MLKitBarcodeScanning (5.0.0): + - MLKitCommon (~> 11.0) + - MLKitVision (~> 7.0) + - MLKitCommon (11.0.0): + - GoogleDataTransport (< 10.0, >= 9.4.1) + - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1) + - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)" + - GoogleUtilities/UserDefaults (< 8.0, >= 7.13.0) + - GoogleUtilitiesComponents (~> 1.0) + - GTMSessionFetcher/Core (< 4.0, >= 3.3.2) + - MLKitVision (7.0.0): + - GoogleToolboxForMac/Logger (< 5.0, >= 4.2.1) + - "GoogleToolboxForMac/NSData+zlib (< 5.0, >= 4.2.1)" + - GTMSessionFetcher/Core (< 4.0, >= 3.3.2) + - MLImage (= 1.0.0-beta5) + - MLKitCommon (~> 11.0) + - mobile_scanner (5.1.1): + - Flutter + - GoogleMLKit/BarcodeScanning (~> 6.0.0) + - nanopb (2.30910.0): + - nanopb/decode (= 2.30910.0) + - nanopb/encode (= 2.30910.0) + - nanopb/decode (2.30910.0) + - nanopb/encode (2.30910.0) + - package_info_plus (0.4.5): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - permission_handler_apple (9.3.0): + - Flutter + - PromisesObjC (2.4.0) + - Protobuf (3.27.2) + - reactive_ble_mobile (0.0.1): + - Flutter + - Protobuf (~> 3.5) + - SwiftProtobuf (~> 1.0) + - recovery (0.0.1): + - Flutter + - SDWebImage (5.19.4): + - SDWebImage/Core (= 5.19.4) + - SDWebImage/Core (5.19.4) + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - SwiftProtobuf (1.27.1) + - SwiftyGif (5.4.5) + - url_launcher_ios (0.0.1): + - Flutter + - wakelock_plus (0.0.1): + - Flutter + +DEPENDENCIES: + - file_picker (from `.symlinks/plugins/file_picker/ios`) + - file_saver (from `.symlinks/plugins/file_saver/ios`) + - Flutter (from `Flutter`) + - mobile_scanner (from `.symlinks/plugins/mobile_scanner/ios`) + - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) + - reactive_ble_mobile (from `.symlinks/plugins/reactive_ble_mobile/ios`) + - recovery (from `./recovery.podspec`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) + - wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`) + +SPEC REPOS: + trunk: + - DKImagePickerController + - DKPhotoGallery + - GoogleDataTransport + - GoogleMLKit + - GoogleToolboxForMac + - GoogleUtilities + - GoogleUtilitiesComponents + - GTMSessionFetcher + - MLImage + - MLKitBarcodeScanning + - MLKitCommon + - MLKitVision + - nanopb + - PromisesObjC + - Protobuf + - SDWebImage + - SwiftProtobuf + - SwiftyGif + +EXTERNAL SOURCES: + file_picker: + :path: ".symlinks/plugins/file_picker/ios" + file_saver: + :path: ".symlinks/plugins/file_saver/ios" + Flutter: + :path: Flutter + mobile_scanner: + :path: ".symlinks/plugins/mobile_scanner/ios" + package_info_plus: + :path: ".symlinks/plugins/package_info_plus/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + permission_handler_apple: + :path: ".symlinks/plugins/permission_handler_apple/ios" + reactive_ble_mobile: + :path: ".symlinks/plugins/reactive_ble_mobile/ios" + recovery: + :path: "./recovery.podspec" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + url_launcher_ios: + :path: ".symlinks/plugins/url_launcher_ios/ios" + wakelock_plus: + :path: ".symlinks/plugins/wakelock_plus/ios" + +SPEC CHECKSUMS: + DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c + DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 + file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + file_saver: 503e386464dbe118f630e17b4c2e1190fa0cf808 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a + GoogleMLKit: 97ac7af399057e99182ee8edfa8249e3226a4065 + GoogleToolboxForMac: d1a2cbf009c453f4d6ded37c105e2f67a32206d8 + GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15 + GoogleUtilitiesComponents: 679b2c881db3b615a2777504623df6122dd20afe + GTMSessionFetcher: 5aea5ba6bd522a239e236100971f10cb71b96ab6 + MLImage: 1824212150da33ef225fbd3dc49f184cf611046c + MLKitBarcodeScanning: 10ca0845a6d15f2f6e911f682a1998b68b973e8b + MLKitCommon: afec63980417d29ffbb4790529a1b0a2291699e1 + MLKitVision: e858c5f125ecc288e4a31127928301eaba9ae0c1 + mobile_scanner: 8564358885a9253c43f822435b70f9345c87224f + nanopb: 438bc412db1928dac798aa6fd75726007be04262 + package_info_plus: 58f0028419748fad15bf008b270aaa8e54380b1c + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 + PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 + Protobuf: fb2c13674723f76ff6eede14f78847a776455fa2 + reactive_ble_mobile: 9ce6723d37ccf701dbffd202d487f23f5de03b4c + recovery: 2514f094eb85cb1660b8a85b6937a4473b1db89d + SDWebImage: 066c47b573f408f18caa467d71deace7c0f8280d + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + SwiftProtobuf: b109bd17979d7993a84da14b1e1fdd8b0ded934a + SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 + url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe + wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 + +PODFILE CHECKSUM: 4e2832874d7b4657aae7c8959ebc9b6aee0be9ad + +COCOAPODS: 1.15.2 diff --git a/chameleonultragui/ios/Runner.xcodeproj/project.pbxproj b/chameleonultragui/ios/Runner.xcodeproj/project.pbxproj index f82455f3..ed62fb45 100644 --- a/chameleonultragui/ios/Runner.xcodeproj/project.pbxproj +++ b/chameleonultragui/ios/Runner.xcodeproj/project.pbxproj @@ -366,7 +366,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; @@ -448,7 +448,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -497,7 +497,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 11.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SUPPORTED_PLATFORMS = iphoneos; diff --git a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fab..53611299 100644 --- a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1,122 @@ { "images" : [ { - "size" : "20x20", - "idiom" : "iphone", "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" }, { - "size" : "20x20", - "idiom" : "iphone", "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" }, { - "size" : "29x29", - "idiom" : "iphone", "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" + "idiom" : "iphone", + "scale" : "1x", + "size" : "29x29" }, { - "size" : "29x29", - "idiom" : "iphone", "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" }, { - "size" : "29x29", - "idiom" : "iphone", "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" }, { - "size" : "40x40", - "idiom" : "iphone", "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" }, { - "size" : "40x40", - "idiom" : "iphone", "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" }, { - "size" : "60x60", - "idiom" : "iphone", "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" }, { - "size" : "60x60", - "idiom" : "iphone", "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" }, { - "size" : "20x20", - "idiom" : "ipad", "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" }, { - "size" : "20x20", - "idiom" : "ipad", "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" }, { - "size" : "29x29", - "idiom" : "ipad", "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" }, { - "size" : "29x29", - "idiom" : "ipad", "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" }, { - "size" : "40x40", - "idiom" : "ipad", "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" }, { - "size" : "40x40", - "idiom" : "ipad", "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" }, { - "size" : "76x76", - "idiom" : "ipad", "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" }, { - "size" : "76x76", - "idiom" : "ipad", "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" }, { - "size" : "83.5x83.5", - "idiom" : "ipad", "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" }, { - "size" : "1024x1024", - "idiom" : "ios-marketing", "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" } ], "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } } diff --git a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png deleted file mode 100644 index e93a8a86..00000000 Binary files a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@1x.png and /dev/null differ diff --git a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png deleted file mode 100644 index 74901e14..00000000 Binary files a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-50x50@2x.png and /dev/null differ diff --git a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png deleted file mode 100644 index 8fadf1c3..00000000 Binary files a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@1x.png and /dev/null differ diff --git a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png deleted file mode 100644 index 1cdd9269..00000000 Binary files a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-57x57@2x.png and /dev/null differ diff --git a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png deleted file mode 100644 index bc6f6b53..00000000 Binary files a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@1x.png and /dev/null differ diff --git a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png b/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png deleted file mode 100644 index 3c7238a2..00000000 Binary files a/chameleonultragui/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-72x72@2x.png and /dev/null differ diff --git a/chameleonultragui/lib/bridge/chameleon.dart b/chameleonultragui/lib/bridge/chameleon.dart index cc215b87..1268e048 100644 --- a/chameleonultragui/lib/bridge/chameleon.dart +++ b/chameleonultragui/lib/bridge/chameleon.dart @@ -70,6 +70,8 @@ enum ChameleonCommand { mf1CheckKey(2007), mf1ReadBlock(2008), mf1WriteBlock(2009), + mf1ManipulateValueBlock(2011), + mf1CheckKeysOfSectors(2012), // not implemented hf14ARawCommand(2010), // lf commands @@ -96,6 +98,19 @@ enum ChameleonCommand { mf1GetWriteMode(4016), mf1SetWriteMode(4017), + mf0NtagGetUidMagicMode(4019), + mf0NtagSetUidMagicMode(4020), + mf0NtagReadEmuPageData(4021), + mf0NtagWriteEmuPageData(4022), + mf0NtagGetVersionData(4023), + mf0NtagSetVersionData(4024), + mf0NtagGetSignatureData(4025), + mf0NtagSetSignatureData(4026), + mf0NtagGetCounterData(4027), + mf0NtagSetCounterData(4028), + mf0NtagResetAuthCount(4029), + mf0NtagGetPageCount(4030), + // read slot info mf1GetBlockData(4008), mf1GetAntiCollData(4018), @@ -115,9 +130,15 @@ enum TagType { mifare1K(1001), mifare2K(1002), mifare4K(1003), + ntag210(1107), + ntag212(1108), ntag213(1100), ntag215(1101), - ntag216(1102); + ntag216(1102), + ultralight(1103), + ultralightC(1104), + ultralight11(1105), + ultralight21(1106); const TagType(this.value); final int value; @@ -334,6 +355,15 @@ class DeviceSettings { this.key = ""}); } +enum MifareClassicValueBlockOperator { + decrement(0xC0), + increment(0xC1), + restore(0xC2); + + const MifareClassicValueBlockOperator(this.value); + final int value; +} + // Some ChatGPT magic // Nobody knows how it works @@ -1148,6 +1178,31 @@ class ChameleonCommunicator { return commands; } + Future manipulateValueBlock( + int srcBlock, + int srcKeyType, + Uint8List srcKey, + MifareClassicValueBlockOperator op, + int value, + int dstBlock, + int dstKeyType, + Uint8List dstKey) async { + await sendCmd(ChameleonCommand.mf1ManipulateValueBlock, + data: Uint8List.fromList([ + srcKeyType, + srcBlock, + ...srcKey, + op.value, + value >> 24, + value >> 16 & 0xFF, + value >> 8 & 0xFF, + value & 0xFF, + dstKeyType, + dstBlock, + ...dstKey + ])); + } + Future send14ARaw(Uint8List data, {int respTimeoutMs = 100, int? bitLen, @@ -1188,4 +1243,69 @@ class ChameleonCommunicator { ])))! .data; } + + Future mf0GetMagicMode() async { + return (await sendCmd(ChameleonCommand.mf0NtagGetUidMagicMode))!.data[0] == + 1; + } + + Future mf0SetMagicMode(bool enabled) async { + await sendCmd(ChameleonCommand.mf0NtagSetUidMagicMode, + data: Uint8List.fromList([enabled ? 1 : 0])); + } + + Future mf0EmulatorReadPages(int from, int count) async { + return (await sendCmd(ChameleonCommand.mf0NtagReadEmuPageData, + data: Uint8List.fromList([from, count])))! + .data; + } + + Future mf0EmulatorWritePages(int from, Uint8List data) async { + await sendCmd(ChameleonCommand.mf0NtagWriteEmuPageData, + data: Uint8List.fromList([from, data.length >> 2, ...data])); + } + + Future mf0EmulatorGetVersionData() async { + return (await sendCmd(ChameleonCommand.mf0NtagGetVersionData))!.data; + } + + Future mf0EmulatorSetVersionData(Uint8List data) async { + await sendCmd(ChameleonCommand.mf0NtagSetVersionData, + data: Uint8List.fromList([...data])); + } + + Future mf0EmulatorGetSignatureData() async { + return (await sendCmd(ChameleonCommand.mf0NtagGetSignatureData))!.data; + } + + Future mf0EmulatorSetSignatureData(Uint8List data) async { + await sendCmd(ChameleonCommand.mf0NtagSetSignatureData, + data: Uint8List.fromList([...data])); + } + + Future mf0ResetAuthCount() async { + return (await sendCmd(ChameleonCommand.mf0NtagResetAuthCount))!.data[0]; + } + + Future mf0EmulatorGetPageCount() async { + return (await sendCmd(ChameleonCommand.mf0NtagGetPageCount))!.data[0]; + } + + Future<(int, bool)> mf0EmulatorGetCounterData(int index) async { + Uint8List data = (await sendCmd(ChameleonCommand.mf0NtagGetCounterData, + data: Uint8List.fromList([index])))! + .data; + return (((data[0] << 16) | (data[1] << 8) | data[2]), data[3] == 0xBD); + } + + Future mf0EmulatorSetCounterData( + int index, int value, bool resetTearing) async { + await sendCmd(ChameleonCommand.mf0NtagSetCounterData, + data: Uint8List.fromList([ + index | ((resetTearing ? 1 : 0) << 7), + (value >> 16) & 0xFF, + (value >> 8) & 0xFF, + value & 0xFF + ])); + } } diff --git a/chameleonultragui/lib/gui/component/card_list.dart b/chameleonultragui/lib/gui/component/card_list.dart index 68710386..55009981 100644 --- a/chameleonultragui/lib/gui/component/card_list.dart +++ b/chameleonultragui/lib/gui/component/card_list.dart @@ -1,6 +1,5 @@ import 'package:chameleonultragui/bridge/chameleon.dart'; import 'package:chameleonultragui/helpers/general.dart'; -import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; import 'package:flutter/material.dart'; @@ -157,10 +156,7 @@ class CardSearchDelegate extends SearchDelegate { color: card.color), title: Text(card.name), subtitle: Text( - chameleonTagToString(card.tag) + - ((chameleonTagSaveCheckForMifareClassicEV1(card)) - ? " EV1" - : ""), + chameleonCardToString(card), maxLines: 2, overflow: TextOverflow.ellipsis, ), diff --git a/chameleonultragui/lib/gui/component/card_recovery.dart b/chameleonultragui/lib/gui/component/mifare/classic.dart similarity index 97% rename from chameleonultragui/lib/gui/component/card_recovery.dart rename to chameleonultragui/lib/gui/component/mifare/classic.dart index 11f96528..fb2ffd1e 100644 --- a/chameleonultragui/lib/gui/component/card_recovery.dart +++ b/chameleonultragui/lib/gui/component/mifare/classic.dart @@ -19,22 +19,22 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; -class CardRecovery extends StatefulWidget { +class MifareClassicHelper extends StatefulWidget { final HFCardInfo hfInfo; final MifareClassicInfo mfcInfo; final bool allowSave; - const CardRecovery( + const MifareClassicHelper( {super.key, required this.hfInfo, required this.mfcInfo, this.allowSave = true}); @override - State createState() => CardRecoveryState(); + State createState() => CardReaderState(); } -class CardRecoveryState extends State { +class CardReaderState extends State { String dumpName = ""; bool skipDefaultDictionary = false; @@ -47,7 +47,7 @@ class CardRecoveryState extends State { ); } - Future saveHFCard({bool bin = false, bool skipDump = false}) async { + Future saveCard({bool bin = false, bool skipDump = false}) async { var appState = Provider.of(context, listen: false); List cardDump = []; @@ -396,7 +396,7 @@ class CardRecoveryState extends State { actions: [ ElevatedButton( onPressed: () async { - await saveHFCard(); + await saveCard(); if (context.mounted) { Navigator.pop(context); } @@ -420,7 +420,7 @@ class CardRecoveryState extends State { const SizedBox(width: 8), ElevatedButton( onPressed: () async { - await saveHFCard(bin: true); + await saveCard(bin: true); }, child: Text(localizations.save_as(".bin")), ), diff --git a/chameleonultragui/lib/gui/component/mifare/ultralight.dart b/chameleonultragui/lib/gui/component/mifare/ultralight.dart new file mode 100644 index 00000000..614af6a1 --- /dev/null +++ b/chameleonultragui/lib/gui/component/mifare/ultralight.dart @@ -0,0 +1,269 @@ +import 'dart:io'; +import 'dart:typed_data'; + +import 'package:chameleonultragui/gui/component/error_message.dart'; +import 'package:chameleonultragui/gui/page/read_card.dart'; +import 'package:chameleonultragui/helpers/general.dart'; +import 'package:chameleonultragui/helpers/mifare_ultralight/general.dart'; +import 'package:chameleonultragui/main.dart'; +import 'package:chameleonultragui/sharedprefsprovider.dart'; +import 'package:collection/collection.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:file_saver/file_saver.dart'; +import 'package:flutter/material.dart'; + +// Localizations +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:provider/provider.dart'; + +enum MifareUltralightState { none, read, save } + +class MifareUltralightHelper extends StatefulWidget { + final HFCardInfo hfInfo; + final bool allowSave; + + const MifareUltralightHelper( + {super.key, required this.hfInfo, this.allowSave = true}); + + @override + State createState() => CardReaderState(); +} + +class CardReaderState extends State { + TextEditingController keyController = TextEditingController(); + MifareUltralightState state = MifareUltralightState.none; + final GlobalKey formKey = GlobalKey(); + List cardData = []; + String version = ""; + String signature = ""; + String dumpName = ""; + String error = ""; + double progress = -1; + + Future readCard({bool withPassword = false}) async { + var appState = Provider.of(context, listen: false); + var localizations = AppLocalizations.of(context)!; + Uint8List? pack; + setState(() { + cardData = []; + error = ""; + state = MifareUltralightState.read; + }); + + for (var page = 0; + page < mfUltralightGetPagesCount(widget.hfInfo.type); + page++) { + if (withPassword) { + pack = await appState.communicator!.send14ARaw( + Uint8List.fromList([0x1B, ...hexToBytes(keyController.text)]), + keepRfField: true); + if (pack.length < 2) { + setState(() { + state = MifareUltralightState.none; + error = localizations.invalid_password; + }); + return; + } + } + + Uint8List pageData = await appState.communicator! + .send14ARaw(Uint8List.fromList([0x30, page])); + if (pageData.isNotEmpty) { + cardData.add(Uint8List.fromList(pageData.slice(0, 4).toList())); + } else { + cardData.add(Uint8List(0)); + } + + setState(() { + progress = page / mfUltralightGetPagesCount(widget.hfInfo.type); + }); + } + + version = + bytesToHexSpace(await mfUltralightGetVersion(appState.communicator!)); + signature = + bytesToHexSpace(await mfUltralightGetSignature(appState.communicator!)); + + // Save password to dump if was used + int passwordPage = mfUltralightGetPasswordPage(widget.hfInfo.type); + if (passwordPage != 0 && withPassword) { + cardData[passwordPage] = hexToBytes(keyController.text); + for (var byte = 0; byte < pack!.length; byte++) { + cardData[passwordPage + 1][byte] = pack[byte]; + } + } + + setState(() { + error = ""; + state = MifareUltralightState.save; + }); + } + + Future saveCard({bool bin = false}) async { + var appState = Provider.of(context, listen: false); + + List cardDump = []; + var localizations = AppLocalizations.of(context)!; + for (var page = 0; + page < mfUltralightGetPagesCount(widget.hfInfo.type); + page++) { + if (cardData[page].isEmpty) { + cardDump.addAll(Uint8List(4)); + } else { + cardDump.addAll(cardData[page]); + } + } + + if (bin) { + try { + await FileSaver.instance.saveAs( + name: widget.hfInfo.uid.replaceAll(" ", ""), + bytes: Uint8List.fromList(cardDump), + ext: 'bin', + mimeType: MimeType.other); + } on UnimplementedError catch (_) { + String? outputFile = await FilePicker.platform.saveFile( + dialogTitle: '${localizations.output_file}:', + fileName: '${widget.hfInfo.uid.replaceAll(" ", "")}.bin', + ); + + if (outputFile != null) { + var file = File(outputFile); + await file.writeAsBytes(Uint8List.fromList(cardDump)); + } + } + } else { + var tags = appState.sharedPreferencesProvider.getCards(); + tags.add(CardSave( + uid: widget.hfInfo.uid, + sak: hexToBytes(widget.hfInfo.sak)[0], + atqa: hexToBytes(widget.hfInfo.atqa), + name: dumpName, + tag: widget.hfInfo.type, + data: cardData, + extraData: CardSaveExtra( + ultralightSignature: hexToBytes(signature), + ultralightVersion: hexToBytes(version), + ), + ats: (widget.hfInfo.ats != localizations.no) + ? hexToBytes(widget.hfInfo.ats) + : Uint8List(0))); + appState.sharedPreferencesProvider.setCards(tags); + } + } + + @override + Widget build(BuildContext context) { + var localizations = AppLocalizations.of(context)!; + + return Column( + children: [ + const SizedBox(height: 16), + if (state == MifareUltralightState.none) ...[ + Form( + key: formKey, + autovalidateMode: AutovalidateMode.onUserInteraction, + child: Column( + children: [ + TextFormField( + controller: keyController, + decoration: InputDecoration( + labelText: localizations.key, + hintMaxLines: 4, + hintText: localizations.enter_something( + localizations.ultralight_key_prompt)), + validator: (String? value) { + if (value!.isNotEmpty && !isValidHexString(value)) { + return localizations.must_be_valid_hex; + } + + if (value.length != 8) { + return localizations.must_be(4, localizations.key); + } + + return null; + }, + ), + ], + ), + ), + const SizedBox(height: 8), + Row(children: [ + Expanded( + child: TextButton( + onPressed: () async => {await readCard(withPassword: true)}, + child: Text(localizations.read_with_key), + ), + ), + Expanded( + child: TextButton( + onPressed: () async => {await readCard(withPassword: false)}, + child: Text(localizations.read_without_key), + ), + ), + ]), + ], + if (error != "") ...[ + const SizedBox(height: 16), + ErrorMessage(errorMessage: error), + ], + if (state == MifareUltralightState.read) ...[ + LinearProgressIndicator(value: progress), + const SizedBox(height: 8) + ], + if (state == MifareUltralightState.save) + Center( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () async { + await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: Text(localizations.enter_name_of_card), + content: TextField( + onChanged: (value) { + setState(() { + dumpName = value; + }); + }, + ), + actions: [ + ElevatedButton( + onPressed: () async { + await saveCard(); + if (context.mounted) { + Navigator.pop(context); + } + }, + child: Text(localizations.ok), + ), + ElevatedButton( + onPressed: () { + Navigator.pop( + context); // Close the modal without saving + }, + child: Text(localizations.cancel), + ), + ], + ); + }, + ); + }, + child: Text(localizations.save), + ), + const SizedBox(width: 8), + ElevatedButton( + onPressed: () async { + await saveCard(bin: true); + }, + child: Text(localizations.save_as(".bin")), + ), + ])), + ], + ); + } +} diff --git a/chameleonultragui/lib/gui/menu/card_edit.dart b/chameleonultragui/lib/gui/menu/card_edit.dart index 7d6c0107..f2758723 100644 --- a/chameleonultragui/lib/gui/menu/card_edit.dart +++ b/chameleonultragui/lib/gui/menu/card_edit.dart @@ -1,4 +1,4 @@ -import 'package:chameleonultragui/helpers/ntag/general.dart'; +import 'package:chameleonultragui/helpers/mifare_ultralight/general.dart'; import 'package:flutter/material.dart'; import 'package:chameleonultragui/helpers/general.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; @@ -27,6 +27,8 @@ class CardEditMenuState extends State { TextEditingController sakController = TextEditingController(); TextEditingController atqaController = TextEditingController(); TextEditingController atsController = TextEditingController(); + TextEditingController ultralightVersionController = TextEditingController(); + TextEditingController ultralightSignatureController = TextEditingController(); Color pickerColor = Colors.deepOrange; Color currentColor = Colors.deepOrange; final GlobalKey _formKey = GlobalKey(); @@ -39,6 +41,10 @@ class CardEditMenuState extends State { sakController.text = bytesToHexSpace(u8ToBytes(widget.tagSave.sak)); atqaController.text = bytesToHexSpace(widget.tagSave.atqa); atsController.text = bytesToHexSpace(widget.tagSave.ats); + ultralightVersionController.text = + bytesToHexSpace(widget.tagSave.extraData.ultralightVersion); + ultralightSignatureController.text = + bytesToHexSpace(widget.tagSave.extraData.ultralightSignature); nameController.text = widget.tagSave.name; pickerColor = widget.tagSave.color; currentColor = widget.tagSave.color; @@ -130,17 +136,8 @@ class CardEditMenuState extends State { const SizedBox(height: 8), DropdownButton( value: selectedType, - items: [ - TagType.mifare1K, - TagType.mifare2K, - TagType.mifare4K, - TagType.mifareMini, - TagType.ntag213, - TagType.ntag215, - TagType.ntag216, - TagType.em410X, - TagType.unknown - ].map>((TagType type) { + items: getTagTypes() + .map>((TagType type) { return DropdownMenuItem( value: type, child: Text( @@ -149,7 +146,7 @@ class CardEditMenuState extends State { ); }).toList(), onChanged: (TagType? newValue) { - if (newValue != TagType.unknown && !isNTAG(newValue!)) { + if (newValue! != TagType.unknown) { setState(() { selectedType = newValue; }); @@ -252,6 +249,44 @@ class CardEditMenuState extends State { } return null; }), + if (isMifareUltralight(selectedType)) ...[ + const SizedBox(height: 20), + TextFormField( + controller: ultralightVersionController, + decoration: InputDecoration( + labelText: localizations.ultralight_version, + hintText: localizations.enter_something( + localizations.ultralight_version)), + validator: (value) { + if (value!.replaceAll(" ", "").length % 2 != + 0) { + return localizations.must_be_valid_hex; + } + + if (value.isNotEmpty && + value.replaceAll(" ", "").length != 16 && + isMifareUltralight(selectedType)) { + return localizations.must_be( + 8, localizations.ultralight_version); + } + + return null; + }), + const SizedBox(height: 20), + TextFormField( + controller: ultralightSignatureController, + decoration: InputDecoration( + labelText: localizations.ultralight_signature, + hintText: localizations.enter_something( + localizations.ultralight_signature)), + validator: (value) { + if (value!.replaceAll(" ", "").length % 2 != + 0) { + return localizations.must_be_valid_hex; + } + return null; + }), + ] ])) ]), ) @@ -280,6 +315,12 @@ class CardEditMenuState extends State { : hexToBytes(sakController.text)[0], atqa: hexToBytes(atqaController.text), uid: bytesToHexSpace(hexToBytes(uidController.text)), + extraData: CardSaveExtra( + ultralightSignature: + hexToBytes(ultralightSignatureController.text), + ultralightVersion: + hexToBytes(ultralightVersionController.text), + ), tag: selectedType, data: widget.tagSave.data, color: currentColor, diff --git a/chameleonultragui/lib/gui/menu/card_view.dart b/chameleonultragui/lib/gui/menu/card_view.dart index 723af9c3..5e8560bd 100644 --- a/chameleonultragui/lib/gui/menu/card_view.dart +++ b/chameleonultragui/lib/gui/menu/card_view.dart @@ -2,6 +2,7 @@ import 'package:chameleonultragui/bridge/chameleon.dart'; import 'package:chameleonultragui/gui/menu/card_edit.dart'; import 'package:chameleonultragui/gui/menu/dictionary_export.dart'; import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; +import 'package:chameleonultragui/helpers/mifare_ultralight/general.dart'; import 'package:flutter/material.dart'; import 'package:chameleonultragui/helpers/general.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; @@ -61,66 +62,102 @@ class CardViewMenuState extends State { ), ], ), - ...(chameleonTagToFrequency(widget.tagSave.tag) == TagFrequency.hf) - ? [ - Row( - children: [ - Text( - "${localizations.sak}: ${widget.tagSave.sak == 0 ? localizations.unavailable : bytesToHex(u8ToBytes(widget.tagSave.sak))}"), - IconButton( - onPressed: () async { - ClipboardData data = ClipboardData( - text: widget.tagSave.sak == 0 - ? localizations.unavailable - : bytesToHex(u8ToBytes(widget.tagSave.sak))); - await Clipboard.setData(data); - }, - icon: const Icon(Icons.copy), - ), - ], - ), - Row( - children: [ - Text( - "${localizations.atqa}: ${widget.tagSave.atqa.isNotEmpty ? bytesToHexSpace(widget.tagSave.atqa) : localizations.unavailable}"), - IconButton( - onPressed: () async { - ClipboardData data = ClipboardData( - text: widget.tagSave.atqa.isNotEmpty - ? bytesToHex(widget.tagSave.atqa) - : localizations.unavailable); - await Clipboard.setData(data); - }, - icon: const Icon(Icons.copy), - ), - ], - ), - if (isMifareClassic(widget.tagSave.tag)) - Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const SizedBox(height: 8), - ElevatedButton( - onPressed: (mfClassicGetKeysFromDump( - widget.tagSave.data) - .isNotEmpty) - ? () async { - List keys = - mfClassicGetKeysFromDump( - widget.tagSave.data); - await showDialog( - context: context, - builder: (BuildContext context) { - return DictionaryExportMenu(keys: keys); - }, - ); - } - : null, - child: Text(localizations.export_to_dictionary)), - ], - ) - ] - : [], + if (chameleonTagToFrequency(widget.tagSave.tag) == + TagFrequency.hf) ...[ + Row( + children: [ + Text( + "${localizations.sak}: ${bytesToHex(u8ToBytes(widget.tagSave.sak))}"), + IconButton( + onPressed: () async { + ClipboardData data = ClipboardData( + text: widget.tagSave.sak == 0 + ? localizations.unavailable + : bytesToHex(u8ToBytes(widget.tagSave.sak))); + await Clipboard.setData(data); + }, + icon: const Icon(Icons.copy), + ), + ], + ), + Row( + children: [ + Text( + "${localizations.atqa}: ${widget.tagSave.atqa.isNotEmpty ? bytesToHexSpace(widget.tagSave.atqa) : localizations.unavailable}"), + IconButton( + onPressed: () async { + ClipboardData data = ClipboardData( + text: widget.tagSave.atqa.isNotEmpty + ? bytesToHex(widget.tagSave.atqa) + : localizations.unavailable); + await Clipboard.setData(data); + }, + icon: const Icon(Icons.copy), + ), + ], + ), + if (isMifareClassic(widget.tagSave.tag)) + Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const SizedBox(height: 8), + ElevatedButton( + onPressed: (mfClassicGetKeysFromDump(widget.tagSave.data) + .isNotEmpty) + ? () async { + List keys = + mfClassicGetKeysFromDump(widget.tagSave.data); + await showDialog( + context: context, + builder: (BuildContext context) { + return DictionaryExportMenu(keys: keys); + }, + ); + } + : null, + child: Text(localizations.export_to_dictionary)), + ], + ), + if (isMifareUltralight(widget.tagSave.tag)) + Column(mainAxisAlignment: MainAxisAlignment.center, children: [ + Row( + children: [ + Text( + "${localizations.ultralight_version}: ${widget.tagSave.extraData.ultralightVersion.isNotEmpty ? bytesToHexSpace(widget.tagSave.extraData.ultralightVersion) : localizations.unavailable}"), + IconButton( + onPressed: () async { + ClipboardData data = ClipboardData( + text: widget.tagSave.extraData.ultralightVersion + .isNotEmpty + ? bytesToHexSpace( + widget.tagSave.extraData.ultralightVersion) + : localizations.unavailable); + await Clipboard.setData(data); + }, + icon: const Icon(Icons.copy), + ), + ], + ), + Row( + children: [ + Text( + "${localizations.ultralight_signature}: ${widget.tagSave.extraData.ultralightSignature.isNotEmpty ? bytesToHexSpace(widget.tagSave.extraData.ultralightSignature) : localizations.unavailable}"), + IconButton( + onPressed: () async { + ClipboardData data = ClipboardData( + text: widget.tagSave.extraData.ultralightVersion + .isNotEmpty + ? bytesToHexSpace( + widget.tagSave.extraData.ultralightVersion) + : localizations.unavailable); + await Clipboard.setData(data); + }, + icon: const Icon(Icons.copy), + ), + ], + ), + ]) + ], ], )), actions: [ @@ -178,7 +215,8 @@ class CardViewMenuState extends State { var confirm = await showDialog( context: context, builder: (BuildContext context) { - return ConfirmDeletionMenu(thingBeingDeleted: widget.tagSave.name); + return ConfirmDeletionMenu( + thingBeingDeleted: widget.tagSave.name); }, ); diff --git a/chameleonultragui/lib/gui/menu/slot_edit.dart b/chameleonultragui/lib/gui/menu/slot_edit.dart index 5858047d..b91f3de8 100644 --- a/chameleonultragui/lib/gui/menu/slot_edit.dart +++ b/chameleonultragui/lib/gui/menu/slot_edit.dart @@ -1,7 +1,6 @@ import 'package:chameleonultragui/bridge/chameleon.dart'; import 'package:chameleonultragui/gui/component/toggle_buttons.dart'; import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; -import 'package:chameleonultragui/helpers/ntag/general.dart'; import 'package:flutter/material.dart'; import 'package:chameleonultragui/helpers/general.dart'; import 'package:provider/provider.dart'; @@ -159,7 +158,7 @@ class SlotEditMenuState extends State { ); }).toList(), onChanged: (TagType? newValue) { - if (newValue != TagType.unknown && !isNTAG(newValue!)) { + if (newValue! != TagType.unknown) { setState(() { selectedType = newValue; }); diff --git a/chameleonultragui/lib/gui/page/read_card.dart b/chameleonultragui/lib/gui/page/read_card.dart index 81b86bf4..16fa6b30 100644 --- a/chameleonultragui/lib/gui/page/read_card.dart +++ b/chameleonultragui/lib/gui/page/read_card.dart @@ -1,9 +1,11 @@ import 'package:chameleonultragui/bridge/chameleon.dart'; -import 'package:chameleonultragui/gui/component/card_recovery.dart'; +import 'package:chameleonultragui/gui/component/mifare/classic.dart'; import 'package:chameleonultragui/gui/component/error_message.dart'; +import 'package:chameleonultragui/gui/component/mifare/ultralight.dart'; import 'package:chameleonultragui/helpers/general.dart'; import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; import 'package:chameleonultragui/helpers/mifare_classic/recovery.dart'; +import 'package:chameleonultragui/helpers/mifare_ultralight/general.dart'; import 'package:chameleonultragui/main.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; import 'package:chameleonultragui/connector/serial_abstract.dart'; @@ -32,6 +34,7 @@ class HFCardInfo { String atqa; String tech; String ats; + TagType type; bool cardExist; HFCardInfo( @@ -40,6 +43,7 @@ class HFCardInfo { this.atqa = '', this.tech = '', this.ats = '', + this.type = TagType.unknown, this.cardExist = true}); } @@ -105,11 +109,14 @@ class ReadCardPageState extends State { CardData card = await appState.communicator!.scan14443aTag(); bool isMifareClassic = false; + TagType type = TagType.unknown; MifareClassicType mifareClassicType = MifareClassicType.none; try { isMifareClassic = await appState.communicator!.detectMf1Support(); - mifareClassicType = await mfClassicGetType(appState.communicator!); + if (isMifareClassic) { + mifareClassicType = await mfClassicGetType(appState.communicator!); + } } catch (_) {} bool isMifareClassicEV1 = isMifareClassic @@ -126,6 +133,16 @@ class ReadCardPageState extends State { }); } + if (!isMifareClassic) { + Uint8List version = + await mfUltralightGetVersion(appState.communicator!); + if (version.length == 8) { + type = mfUltralightGetType(version); + } + } else { + type = mfClassicGetChameleonTagType(mifareClassicType); + } + setState(() { hfInfo.uid = bytesToHexSpace(card.uid); hfInfo.sak = card.sak.toRadixString(16).padLeft(2, '0').toUpperCase(); @@ -133,14 +150,14 @@ class ReadCardPageState extends State { hfInfo.ats = (card.ats.isNotEmpty) ? bytesToHexSpace(card.ats) : localizations.no; + hfInfo.type = type; mfcInfo.isEV1 = isMifareClassicEV1; mfcInfo.type = mifareClassicType; mfcInfo.state = (mfcInfo.type != MifareClassicType.none) ? MifareClassicState.checkKeys : MifareClassicState.none; - hfInfo.tech = isMifareClassic - ? "Mifare Classic ${mfClassicGetName(mfcInfo.type)}${isMifareClassicEV1 ? " EV1" : ""}" - : localizations.other; + hfInfo.tech = + chameleonTagToString(type) + (isMifareClassicEV1 ? " EV1" : ""); }); } catch (_) { setState(() { @@ -341,8 +358,10 @@ class ReadCardPageState extends State { child: Text(localizations.save_only_uid), ), ], - if (mfcInfo.type != MifareClassicType.none) - CardRecovery(mfcInfo: mfcInfo, hfInfo: hfInfo) + if (isMifareClassic(hfInfo.type)) + MifareClassicHelper(mfcInfo: mfcInfo, hfInfo: hfInfo), + if (isMifareUltralight(hfInfo.type)) + MifareUltralightHelper(hfInfo: hfInfo) ], ), ), diff --git a/chameleonultragui/lib/gui/page/saved_cards.dart b/chameleonultragui/lib/gui/page/saved_cards.dart index 8988ff85..54e2d512 100644 --- a/chameleonultragui/lib/gui/page/saved_cards.dart +++ b/chameleonultragui/lib/gui/page/saved_cards.dart @@ -478,11 +478,7 @@ class SavedCardsPageState extends State { : Icons.wifi, iconColor: tag.color, firstLine: tag.name.isEmpty ? "⠀" : tag.name, - secondLine: chameleonTagToString(tag.tag) + - ((chameleonTagSaveCheckForMifareClassicEV1( - tag)) - ? " EV1" - : ""), + secondLine: chameleonCardToString(tag), itemIndex: index, onPressed: () { showDialog( diff --git a/chameleonultragui/lib/gui/page/settings.dart b/chameleonultragui/lib/gui/page/settings.dart index 0f635ee8..f94f1800 100644 --- a/chameleonultragui/lib/gui/page/settings.dart +++ b/chameleonultragui/lib/gui/page/settings.dart @@ -35,7 +35,7 @@ const localeNameMap = { "it": "Italiano", "ja": "日本語", "ko": "한국어", - "nl": "Dutch", + "nl": "Nederlands", "ar": "العربية ", "tr": "Türkçe", "pl": "Polski", @@ -155,7 +155,8 @@ class SettingsMainPageState extends State { selectedValue: appState.sharedPreferencesProvider.getTheme().index, onChange: (int index) async { - appState.sharedPreferencesProvider.setTheme(ThemeMode.values[index]); + appState.sharedPreferencesProvider + .setTheme(ThemeMode.values[index]); appState.changesMade(); }), const SizedBox(height: 10), @@ -224,11 +225,9 @@ class SettingsMainPageState extends State { }, items: AppLocalizations.supportedLocales.map((locale) { return DropdownMenuItem( - value: locale.toLanguageTag(), - child: Text( - localeNameMap[locale.toLanguageTag()] ?? "Unknown" - ) - ); + value: locale.toLanguageTag(), + child: Text(localeNameMap[locale.toLanguageTag()] ?? + "Unknown")); }).toList(), ), ), @@ -242,8 +241,8 @@ class SettingsMainPageState extends State { ), const SizedBox(width: 5), Switch( - value: appState.sharedPreferencesProvider - .getConfirmDelete(), + value: + appState.sharedPreferencesProvider.getConfirmDelete(), onChanged: (value) async { appState.sharedPreferencesProvider .setConfirmDelete(value); diff --git a/chameleonultragui/lib/gui/page/slot_manager.dart b/chameleonultragui/lib/gui/page/slot_manager.dart index 38caa98e..d2a5fa58 100644 --- a/chameleonultragui/lib/gui/page/slot_manager.dart +++ b/chameleonultragui/lib/gui/page/slot_manager.dart @@ -5,6 +5,7 @@ import 'package:chameleonultragui/gui/component/card_list.dart'; import 'package:chameleonultragui/gui/menu/slot_settings.dart'; import 'package:chameleonultragui/helpers/general.dart'; import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; +import 'package:chameleonultragui/helpers/mifare_ultralight/general.dart'; import 'package:chameleonultragui/main.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; import 'package:flutter/material.dart'; @@ -207,6 +208,52 @@ class SlotManagerPageState extends State { await appState.communicator!.saveSlotData(); appState.changesMade(); refreshSlot(gridPosition); + } else if (isMifareUltralight(card.tag)) { + close(context, card.name); + setUploadState(0); + + await appState.communicator!.setReaderDeviceMode(false); + await appState.communicator! + .enableSlot(gridPosition, TagFrequency.hf, true); + await appState.communicator!.activateSlot(gridPosition); + await appState.communicator!.setSlotType(gridPosition, card.tag); + await appState.communicator!.setDefaultDataToSlot(gridPosition, card.tag); + var cardData = CardData( + uid: hexToBytes(card.uid), + atqa: card.atqa, + sak: card.sak, + ats: card.ats); + await appState.communicator!.setMf1AntiCollision(cardData); + + for (var page = 0; page < mfUltralightGetPagesCount(card.tag); page++) { + await appState.communicator! + .mf0EmulatorWritePages(page, card.data[page]); + + setUploadState( + (page / mfUltralightGetPagesCount(card.tag) * 100).round()); + + await asyncSleep(1); + } + + if (card.extraData.ultralightVersion.isNotEmpty) { + await appState.communicator! + .mf0EmulatorSetVersionData(card.extraData.ultralightVersion); + } + + if (card.extraData.ultralightSignature.isNotEmpty) { + await appState.communicator! + .mf0EmulatorSetSignatureData(card.extraData.ultralightSignature); + } + + setUploadState(100); + + await appState.communicator!.setSlotTagName( + gridPosition, + (card.name.isEmpty) ? localizations.no_name : card.name, + TagFrequency.hf); + await appState.communicator!.saveSlotData(); + appState.changesMade(); + refreshSlot(gridPosition); } else { appState.log!.e("Can't write this card type yet."); close(context, card.name); diff --git a/chameleonultragui/lib/gui/page/write_card.dart b/chameleonultragui/lib/gui/page/write_card.dart index 6d29d97d..fd106e72 100644 --- a/chameleonultragui/lib/gui/page/write_card.dart +++ b/chameleonultragui/lib/gui/page/write_card.dart @@ -280,6 +280,12 @@ class WriteCardPageState extends State { @override Widget build(BuildContext context) { var localizations = AppLocalizations.of(context)!; + var typeLocalization = { + 'gen1': localizations.gen1, + 'gen2': localizations.gen2, + 'gen3': localizations.gen3, + 't55xx': localizations.t55xx, + }; return Scaffold( appBar: AppBar( @@ -345,7 +351,8 @@ class WriteCardPageState extends State { (AbstractWriteHelper helperClass) { return DropdownMenuItem( value: helperClass, - child: Text(helperClass.name), + child: + Text(typeLocalization[helperClass.name]!), ); }).toList(), onChanged: (AbstractWriteHelper? helperClass) { diff --git a/chameleonultragui/lib/helpers/general.dart b/chameleonultragui/lib/helpers/general.dart index b3be87f6..a7360300 100644 --- a/chameleonultragui/lib/helpers/general.dart +++ b/chameleonultragui/lib/helpers/general.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'dart:typed_data'; import 'package:chameleonultragui/bridge/chameleon.dart'; import 'package:chameleonultragui/connector/serial_abstract.dart'; +import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; import 'package:chameleonultragui/main.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; import 'package:file_picker/file_picker.dart'; @@ -117,17 +118,39 @@ String chameleonTagToString(TagType tag) { return "Mifare Classic 4K"; } else if (tag == TagType.em410X) { return "EM410X"; + } else if (tag == TagType.ntag210) { + return "NTAG210"; + } else if (tag == TagType.ntag212) { + return "NTAG212"; } else if (tag == TagType.ntag213) { return "NTAG213"; } else if (tag == TagType.ntag215) { return "NTAG215"; } else if (tag == TagType.ntag216) { return "NTAG216"; + } else if (tag == TagType.ultralight) { + return "Ultralight"; + } else if (tag == TagType.ultralightC) { + return "Ultralight C"; + } else if (tag == TagType.ultralight11) { + return "Ultralight EV1 (20)"; + } else if (tag == TagType.ultralight21) { + return "Ultralight EV1 (41)"; } else { return "Unknown"; } } +String chameleonCardToString(CardSave card) { + String name = chameleonTagToString(card.tag); + + if (chameleonTagSaveCheckForMifareClassicEV1(card)) { + name += " EV1"; + } + + return name; +} + TagType numberToChameleonTag(int type) { if (type == TagType.mifareMini.value) { return TagType.mifareMini; @@ -139,17 +162,49 @@ TagType numberToChameleonTag(int type) { return TagType.mifare4K; } else if (type == TagType.em410X.value) { return TagType.em410X; + } else if (type == TagType.ntag210.value) { + return TagType.ntag210; + } else if (type == TagType.ntag212.value) { + return TagType.ntag212; } else if (type == TagType.ntag213.value) { return TagType.ntag213; } else if (type == TagType.ntag215.value) { return TagType.ntag215; } else if (type == TagType.ntag216.value) { return TagType.ntag216; + } else if (type == TagType.ultralight.value) { + return TagType.ultralight; + } else if (type == TagType.ultralight11.value) { + return TagType.ultralight11; + } else if (type == TagType.ultralight21.value) { + return TagType.ultralight21; + } else if (type == TagType.ultralightC.value) { + return TagType.ultralightC; } else { return TagType.unknown; } } +List getTagTypes() { + return [ + TagType.mifare1K, + TagType.mifare2K, + TagType.mifare4K, + TagType.mifareMini, + TagType.em410X, + TagType.ultralight, + TagType.ultralightC, + TagType.ultralight11, + TagType.ultralight21, + TagType.ntag210, + TagType.ntag212, + TagType.ntag213, + TagType.ntag215, + TagType.ntag216, + TagType.unknown + ]; +} + TagType getTagTypeByValue(int value) { return TagType.values.firstWhere((element) => element.value == value, orElse: () => TagType.unknown); @@ -303,9 +358,15 @@ List getTagTypeByFrequency(TagFrequency frequency) { TagType.mifare2K, TagType.mifare4K, TagType.mifareMini, + TagType.ntag210, + TagType.ntag212, TagType.ntag213, TagType.ntag215, TagType.ntag216, + TagType.ultralight, + TagType.ultralightC, + TagType.ultralight11, + TagType.ultralight21 ]; } else if (frequency == TagFrequency.lf) { return [TagType.em410X]; diff --git a/chameleonultragui/lib/helpers/mifare_classic/write/base.dart b/chameleonultragui/lib/helpers/mifare_classic/write/base.dart index ba94827b..32cd4cd4 100644 --- a/chameleonultragui/lib/helpers/mifare_classic/write/base.dart +++ b/chameleonultragui/lib/helpers/mifare_classic/write/base.dart @@ -1,7 +1,7 @@ import 'dart:typed_data'; import 'package:chameleonultragui/bridge/chameleon.dart'; -import 'package:chameleonultragui/gui/component/card_recovery.dart'; +import 'package:chameleonultragui/gui/component/mifare/classic.dart'; import 'package:chameleonultragui/gui/page/read_card.dart'; import 'package:chameleonultragui/helpers/general.dart'; import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; @@ -18,7 +18,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:provider/provider.dart'; -class BaseMifareClassicMagicCardHelper extends AbstractWriteHelper { +class BaseMifareClassicWriteHelper extends AbstractWriteHelper { late MifareClassicRecovery recovery; late MifareClassicType type; late bool isEV1; @@ -29,7 +29,7 @@ class BaseMifareClassicMagicCardHelper extends AbstractWriteHelper { @override bool get autoDetect => true; - BaseMifareClassicMagicCardHelper(super.communicator, + BaseMifareClassicWriteHelper(super.communicator, {required this.recovery, this.type = MifareClassicType.m1k, this.isEV1 = false}); @@ -92,9 +92,16 @@ class BaseMifareClassicMagicCardHelper extends AbstractWriteHelper { } @override - Future writeData(CardSave card, dynamic update) async { + Future writeData( + CardSave card, Function(int writeProgress) update) async { List data = card.data; + try { + await communicator.scan14443aTag(); + } catch (e) { + return false; + } + if (data.isEmpty || data[0].isEmpty) { if (data.isEmpty) { data = [Uint8List(0)]; @@ -215,6 +222,12 @@ class BaseMifareClassicMagicCardHelper extends AbstractWriteHelper { setState(() { mfcInfo!.recovery = getExtraData()[0]; }); + } else { + setState(() { + hfInfo!.cardExist = false; + }); + + return; } setState(() { @@ -250,7 +263,7 @@ class BaseMifareClassicMagicCardHelper extends AbstractWriteHelper { future: (hfInfo != null) ? Future.value([]) : prepareMifareClassic(), builder: (BuildContext context, AsyncSnapshot snapshot) { if (hfInfo != null && mfcInfo != null && mfcInfo!.recovery != null) { - return CardRecovery( + return MifareClassicHelper( hfInfo: hfInfo!, mfcInfo: mfcInfo!, allowSave: false); } else if (hfInfo != null && mfcInfo != null && diff --git a/chameleonultragui/lib/helpers/mifare_classic/write/gen1.dart b/chameleonultragui/lib/helpers/mifare_classic/write/gen1.dart index 941a1579..08b890d5 100644 --- a/chameleonultragui/lib/helpers/mifare_classic/write/gen1.dart +++ b/chameleonultragui/lib/helpers/mifare_classic/write/gen1.dart @@ -2,13 +2,13 @@ import 'dart:typed_data'; import 'package:chameleonultragui/helpers/mifare_classic/write/base.dart'; -class MifareClassicGen1WriteHelper extends BaseMifareClassicMagicCardHelper { +class MifareClassicGen1WriteHelper extends BaseMifareClassicWriteHelper { MifareClassicGen1WriteHelper(super.communicator, {required super.recovery}); @override - String get name => "Gen1"; + String get name => "gen1"; - static String get staticName => "Gen1"; + static String get staticName => "gen1"; @override Future isMagic(dynamic data) async { diff --git a/chameleonultragui/lib/helpers/mifare_classic/write/gen2.dart b/chameleonultragui/lib/helpers/mifare_classic/write/gen2.dart index 5361b259..2a2a75fb 100644 --- a/chameleonultragui/lib/helpers/mifare_classic/write/gen2.dart +++ b/chameleonultragui/lib/helpers/mifare_classic/write/gen2.dart @@ -6,14 +6,14 @@ import 'package:chameleonultragui/helpers/mifare_classic/recovery.dart'; import 'package:chameleonultragui/helpers/mifare_classic/write/base.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; -class MifareClassicGen2WriteHelper extends BaseMifareClassicMagicCardHelper { +class MifareClassicGen2WriteHelper extends BaseMifareClassicWriteHelper { List failedBlocks = []; MifareClassicGen2WriteHelper(super.communicator, {required super.recovery}); @override - String get name => "Gen2 / Generic"; + String get name => "gen2"; - static String get staticName => "Gen2 / Generic"; + static String get staticName => "gen2"; @override Future isMagic(dynamic data) async { @@ -99,11 +99,18 @@ class MifareClassicGen2WriteHelper extends BaseMifareClassicMagicCardHelper { } @override - Future writeData(CardSave card, dynamic update) async { + Future writeData( + CardSave card, Function(int writeProgress) update) async { List data = card.data; List cleanSectors = List.generate(40, (index) => false); failedBlocks = []; + try { + await communicator.scan14443aTag(); + } catch (e) { + return false; + } + if (data.isEmpty || data[0].isEmpty) { if (data.isEmpty) { data = [Uint8List(0)]; diff --git a/chameleonultragui/lib/helpers/mifare_classic/write/gen3.dart b/chameleonultragui/lib/helpers/mifare_classic/write/gen3.dart index 2931ba15..e1d585bc 100644 --- a/chameleonultragui/lib/helpers/mifare_classic/write/gen3.dart +++ b/chameleonultragui/lib/helpers/mifare_classic/write/gen3.dart @@ -11,9 +11,9 @@ class MifareClassicGen3WriteHelper extends MifareClassicGen2WriteHelper { MifareClassicGen3WriteHelper(super.communicator, {required super.recovery}); @override - String get name => "Gen3"; + String get name => "gen3"; - static String get staticName => "Gen3"; + static String get staticName => "gen3"; @override Future isMagic(dynamic data) async { diff --git a/chameleonultragui/lib/helpers/mifare_ultralight/general.dart b/chameleonultragui/lib/helpers/mifare_ultralight/general.dart new file mode 100644 index 00000000..416e2252 --- /dev/null +++ b/chameleonultragui/lib/helpers/mifare_ultralight/general.dart @@ -0,0 +1,100 @@ +import 'package:chameleonultragui/bridge/chameleon.dart'; +import 'package:chameleonultragui/helpers/general.dart'; +import 'package:flutter/services.dart'; + +bool isMifareUltralight(TagType type) { + return [ + TagType.ntag210, + TagType.ntag212, + TagType.ntag213, + TagType.ntag215, + TagType.ntag216, + TagType.ultralight, + TagType.ultralightC, + TagType.ultralight11, + TagType.ultralight21 + ].contains(type); +} + +Future mfUltralightGetVersion( + ChameleonCommunicator communicator) async { + return await communicator.send14ARaw(Uint8List.fromList([0x60])); +} + +Future mfUltralightGetSignature( + ChameleonCommunicator communicator) async { + Uint8List signature = + await communicator.send14ARaw(Uint8List.fromList([0x3C, 0x00])); + if (bytesToHex(signature) == bytesToHex(Uint8List(32))) { + return Uint8List(0); + } + return signature; +} + +TagType mfUltralightGetType(Uint8List version) { + // TODO: detect ultralightC/ntag210/ntag212 + if (version[6] == 0x0B || version[6] == 0x00) { + return TagType.ultralight11; + } else if (version[6] == 0x0E) { + return TagType.ultralight21; + } else if (version[6] == 0x0F) { + return TagType.ntag213; + } else if (version[6] == 0x11) { + return TagType.ntag215; + } else if (version[6] == 0x13) { + return TagType.ntag216; + } + + return TagType.ultralight; +} + +// https://www.nxp.com/docs/en/data-sheet/MF0ICU2.pdf +// https://www.nxp.com/docs/en/data-sheet/MF0ULX1.pdf +// https://www.nxp.com/docs/en/data-sheet/NTAG210_212.pdf +// https://www.nxp.com/docs/en/data-sheet/NTAG213_215_216.pdf + +int mfUltralightGetPagesCount(TagType type) { + if (type == TagType.ultralight) { + return 16; + } else if (type == TagType.ultralightC) { + return 48; + } else if (type == TagType.ultralight11) { + return 20; + } else if (type == TagType.ultralight21) { + return 41; + } else if (type == TagType.ntag210) { + return 20; + } else if (type == TagType.ntag212) { + return 41; + } else if (type == TagType.ntag213) { + return 45; + } else if (type == TagType.ntag215) { + return 135; + } else if (type == TagType.ntag216) { + return 231; + } + return 0; +} + +int mfUltralightGetPasswordPage(TagType type) { + if (type == TagType.ultralight) { + return 0; // Don't have password support + } else if (type == TagType.ultralightC) { + return 0; // 44 to 47, custom logic required for Ultralight C + } else if (type == TagType.ultralight11) { + return 18; + } else if (type == TagType.ultralight21) { + return 39; + } else if (type == TagType.ntag210) { + return 18; + } else if (type == TagType.ntag212) { + return 39; + } else if (type == TagType.ntag213) { + return 43; + } else if (type == TagType.ntag215) { + return 133; + } else if (type == TagType.ntag216) { + return 229; + } + return 0; +} diff --git a/chameleonultragui/lib/helpers/mifare_ultralight/write/base.dart b/chameleonultragui/lib/helpers/mifare_ultralight/write/base.dart new file mode 100644 index 00000000..74cf7e7d --- /dev/null +++ b/chameleonultragui/lib/helpers/mifare_ultralight/write/base.dart @@ -0,0 +1,173 @@ +import 'dart:typed_data'; + +import 'package:chameleonultragui/gui/page/read_card.dart'; +import 'package:chameleonultragui/helpers/general.dart'; +import 'package:chameleonultragui/helpers/write.dart'; +import 'package:chameleonultragui/sharedprefsprovider.dart'; +import 'package:flutter/material.dart'; + +// Localizations +import 'package:flutter_gen/gen_l10n/app_localizations.dart'; + +class BaseMifareUltralightWriteHelper extends AbstractWriteHelper { + HFCardInfo? hfInfo; + List failedBlocks = []; + + @override + bool get autoDetect => false; + + @override + String get name => "gen2"; + + static String get staticName => "gen2"; + TextEditingController keyController = TextEditingController(); + String? key; + + BaseMifareUltralightWriteHelper(super.communicator); + + @override + List getAvailableMethods() { + return [ + BaseMifareUltralightWriteHelper(communicator), + ]; + } + + @override + List getAvailableMethodsByPriority() { + return [BaseMifareUltralightWriteHelper(communicator)]; + } + + @override + Widget getWriteWidget(BuildContext context, setState) { + var localizations = AppLocalizations.of(context)!; + final GlobalKey formKey = GlobalKey(); + + return Row(children: [ + Form( + key: formKey, + autovalidateMode: AutovalidateMode.onUserInteraction, + child: Expanded( + child: Column( + children: [ + TextFormField( + controller: keyController, + decoration: InputDecoration( + labelText: localizations.key, + hintMaxLines: 4, + hintText: localizations + .enter_something(localizations.ultralight_key_prompt)), + validator: (String? value) { + if (value!.isNotEmpty && !isValidHexString(value)) { + return localizations.must_be_valid_hex; + } + + if (value.length != 8) { + return localizations.must_be(4, localizations.key); + } + + return null; + }, + ) + ], + ))), + TextButton( + onPressed: () => { + setState(() { + key = keyController.text; + }) + }, + child: Text(localizations.next), + ), + TextButton( + onPressed: () => { + setState(() { + key = ""; + }) + }, + child: Text(localizations.no_key), + ) + ]); + } + + @override + Future isCompatible(CardSave card) async { + return true; + } + + @override + Future isMagic(data) async { + return false; + } + + @override + bool isReady() { + return key != null; + } + + @override + bool writeWidgetSupported() { + return true; + } + + @override + Future reset() async { + failedBlocks = []; + key = null; + } + + @override + Future writeData( + CardSave card, Function(int writeProgress) update) async { + int totalBlocks = card.data.length; + + if (!await communicator.isReaderDeviceMode()) { + await communicator.setReaderDeviceMode(true); + } + + try { + await communicator.scan14443aTag(); + } catch (e) { + return false; + } + + if (key!.isNotEmpty) { + Uint8List pack = await communicator.send14ARaw( + Uint8List.fromList([0x1B, ...hexToBytes(key!)]), + keepRfField: true); + if (pack.length < 2) { + return false; + } + } + + for (var block = 0; block < totalBlocks; block++) { + Uint8List write = await communicator.send14ARaw( + Uint8List.fromList([0xA2, block, ...card.data[block]]), + keepRfField: true, + checkResponseCrc: false, + autoSelect: block == 0 || block == 3); + if (write.isEmpty || write[0] != 0x0A || block == 2) { + await communicator.send14ARaw(Uint8List(1)); // reset + + if (key!.isNotEmpty) { + await communicator.send14ARaw( + Uint8List.fromList([0x1B, ...hexToBytes(key!)]), + keepRfField: true); + } + + if (block > 2) { + // block is not UID + failedBlocks.add(block); + } + } + + update((block / totalBlocks * 100).round()); + } + + return failedBlocks.isEmpty; + } + + @override + List getFailedBlocks() { + return failedBlocks; + } +} diff --git a/chameleonultragui/lib/helpers/ntag/general.dart b/chameleonultragui/lib/helpers/ntag/general.dart deleted file mode 100644 index f0cb5c5a..00000000 --- a/chameleonultragui/lib/helpers/ntag/general.dart +++ /dev/null @@ -1,5 +0,0 @@ -import 'package:chameleonultragui/bridge/chameleon.dart'; - -bool isNTAG(TagType type) { - return [TagType.ntag213, TagType.ntag215, TagType.ntag216].contains(type); -} diff --git a/chameleonultragui/lib/helpers/t55xx/write/base.dart b/chameleonultragui/lib/helpers/t55xx/write/base.dart index 98be8207..e8b937a8 100644 --- a/chameleonultragui/lib/helpers/t55xx/write/base.dart +++ b/chameleonultragui/lib/helpers/t55xx/write/base.dart @@ -14,9 +14,9 @@ class BaseT55XXCardHelper extends AbstractWriteHelper { bool get autoDetect => true; @override - String get name => "T55XX"; + String get name => "t55xx"; - static String get staticName => "T55XX"; + static String get staticName => "t55xx"; TextEditingController newKeyController = TextEditingController(); TextEditingController currentKeyController = TextEditingController(); String currentKey = ""; @@ -157,7 +157,8 @@ class BaseT55XXCardHelper extends AbstractWriteHelper { } @override - Future writeData(CardSave card, update) async { + Future writeData( + CardSave card, Function(int writeProgress) update) async { await communicator.writeEM410XtoT55XX( hexToBytes(card.uid), hexToBytes(newKey), [hexToBytes(currentKey)]); var newCard = await communicator.readEM410X(); diff --git a/chameleonultragui/lib/helpers/write.dart b/chameleonultragui/lib/helpers/write.dart index 1a242aa4..b07f0e9a 100644 --- a/chameleonultragui/lib/helpers/write.dart +++ b/chameleonultragui/lib/helpers/write.dart @@ -2,6 +2,8 @@ import 'package:chameleonultragui/bridge/chameleon.dart'; import 'package:chameleonultragui/helpers/mifare_classic/general.dart'; import 'package:chameleonultragui/helpers/mifare_classic/recovery.dart'; import 'package:chameleonultragui/helpers/mifare_classic/write/base.dart'; +import 'package:chameleonultragui/helpers/mifare_ultralight/general.dart'; +import 'package:chameleonultragui/helpers/mifare_ultralight/write/base.dart'; import 'package:chameleonultragui/helpers/t55xx/write/base.dart'; import 'package:chameleonultragui/main.dart'; import 'package:chameleonultragui/sharedprefsprovider.dart'; @@ -41,11 +43,15 @@ abstract class AbstractWriteHelper { static AbstractWriteHelper? getClassByCardType( TagType type, ChameleonGUIState appState, void Function() update) { - if (chameleonTagTypeGetMfClassicType(type) != MifareClassicType.none) { - return BaseMifareClassicMagicCardHelper(appState.communicator!, + if (isMifareClassic(type)) { + return BaseMifareClassicWriteHelper(appState.communicator!, recovery: MifareClassicRecovery(appState: appState, update: update)); } + if (isMifareUltralight(type)) { + return BaseMifareUltralightWriteHelper(appState.communicator!); + } + if (type == TagType.em410X) { return BaseT55XXCardHelper(appState.communicator!); } @@ -53,7 +59,7 @@ abstract class AbstractWriteHelper { return null; // writing is not supported } - Future writeData(CardSave card, dynamic update); + Future writeData(CardSave card, Function(int writeProgress) update); Widget getWriteWidget(BuildContext context, dynamic setState); @@ -66,5 +72,6 @@ abstract class AbstractWriteHelper { } @override - bool operator ==(dynamic other) => other != null && name == other.name; + bool operator ==(Object other) => + other is AbstractWriteHelper && name == other.name; } diff --git a/chameleonultragui/lib/l10n/app_en.arb b/chameleonultragui/lib/l10n/app_en.arb index ca5d6677..5691c2ba 100644 --- a/chameleonultragui/lib/l10n/app_en.arb +++ b/chameleonultragui/lib/l10n/app_en.arb @@ -281,5 +281,16 @@ "key": "Key", "t55xx_key_prompt": "current T55XX key. Default CU key is 20206666", "t55xx_new_key_prompt": "new T55XX key if you want to change it", - "new_key": "New key" + "new_key": "New key", + "ultralight_key_prompt": "Ultralight key (HEX, 4 bytes)", + "read_with_key": "Read with key", + "read_without_key": "Read without key", + "invalid_password": "Invalid password", + "ultralight_version": "Ultralight version", + "ultralight_signature": "Ultralight signature", + "no_key": "No key", + "gen1": "Gen1", + "gen2": "Gen2 / Generic", + "gen3": "Gen3", + "t55xx": "T55XX" } \ No newline at end of file diff --git a/chameleonultragui/lib/recovery/bindings.dart b/chameleonultragui/lib/recovery/bindings.dart index 0ae8e442..42689d43 100644 --- a/chameleonultragui/lib/recovery/bindings.dart +++ b/chameleonultragui/lib/recovery/bindings.dart @@ -30,7 +30,7 @@ class Recovery { ffi.Pointer darkside( ffi.Pointer data, - ffi.Pointer keyCount, + ffi.Pointer keyCount, ) { return _darkside( data, @@ -41,10 +41,10 @@ class Recovery { late final _darksidePtr = _lookup< ffi.NativeFunction< ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>>('darkside'); + ffi.Pointer, ffi.Pointer)>>('darkside'); late final _darkside = _darksidePtr.asFunction< ffi.Pointer Function( - ffi.Pointer, ffi.Pointer)>(); + ffi.Pointer, ffi.Pointer)>(); ffi.Pointer nested( ffi.Pointer data, diff --git a/chameleonultragui/lib/recovery/recovery.dart b/chameleonultragui/lib/recovery/recovery.dart index adf59b19..565aa3d0 100644 --- a/chameleonultragui/lib/recovery/recovery.dart +++ b/chameleonultragui/lib/recovery/recovery.dart @@ -254,7 +254,7 @@ Future _helperIsolateSendPort = () async { pointer.ref.items = itemPointer; pointer.ref.count = i; - Pointer count = calloc(); + Pointer count = calloc(); count.value = 0; List keys = []; final Pointer result = _bindings.darkside(pointer, count); diff --git a/chameleonultragui/lib/sharedprefsprovider.dart b/chameleonultragui/lib/sharedprefsprovider.dart index 6ec88e3a..cf781d1c 100644 --- a/chameleonultragui/lib/sharedprefsprovider.dart +++ b/chameleonultragui/lib/sharedprefsprovider.dart @@ -75,6 +75,7 @@ class CardSave { String name; TagType tag; List data; + CardSaveExtra extraData; Color color; factory CardSave.fromJson(String json) { @@ -86,6 +87,7 @@ class CardSave { final ats = List.from((data['ats'] ?? []) as List); final name = data['name'] as String; final tag = getTagTypeByValue(data['tag']); + final extraData = CardSaveExtra.import(data['extra'] ?? {}); final color = data['color'] == null ? Colors.deepOrange : hexToColor(data['color']); List tagData = (data['data'] as List) @@ -100,6 +102,7 @@ class CardSave { tag: tag, data: tagData, color: color, + extraData: extraData, ats: Uint8List.fromList(ats), atqa: Uint8List.fromList(atqa)); } @@ -115,23 +118,63 @@ class CardSave { 'tag': tag.value, 'color': colorToHex(color), 'data': data.map((data) => data.toList()).toList(), + 'extra': extraData.export(), }); } - CardSave( - {String? id, - required this.uid, - required this.name, - required this.tag, - int? sak, - Uint8List? atqa, - Uint8List? ats, - this.color = Colors.deepOrange, - this.data = const []}) - : id = id ?? const Uuid().v4(), + CardSave({ + String? id, + required this.uid, + required this.name, + required this.tag, + int? sak, + Uint8List? atqa, + Uint8List? ats, + CardSaveExtra? extraData, + this.color = Colors.deepOrange, + this.data = const [], + }) : id = id ?? const Uuid().v4(), sak = sak ?? 0, atqa = atqa ?? Uint8List(0), - ats = ats ?? Uint8List(0); + ats = ats ?? Uint8List(0), + extraData = extraData ?? CardSaveExtra(); +} + +class CardSaveExtra { + Uint8List ultralightSignature; + Uint8List ultralightVersion; + + factory CardSaveExtra.import(Map data) { + List readBytes(Map data, String key) { + return List.from( + data[key] != null ? data[key] as List : []); + } + + final ultralightSignature = readBytes(data, 'ultralightSignature'); + final ultralightVersion = readBytes(data, 'ultralightVersion'); + + return CardSaveExtra( + ultralightSignature: Uint8List.fromList(ultralightSignature), + ultralightVersion: Uint8List.fromList(ultralightVersion)); + } + + Map export() { + Map json = {}; + + if (ultralightSignature.isNotEmpty) { + json['ultralightSignature'] = ultralightSignature; + } + + if (ultralightVersion.isNotEmpty) { + json['ultralightVersion'] = ultralightVersion; + } + + return json; + } + + CardSaveExtra({Uint8List? ultralightSignature, Uint8List? ultralightVersion}) + : ultralightSignature = ultralightSignature ?? Uint8List(0), + ultralightVersion = ultralightVersion ?? Uint8List(0); } class SharedPreferencesProvider extends ChangeNotifier { diff --git a/chameleonultragui/macos/Podfile.lock b/chameleonultragui/macos/Podfile.lock new file mode 100644 index 00000000..82a6aa0e --- /dev/null +++ b/chameleonultragui/macos/Podfile.lock @@ -0,0 +1,79 @@ +PODS: + - file_saver (0.0.1): + - FlutterMacOS + - flutter_libserialport (0.0.1): + - FlutterMacOS + - libserialport + - FlutterMacOS (1.0.0) + - libserialport (0.1.1) + - mobile_scanner (5.1.1): + - FlutterMacOS + - package_info_plus (0.0.1): + - FlutterMacOS + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - recovery (0.0.1): + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + - url_launcher_macos (0.0.1): + - FlutterMacOS + - wakelock_plus (0.0.1): + - FlutterMacOS + +DEPENDENCIES: + - file_saver (from `Flutter/ephemeral/.symlinks/plugins/file_saver/macos`) + - flutter_libserialport (from `Flutter/ephemeral/.symlinks/plugins/flutter_libserialport/macos`) + - FlutterMacOS (from `Flutter/ephemeral`) + - mobile_scanner (from `Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - recovery (from `./recovery.podspec`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) + - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - wakelock_plus (from `Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos`) + +SPEC REPOS: + trunk: + - libserialport + +EXTERNAL SOURCES: + file_saver: + :path: Flutter/ephemeral/.symlinks/plugins/file_saver/macos + flutter_libserialport: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_libserialport/macos + FlutterMacOS: + :path: Flutter/ephemeral + mobile_scanner: + :path: Flutter/ephemeral/.symlinks/plugins/mobile_scanner/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + recovery: + :path: "./recovery.podspec" + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin + url_launcher_macos: + :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + wakelock_plus: + :path: Flutter/ephemeral/.symlinks/plugins/wakelock_plus/macos + +SPEC CHECKSUMS: + file_saver: 44e6fbf666677faf097302460e214e977fdd977b + flutter_libserialport: d1a505fd4b05785f7b50cc7c93b361937ea1c5bd + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 + libserialport: 1cb25e66ef3c92a8e59c2ea3820302c3fa2268cd + mobile_scanner: 1efac1e53c294b24e3bb55bcc7f4deee0233a86b + package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + recovery: 3dd1b9b85ac8e7f017ef8f6a3caea297d8559924 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 + wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 + +PODFILE CHECKSUM: 58eeb33b8e458bd5d682f8fe36f300c258f4d19a + +COCOAPODS: 1.15.2 diff --git a/chameleonultragui/macos/Runner.xcodeproj/project.pbxproj b/chameleonultragui/macos/Runner.xcodeproj/project.pbxproj index 4a4a6a24..b708c77e 100644 --- a/chameleonultragui/macos/Runner.xcodeproj/project.pbxproj +++ b/chameleonultragui/macos/Runner.xcodeproj/project.pbxproj @@ -203,7 +203,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/chameleonultragui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/chameleonultragui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 2331cca6..e2803976 100644 --- a/chameleonultragui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/chameleonultragui/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ 3.0.0' @@ -33,7 +33,10 @@ dependencies: path: async: - flutter_libserialport: ^0.4.0 + flutter_libserialport: + git: + url: https://github.com/snabble/flutter_libserialport.git # FIXME: When https://github.com/jpnurmi/flutter_libserialport/pull/109 merged, switch back to proper package + ref: 0.5.0 provider: ^6.0.5 logger: ^2.0.1 convert: ^3.1.1 diff --git a/chameleonultragui/src/crapto1.c b/chameleonultragui/src/crapto1.c index 70195e07..6603be40 100644 --- a/chameleonultragui/src/crapto1.c +++ b/chameleonultragui/src/crapto1.c @@ -340,7 +340,9 @@ uint8_t lfsr_rollback_bit(struct Crypto1State *s, uint32_t in, int fb) uint32_t t; s->odd &= 0xffffff; - t = s->odd, s->odd = s->even, s->even = t; + t = s->odd; + s->odd = s->even; + s->even = t; out = s->even & 1; out ^= LF_POLY_EVEN & (s->even >>= 1); diff --git a/chameleonultragui/src/mfkey.c b/chameleonultragui/src/mfkey.c index b04cf310..6b7fc857 100644 --- a/chameleonultragui/src/mfkey.c +++ b/chameleonultragui/src/mfkey.c @@ -23,7 +23,7 @@ int compare_uint64(const void *a, const void *b) } // create the intersection (common members) of two sorted lists. Lists are terminated by -1. Result will be in list1. Number of elements is returned. -uint32_t intersection(uint64_t *listA, uint64_t *listB) +uint64_t intersection(uint64_t *listA, uint64_t *listB) { if (listA == NULL || listB == NULL) return 0; diff --git a/chameleonultragui/src/mfkey.h b/chameleonultragui/src/mfkey.h index 4f974fe6..773728d0 100644 --- a/chameleonultragui/src/mfkey.h +++ b/chameleonultragui/src/mfkey.h @@ -18,6 +18,6 @@ uint32_t nonce2key(uint32_t uid, uint32_t nt, uint32_t nr, uint32_t ar, uint64_t par_info, uint64_t ks_info, uint64_t **keys); int compare_uint64(const void *a, const void *b); -uint32_t intersection(uint64_t *listA, uint64_t *listB); +uint64_t intersection(uint64_t *listA, uint64_t *listB); #endif diff --git a/chameleonultragui/src/recovery.c b/chameleonultragui/src/recovery.c index 0a2a5001..817e3a1e 100644 --- a/chameleonultragui/src/recovery.c +++ b/chameleonultragui/src/recovery.c @@ -49,11 +49,11 @@ typedef struct uint32_t endPos; } RecPar; -FFI_PLUGIN_EXPORT uint64_t *darkside(Darkside *data, uint32_t *outputKeyCount) +FFI_PLUGIN_EXPORT uint64_t *darkside(Darkside *data, uint64_t *outputKeyCount) { uint32_t uid = data->uid; uint32_t count = 0, i = 0; - uint32_t keycount = 0; + uint64_t keycount = 0; uint64_t *keylist = NULL, *last_keylist = NULL; DarksideParam *dps = calloc(1, sizeof(DarksideParam) * data->count); uint64_t *keys = malloc(sizeof(uint64_t) * 256); @@ -95,7 +95,7 @@ FFI_PLUGIN_EXPORT uint64_t *darkside(Darkside *data, uint32_t *outputKeyCount) continue; } } - uint8_t key_tmp[6] = {0}; + if (keycount > 0) { no_key_recover = false; @@ -261,7 +261,6 @@ static void nested_recover(RecPar *rp) uint64_t *nested_run(NtpKs1 *pNK, uint32_t sizePNK, uint32_t authuid, uint32_t *keyCount, uint32_t *outputKeyCount) { *keyCount = 0; - uint32_t i; RecPar *pRPs = malloc(sizeof(RecPar)); if (pRPs == NULL) @@ -364,9 +363,9 @@ FFI_PLUGIN_EXPORT uint64_t *nested(Nested *data, uint32_t *outputKeyCount) FFI_PLUGIN_EXPORT uint64_t *static_nested(StaticNested *data, uint32_t *outputKeyCount) { NtpKs1 *pNK = NULL; - uint32_t i, m; + uint32_t i; uint32_t j = 0; - uint32_t nt1, nt2, nttest, ks1, dist; + uint32_t nt1, nt2, nttest, ks1, dist = 0; uint32_t authuid = data->uid; uint8_t type = (uint8_t)data->key_type; // target key type @@ -470,4 +469,4 @@ FFI_PLUGIN_EXPORT uint64_t mfkey32(Mfkey32 *data) free(s); return UINT64_MAX; -} \ No newline at end of file +} diff --git a/chameleonultragui/src/recovery.h b/chameleonultragui/src/recovery.h index b3cd5368..f41a6642 100644 --- a/chameleonultragui/src/recovery.h +++ b/chameleonultragui/src/recovery.h @@ -64,7 +64,7 @@ typedef struct uint32_t ar1_enc; // second encrypted reader response } Mfkey32; -FFI_PLUGIN_EXPORT uint64_t *darkside(Darkside *data, uint32_t *keyCount); +FFI_PLUGIN_EXPORT uint64_t *darkside(Darkside *data, uint64_t *keyCount); FFI_PLUGIN_EXPORT uint64_t *nested(Nested *data, uint32_t *keyCount);