From c89d841c174656a95861a494f2956b2ab72f6770 Mon Sep 17 00:00:00 2001 From: Efe E Date: Tue, 26 May 2026 21:55:04 +0100 Subject: [PATCH 1/4] PR for libfprint --- README.md | 69 ++++++++- meson.build | 425 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 486 insertions(+), 8 deletions(-) create mode 100644 meson.build diff --git a/README.md b/README.md index dbea943..102052e 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,12 @@ ## Status: **WORKING** ✓ -Enrollment and verify confirmed working on real hardware (2026-03-10). +Enrollment and verify confirmed working on real hardware (2026-05-26). ## Hardware -[TNP Nano USB Fingerprint Reader](https://www.amazon.com/dp/B07DW62XS7) (Amazon) +[TNP Nano USB Fingerprint Reader](https://www.amazon.com/dp/B07DW62XS7) (Amazon US) +[TNP Nano USB Fingerprint Reader](https://www.amazon.co.uk/TNP-Fingerprint-Reader-Windows-Hello/dp/B07DW62XS7/) (Amazon UK) TNP Nano USB Fingerprint Reader @@ -45,27 +46,79 @@ See [Reverse Engineering](docs/reverse-engineering.md) for how to reproduce. - The required number of GenChar samples for RegModel is `DAT_180032020 / 3`clamped to \[3, 6\]. For this device the value is 6. - Extra GET_IMAGE calls between GenChars corrupt the device's char buffer state. The `waiting_for_lift` approach must minimize GET_IMAGE polling between captures. -## Build +## Instructions +1. Update your machine ```bash -./build.sh +sudo apt update ``` -Copies `src/microarray.c` into the libfprint source tree (`$LIBFPRINT_SRC`, defaults to `~/libfprint`), builds with ninja, and installs the shared library. +2. Install all required tools/libraries -## Testing +```bash +sudo apt install -y git build-essential meson ninja-build \ + pkg-config libglib2.0-dev libgusb-dev libgudev-1.0-dev \ + libpixman-1-dev libnss3-dev libssl-dev libcairo2-dev \ + libgirepository1.0-dev gtk-doc-tools \ + fprintd libpam-fprintd + ``` + +3. Clone the official libfprint source code to ~/libfprint directory + +```bash +git clone https://gitlab.freedesktop.org/libfprint/libfprint.git ~/libfprint +``` + +4. Manually create the microarray directory + +```bash +cd ~/libfprint +mkdir -p libfprint/drivers/microarray +meson setup build +``` + +5. Copy this repo + +```bash +git clone https://github.com/jdillon/libfprint-microarray.git ~/libfprint-microarray +``` + +6. Make changes to ~/libfprint ```bash +# copy fixed meson.build file over to other library +cp ~/libfprint-microarray/meson.build ~/libfprint/libfprint/meson.build +cp ~/libfprint-microarray/src/microarray.c ~/libfprint/libfprint/drivers/microarray/microarray.c + +cd ~/libfprint/build +meson configure -Ddrivers=all +ninja +sudo cp libfprint/libfprint-2.so.2.0.0 /usr/lib/x86_64-linux-gnu/libfprint-2.so.2 +sudo cp libfprint/libfprint-2.so.2.0.0 /usr/lib/libfprint-2.so.2 +sudo ldconfig +sudo udevadm control --reload-rules && sudo udevadm trigger +#sudo systemctl enable --now fprintd +``` + +## Testing +```bash + +# Restart daemon +sudo systemctl stop fprintd +sudo G_MESSAGES_DEBUG=all /usr/libexec/fprintd -t 2>&1 + # Enroll right index finger (6 press/lift cycles) fprintd-enroll -f right-index-finger # Verify fprintd-verify -f right-index-finger -# Debug logging -sudo G_MESSAGES_DEBUG=all /usr/libexec/fprintd -t 2>&1 ``` +**If there is a future update of libfprint, re-running Step (6) above should make everything work again.** + + + ## License [MIT](LICENSE) diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..32ed7dd --- /dev/null +++ b/meson.build @@ -0,0 +1,425 @@ +spi_sources = [] +spi_headers = [] + +if enabled_spi_drivers.length() > 0 + spi_headers = ['fpi-spi-transfer.h'] + spi_sources = ['fpi-spi-transfer.c'] +endif + +libfprint_sources = [ + 'fp-context.c', + 'fp-device.c', + 'fp-image.c', + 'fp-print.c', + 'fp-image-device.c', +] + +libfprint_private_sources = [ + 'fpi-assembling.c', + 'fpi-byte-reader.c', + 'fpi-byte-writer.c', + 'fpi-device.c', + 'fpi-image-device.c', + 'fpi-image.c', + 'fpi-print.c', + 'fpi-ssm.c', + 'fpi-usb-transfer.c', +] + spi_sources + +libfprint_public_headers = [ + 'fp-context.h', + 'fp-device.h', + 'fp-image-device.h', + 'fp-image.h', + 'fp-print.h', +] + +libfprint_private_headers = [ + 'fpi-assembling.h', + 'fpi-byte-reader.h', + 'fpi-byte-utils.h', + 'fpi-byte-writer.h', + 'fpi-compat.h', + 'fpi-context.h', + 'fpi-device.h', + 'fpi-image-device.h', + 'fpi-image.h', + 'fpi-log.h', + 'fpi-minutiae.h', + 'fpi-print.h', + 'fpi-usb-transfer.h', + 'fpi-ssm.h', +] + spi_headers + +nbis_sources = [ + 'nbis/bozorth3/bozorth3.c', + 'nbis/bozorth3/bz_alloc.c', + 'nbis/bozorth3/bz_drvrs.c', + 'nbis/bozorth3/bz_gbls.c', + 'nbis/bozorth3/bz_io.c', + 'nbis/bozorth3/bz_sort.c', + 'nbis/mindtct/binar.c', + 'nbis/mindtct/block.c', + 'nbis/mindtct/chaincod.c', + 'nbis/mindtct/contour.c', + 'nbis/mindtct/detect.c', + 'nbis/mindtct/dft.c', + 'nbis/mindtct/free.c', + 'nbis/mindtct/getmin.c', + 'nbis/mindtct/globals.c', + 'nbis/mindtct/imgutil.c', + 'nbis/mindtct/init.c', + 'nbis/mindtct/line.c', + 'nbis/mindtct/link.c', + 'nbis/mindtct/log.c', + 'nbis/mindtct/loop.c', + 'nbis/mindtct/maps.c', + 'nbis/mindtct/matchpat.c', + 'nbis/mindtct/minutia.c', + 'nbis/mindtct/morph.c', + 'nbis/mindtct/quality.c', + 'nbis/mindtct/remove.c', + 'nbis/mindtct/ridges.c', + 'nbis/mindtct/shape.c', + 'nbis/mindtct/sort.c', + 'nbis/mindtct/util.c', + 'nbis/mindtct/xytreps.c', +] + +driver_sources = { + 'upekts' : + [ 'drivers/upekts.c', 'drivers/upek_proto.c' ], + 'upektc' : + [ 'drivers/upektc.c' ], + 'upeksonly' : + [ 'drivers/upeksonly.c' ], + 'uru4000' : + [ 'drivers/uru4000.c' ], + 'aes1610' : + [ 'drivers/aes1610.c' ], + 'aes1660' : + [ 'drivers/aes1660.c' ], + 'aes2501' : + [ 'drivers/aes2501.c' ], + 'aes2550' : + [ 'drivers/aes2550.c' ], + 'aes2660' : + [ 'drivers/aes2660.c' ], + 'aes3500' : + [ 'drivers/aes3500.c' ], + 'aes4000' : + [ 'drivers/aes4000.c' ], + 'vcom5s' : + [ 'drivers/vcom5s.c' ], + 'vfs101' : + [ 'drivers/vfs101.c' ], + 'vfs301' : + [ 'drivers/vfs301.c', 'drivers/vfs301_proto.c' ], + 'vfs5011' : + [ 'drivers/vfs5011.c' ], + 'vfs7552' : + [ 'drivers/vfs7552.c' ], + 'upektc_img' : + [ 'drivers/upektc_img.c', 'drivers/upek_proto.c' ], + 'etes603' : + [ 'drivers/etes603.c' ], + 'egis0570' : + [ 'drivers/egis0570.c' ], + 'egismoc' : + [ 'drivers/egismoc/egismoc.c' ], + 'vfs0050' : + [ 'drivers/vfs0050.c' ], + 'elan' : + [ 'drivers/elan.c' ], + 'elanmoc' : + [ 'drivers/elanmoc/elanmoc.c' ], + 'elanspi' : + [ 'drivers/elanspi.c' ], + 'nb1010' : + [ 'drivers/nb1010.c' ], + 'virtual_image' : + [ 'drivers/virtual-image.c' ], + 'virtual_device' : + [ 'drivers/virtual-device.c' ], + 'virtual_device_storage' : + [ 'drivers/virtual-device-storage.c' ], + 'synaptics' : + [ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ], + 'goodixmoc' : + [ 'drivers/goodixmoc/goodix.c', 'drivers/goodixmoc/goodix_proto.c' ], + 'fpcmoc' : + [ 'drivers/fpcmoc/fpc.c' ], + 'realtek' : + [ 'drivers/realtek/realtek.c' ], + 'focaltech_moc' : + [ 'drivers/focaltech_moc/focaltech_moc.c' ], + 'microarray' : + [ 'drivers/microarray/microarray.c' ], +} + +helper_sources = { + 'aeslib' : + [ 'drivers/aeslib.c' ], + 'aesx660' : + [ 'drivers/aesx660.c' ], + 'aes3k' : + [ 'drivers/aes3k.c' ], + 'openssl' : + [ ], + 'udev' : + [ ], + 'virtual' : + [ 'drivers/virtual-device-listener.c' ], +} + +drivers_sources = [] +drivers_cflags = [] +foreach driver: drivers + drivers_sources += driver_sources[driver] +endforeach + +drivers_sources += driver_sources['microarray'] +foreach helper : driver_helpers + drivers_sources += helper_sources[helper] +endforeach + + +fp_enums = gnome.mkenums_simple('fp-enums', + sources: libfprint_public_headers, + install_header: true, + install_dir: get_option('includedir') / versioned_libname, +) +fp_enums_h = fp_enums[1] + +fpi_enums = gnome.mkenums_simple('fpi-enums', + sources: libfprint_private_headers, + install_header: false, +) +fpi_enums_h = fpi_enums[1] + +enums_dep = declare_dependency( + sources: [ fp_enums_h, fpi_enums_h ] +) + +# Export the drivers' types to the core code +drivers_type_list = [] +drivers_type_func = [] +drivers_type_list += '#include ' +drivers_type_list += '#include "fpi-context.h"' +drivers_type_list += '' +drivers_type_func += 'GArray *' +drivers_type_func += 'fpi_get_driver_types (void)' +drivers_type_func += '{' +drivers_type_func += ' GArray *drivers = g_array_new (TRUE, FALSE, sizeof (GType));' +drivers_type_func += ' GType t;' +drivers_type_func += '' + +supported_drivers += 'microarray' + +foreach driver: supported_drivers + drivers_type_list += 'extern GType (fpi_device_' + driver + '_get_type) (void);' + drivers_type_func += ' t = fpi_device_' + driver + '_get_type ();' + drivers_type_func += ' g_array_append_val (drivers, t);' + drivers_type_func += '' +endforeach +drivers_type_list += '' +drivers_type_func += ' return drivers;' +drivers_type_func += '}' + +drivers_sources += configure_file(input: 'empty_file', + output: 'fpi-drivers.c', + capture: true, + command: [ + 'echo', + '\n'.join(drivers_type_list + [] + drivers_type_func) + ]) + +deps = [ + enums_dep, + gio_dep, + glib_dep, + gobject_dep, + gusb_dep, + mathlib_dep, +] + optional_deps + +# These are empty and only exist so that the include directories are created +# in the build tree. This silences a build time warning. +subdir('nbis/include') +subdir('nbis/libfprint-include') +deps += declare_dependency(include_directories: [ + root_inc, + include_directories('nbis/include'), + include_directories('nbis/libfprint-include'), +]) + +libnbis = static_library('nbis', + nbis_sources, + dependencies: deps, + c_args: cc.get_supported_arguments([ + '-Wno-error=redundant-decls', + '-Wno-redundant-decls', + '-Wno-discarded-qualifiers', + '-Wno-array-bounds', + '-Wno-array-parameter', + '-Wno-unused-but-set-variable', + ]), + install: false) + +libfprint_private = static_library('fprint-private', + sources: [ + fpi_enums, + libfprint_private_sources, + ], + dependencies: deps, + link_with: libnbis, + install: false) + +libfprint_drivers = static_library('fprint-drivers', + sources: drivers_sources, + c_args: drivers_cflags, + dependencies: deps, + link_with: libfprint_private, + install: false) + +mapfile = files('libfprint.ver')[0] +if meson.version().version_compare('>=1.4') + mapfile_path = mapfile.full_path() +else + mapfile_path = meson.project_source_root() / '@0@'.format(mapfile) +endif +vflag = '-Wl,--version-script,@0@'.format(mapfile_path) + +libfprint = shared_library(versioned_libname.split('lib')[1], + sources: [ + fp_enums, + libfprint_sources, + ], + soversion: soversion, + version: libversion, + link_args : vflag, + link_depends : mapfile, + link_with: [libfprint_drivers, libfprint_private], + dependencies: deps, + install: true) + +libfprint_dep = declare_dependency(link_with: libfprint, + include_directories: root_inc, + dependencies: [ + enums_dep, + gio_dep, + glib_dep, + gobject_dep, + gusb_dep, + ]) + +install_headers(['fprint.h'] + libfprint_public_headers, + subdir: versioned_libname +) + +libfprint_private_dep = declare_dependency( + include_directories: include_directories('.'), + link_with: libfprint_private, + dependencies: [ + deps, + libfprint_dep, + ] +) + +udev_hwdb = executable('fprint-list-udev-hwdb', + 'fprint-list-udev-hwdb.c', + dependencies: libfprint_private_dep, + link_with: libfprint_drivers, + install: false) + +udev_hwdb_generator = custom_target('udev-hwdb', + output: 'autosuspend.hwdb', + depend_files: drivers_sources, + capture: true, + command: [ udev_hwdb ], + install: false, +) + +metainfo = executable('fprint-list-metainfo', + 'fprint-list-metainfo.c', + dependencies: libfprint_private_dep, + link_with: libfprint_drivers, + install: false) + +metainfo_generator = custom_target('metainfo', + output: 'org.freedesktop.libfprint.metainfo.xml', + depend_files: drivers_sources, + capture: true, + command: [ metainfo ], + install: true, + install_dir: datadir / 'metainfo' +) + +if install_udev_rules + udev_rules = executable('fprint-list-udev-rules', + 'fprint-list-udev-rules.c', + dependencies: libfprint_private_dep, + link_with: libfprint_drivers, + install: false) + + custom_target('udev-rules', + output: '70-@0@.rules'.format(versioned_libname), + depend_files: drivers_sources, + capture: true, + command: [ udev_rules ], + install: true, + install_dir: udev_rules_dir, + ) +endif + +sync_udev_udb = custom_target('sync-udev-hwdb', + depends: udev_hwdb_generator, + output: 'sync-udev-hwdb', + install: false, + command: [ + 'cp', '-v', + udev_hwdb_generator.full_path(), + meson.project_source_root() / 'data' + ] +) + +alias_target('sync-udev-hwdb', sync_udev_udb) + +supported_devices = executable('fprint-list-supported-devices', + 'fprint-list-supported-devices.c', + dependencies: libfprint_private_dep, + link_with: libfprint_drivers, + install: false) + + +if get_option('introspection') + # We do *not* include the private header here + libfprint_girtarget = gnome.generate_gir(libfprint, + sources : fp_enums + [ + libfprint_public_headers, + libfprint_sources, + ], + nsversion : '@0@.0'.format(soversion), + namespace : 'FPrint', + symbol_prefix : 'fp_', + identifier_prefix : 'Fp', + export_packages : 'fprint', + extra_args : [ + '--c-include=fprint.h', + ], + link_with : libfprint, + dependencies : [ + gio_dep, + gobject_dep, + gusb_dep, + ], + includes : [ + 'Gio-2.0', + 'GObject-2.0', + 'GUsb-1.0', + ], + fatal_warnings: true, + install : true) + libfprint_gir = libfprint_girtarget[0] + libfprint_typelib = libfprint_girtarget[1] +endif From 66027a9babbbe27ff7b0816ab287051e96d6e943 Mon Sep 17 00:00:00 2001 From: JadegamesUK Date: Mon, 1 Jun 2026 11:53:39 +0100 Subject: [PATCH 2/4] Change microarray.c so you can enrol multiple fingerprints --- src/microarray.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/microarray.c b/src/microarray.c index d85c6c2..7f962fd 100644 --- a/src/microarray.c +++ b/src/microarray.c @@ -420,25 +420,38 @@ enroll_run_state (FpiSsm *ssm, FpDevice *device) break; case ENROLL_EMPTY: { - /* Check bitmap from pre-enrollment ReadIndex */ + /* Check bitmap from pre-enrollment ReadIndex to find a free slot */ const guint8 *resp = self->resp_buf + MA_OVERHEAD; + self->fid = -1; + if (resp[0] == 0x00) { for (int byte = 0; byte < 4 && self->fid < 0; byte++) { for (int bit = 0; bit < 8; bit++) { + int candidate_slot = byte * 8 + bit; + + /* STRICT CAP: Your chip only supports up to slot 9 (10 fingers total) */ + if (candidate_slot > 9) { + break; + } + + /* If this bit is 0, the slot is empty! Let's claim it. */ if (!(resp[1 + byte] & (1 << bit))) { - self->fid = byte * 8 + bit; + self->fid = candidate_slot; break; } } } } - if (self->fid >= 0) { - fp_dbg ("FID slot %d free, skipping Empty", self->fid); + + /* If we found a valid free slot (0-9), skip erasing and proceed to scan */ + if (self->fid >= 0 && self->fid <= 9) { + fp_dbg ("Found free FID slot %d. Proceeding to image capture.", self->fid); fpi_ssm_jump_to_state (ssm, ENROLL_GET_IMAGE); return; } - /* No free slots — erase all templates, use slot 0 */ - fp_dbg ("no free FID slots, clearing all templates (CMD 0x0D)"); + + /* FALLBACK: If slots 0-9 are completely full, nuke the chip to start fresh */ + fp_dbg ("Storage slots 0-9 are completely full! Clearing all templates."); self->fid = 0; cmd[0] = MA_CMD_EMPTY; ma_submit_cmd (ssm, device, cmd, 1); From 16676247cefb090df74f0128a379f47bfcbadd9e Mon Sep 17 00:00:00 2001 From: JadegamesUK Date: Mon, 1 Jun 2026 12:10:15 +0100 Subject: [PATCH 3/4] updated steps in README.md for this to actually work! --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 102052e..519c204 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ meson setup build 5. Copy this repo ```bash -git clone https://github.com/jdillon/libfprint-microarray.git ~/libfprint-microarray +git clone https://github.com/jadegamesuk/libfprint-microarray.git ~/libfprint-microarray ``` 6. Make changes to ~/libfprint @@ -102,17 +102,19 @@ sudo udevadm control --reload-rules && sudo udevadm trigger ## Testing ```bash - # Restart daemon sudo systemctl stop fprintd sudo G_MESSAGES_DEBUG=all /usr/libexec/fprintd -t 2>&1 +``` + +### Open a new Terminal Window for the following +```bash # Enroll right index finger (6 press/lift cycles) fprintd-enroll -f right-index-finger # Verify fprintd-verify -f right-index-finger - ``` **If there is a future update of libfprint, re-running Step (6) above should make everything work again.** From 9aff905b91aaf174a219419f310b7c4bfc82e85e Mon Sep 17 00:00:00 2001 From: JadegamesUK Date: Mon, 1 Jun 2026 12:33:39 +0100 Subject: [PATCH 4/4] Cleaning up README.md steps even more --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 519c204..650ec1a 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ See [Reverse Engineering](docs/reverse-engineering.md) for how to reproduce. - Extra GET_IMAGE calls between GenChars corrupt the device's char buffer state. The `waiting_for_lift` approach must minimize GET_IMAGE polling between captures. ## Instructions -1. Update your machine +1. Plug in device & update your machine ```bash sudo apt update @@ -66,6 +66,7 @@ sudo apt install -y git build-essential meson ninja-build \ 3. Clone the official libfprint source code to ~/libfprint directory ```bash +rm -rf ~/libfprint git clone https://gitlab.freedesktop.org/libfprint/libfprint.git ~/libfprint ``` @@ -80,6 +81,7 @@ meson setup build 5. Copy this repo ```bash +rm -rf ~/libfprint-microarray/ git clone https://github.com/jadegamesuk/libfprint-microarray.git ~/libfprint-microarray ``` @@ -115,6 +117,18 @@ fprintd-enroll -f right-index-finger # Verify fprintd-verify -f right-index-finger + +# Options for [finger]: +left-thumb +left-index-finger +left-middle-finger +left-ring-finger +left-little-finger +right-thumb +right-index-finger +right-middle-finger +right-ring-finger +right-little-finger ``` **If there is a future update of libfprint, re-running Step (6) above should make everything work again.**