basic application interface

This commit is contained in:
nganhkhoa 2023-03-07 21:06:36 +07:00
parent 68d476950e
commit e3d3649dd2
3 changed files with 213 additions and 14 deletions

View File

@ -8,18 +8,20 @@
std::unique_ptr<Connector> connector = nullptr;
void setup(JNIEnv* env, jobject isoDepObj);
void initSessionViaBAC();
void setup(JNIEnv* env, jobject isoDepObj, jstring _passcode);
extern "C" JNIEXPORT jint JNICALL
Java_com_bshield_cccc_MainActivity_initNFCScan(
JNIEnv* env,
jobject /* this */,
jobject isoDepObj) {
jobject isoDepObj,
jstring passcode) {
setup(env, isoDepObj);
setup(env, isoDepObj, passcode);
if (!connector) return 0;
// TODO: move to connector class
connector->selectDf1();
connector->initBAC();
@ -31,12 +33,62 @@ Java_com_bshield_cccc_MainActivity_initNFCScan(
connector->readEFDG15();
connector->readEFSOD();
connector->activeAuthentication();
bytes challenge = randomBytes(8);
connector->activeAuthentication(challenge);
connector->ready = true;
return 1;
}
void setup(JNIEnv* env, jobject isoDepObj) {
extern "C" JNIEXPORT jint JNICALL
Java_com_bshield_cccc_MainActivity_ChallengeResponse(
JNIEnv* env,
jobject /* this */,
jobject challenge_bytes) {
if (!connector) return 0;
// connector->activeAuthentication(challenge)
return 1;
};
extern "C" JNIEXPORT jint JNICALL
Java_com_bshield_cccc_MainActivity_GetBasicInfo(
JNIEnv* env,
jobject /* this */) {
if (!connector) return 0;
if (!connector->ready) return 0;
auto passport = connector->passport;
// Get the class reference of the Java class
jclass passportDataClass = env->FindClass("com/bshield/cccc/PassportData");
// Create a new object of the Java class
jobject passportDataObject = env->NewObject(passportDataClass, env->GetMethodID(passportDataClass, "<init>", "()V"));
// Set the values of each field
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "country", "Ljava/lang/String;"), env->NewStringUTF(passport.country.c_str()));
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "documentNumber", "Ljava/lang/String;"), env->NewStringUTF(passport.documentNumber.c_str()));
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "gender", "Ljava/lang/String;"), env->NewStringUTF(passport.gender.c_str()));
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "nationality", "Ljava/lang/String;"), env->NewStringUTF(passport.nationality.c_str()));
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "familyName", "Ljava/lang/String;"), env->NewStringUTF(passport.familyName.c_str()));
// Create a Java List object and populate it with the nameComponents vector
jclass stringClass = env->FindClass("java/lang/String");
jobjectArray nameComponentsArray = env->NewObjectArray(passport.nameComponents.size(), stringClass, nullptr);
for (int i = 0; i < passport.nameComponents.size(); i++) {
env->SetObjectArrayElement(nameComponentsArray, i, env->NewStringUTF(passport.nameComponents[i].c_str()));
}
env->SetObjectField(passportDataObject, env->GetFieldID(passportDataClass, "nameComponents", "Ljava/util/List;"), nameComponentsArray);
// Set the values of birthDate and expiryDate fields
env->SetLongField(passportDataObject, env->GetFieldID(passportDataClass, "birthDate", "J"), (jlong) passport.birthDate);
env->SetLongField(passportDataObject, env->GetFieldID(passportDataClass, "expiryDate", "J"), (jlong) passport.expiryDate);
return 1;
};
void setup(JNIEnv* env, jobject isoDepObj, jstring _passcode) {
// Get the IsoDep class and its methods
jclass isoDepClass = env->FindClass("android/nfc/tech/IsoDep");
@ -61,7 +113,11 @@ void setup(JNIEnv* env, jobject isoDepObj) {
return vec;
};
connector.reset(new Connector(transceive));
const char *cstr = env->GetStringUTFChars(_passcode, NULL);
std::string passcode = std::string(cstr);
env->ReleaseStringUTFChars(_passcode, cstr);
connector.reset(new Connector(transceive, passcode));
// cannot remove, must call connect to connect
env->CallVoidMethod(isoDepObj, connectMethod);

View File

@ -1,18 +1,34 @@
package com.bshield.cccc
import android.R
import android.app.DatePickerDialog
import android.content.IntentFilter
import android.nfc.NfcAdapter
import android.nfc.NfcAdapter.ACTION_ADAPTER_STATE_CHANGED
import android.nfc.NfcAdapter.getDefaultAdapter
import android.nfc.tech.IsoDep
import android.nfc.tech.*
import android.nfc.tech.TagTechnology
import android.os.Bundle
import android.util.Log
import android.text.InputType
import android.view.View
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import com.bshield.cccc.databinding.ActivityMainBinding
import java.util.*
class PassportData {
var country: String? = null
var documentNumber: String? = null
var gender: String? = null
var nationality: String? = null
var familyName: String? = null
var nameComponents: List<String>? = null
var birthDate: Long = 0
var expiryDate: Long = 0
var portrait: ByteArray? = null
}
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@ -20,6 +36,11 @@ class MainActivity : AppCompatActivity() {
private var tagTechnology: TagTechnology? = null;
private lateinit var nfcAdapter: NfcAdapter;
private lateinit var birthday: String;
private lateinit var expirydate: String;
var picker: DatePickerDialog? = null;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -28,6 +49,59 @@ class MainActivity : AppCompatActivity() {
nfcAdapter = getDefaultAdapter(this);
val filter = IntentFilter(ACTION_ADAPTER_STATE_CHANGED)
if(true){
val eText = binding.birthday;
eText.setInputType(InputType.TYPE_NULL)
eText.setOnClickListener(object : View.OnClickListener {
override fun onClick(v: View?) {
val cldr: Calendar = Calendar.getInstance()
val day: Int = cldr.get(Calendar.DAY_OF_MONTH)
val month: Int = cldr.get(Calendar.MONTH)
val year: Int = cldr.get(Calendar.YEAR)
// date picker dialog
picker = DatePickerDialog(
this@MainActivity,
{ view, year, monthOfYear, dayOfMonth -> setBirthDate(dayOfMonth, monthOfYear, year) },
year,
month,
day
)
picker!!.show()
}
})
}
if(true){
val eText = binding.expirydate;
eText.setInputType(android.text.InputType.TYPE_NULL)
eText.setOnClickListener(object : android.view.View.OnClickListener {
override fun onClick(v: android.view.View?) {
val cldr: java.util.Calendar = java.util.Calendar.getInstance()
val day: kotlin.Int = cldr.get(java.util.Calendar.DAY_OF_MONTH)
val month: kotlin.Int = cldr.get(java.util.Calendar.MONTH)
val year: kotlin.Int = cldr.get(java.util.Calendar.YEAR)
// date picker dialog
picker = android.app.DatePickerDialog(
this@MainActivity,
{ view, year, monthOfYear, dayOfMonth -> setExpiryDate(dayOfMonth, monthOfYear, year) },
year,
month,
day
)
picker!!.show()
}
})
}
}
fun setBirthDate(dayOfMonth: Int, monthOfYear: Int, year: Int) {
birthday = "%s%02d%02d".format(year.toString().substring(2), monthOfYear + 1, dayOfMonth);
binding.birthday.setText(birthday);
}
fun setExpiryDate(dayOfMonth: Int, monthOfYear: Int, year: Int) {
expirydate = "%s%02d%02d".format(year.toString().substring(2), monthOfYear + 1, dayOfMonth);
binding.expirydate.setText(expirydate);
}
override fun onResume() {
@ -44,15 +118,16 @@ class MainActivity : AppCompatActivity() {
}, (0x1 or 0x2), null);
// Example of a call to a native method
binding.sampleText.text = "nfc enabled? ${nfcAdapter.isEnabled()}"
// binding.sampleText.text = "nfc enabled? ${nfcAdapter.isEnabled()}"
}
/**
* A native method that is implemented by the 'cccc' native library,
* which is packaged with this application.
*/
external fun initNFCScan(tag: TagTechnology): Boolean
external fun initNFCScan(tag: TagTechnology, passcode: String): Boolean
external fun ChallengeResponse(): Boolean
external fun GetBasicInfo(): Boolean
companion object {
// Used to load the 'cccc' library on application startup.
@ -66,6 +141,35 @@ class MainActivity : AppCompatActivity() {
return;
}
val r = initNFCScan(tagTechnology!!);
if (binding.idnumber.text.length != 12) {
binding.error.text = "ID number must be 12 digits";
return;
}
if (!::birthday.isInitialized) {
binding.error.text = "Birthday is not entered";
}
if (!::expirydate.isInitialized) {
binding.error.text = "Birthday is not entered";
}
val id = binding.idnumber.text.substring(3);
fun checkdigit(digits: String): String {
fun mapValue(x: Char): Int {
return when {
x.isDigit() -> x.toString().toInt()
x in 'A'..'Z' -> x.toInt() - 'A'.toInt() + 10
x == '<' -> 0
else -> throw IllegalArgumentException("Invalid character: $x")
}
}
val weights = listOf(7, 3, 1)
val hash = digits.withIndex().sumBy { (i, c) -> mapValue(c) * weights[i % weights.size] }
return (hash % 10).toString();
}
val passcode = id + checkdigit(id) + birthday + checkdigit(birthday) + expirydate + checkdigit(expirydate);
val r = initNFCScan(tagTechnology!!, passcode);
}
}

View File

@ -6,8 +6,46 @@
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/idnumber"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="137dp"
android:layout_marginBottom="144dp"
android:hint="Nhap so chung minh nhan dan"
app:layout_constraintBottom_toBottomOf="@+id/expirydate"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<EditText
android:id="@+id/birthday"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginTop="24dp"
android:hint="Enter birth day"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/idnumber" />
<EditText
android:id="@+id/expirydate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginBottom="30dp"
android:hint="Enter expiry date"
app:layout_constraintBottom_toTopOf="@+id/error"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/sample_text"
android:id="@+id/error"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
@ -16,4 +54,5 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>