bastianraschke / pyfingerprint

Python library for ZhianTec fingerprint sensors (e.g. ZFM-20, ZFM-60)
Other
190 stars 115 forks source link

fingerprint characteristics seem to change inside the reader #70

Open gitcat555 opened 5 years ago

gitcat555 commented 5 years ago

Hey all, I've been working with this library for quite some time now and my understanding of how the reader works is:

(please correct me if I'm wrong!)

Now the problem I am facing is that the template does not quite seem to be exactly the same whenever I am scanning a fingerprint. I have even tried extracting the characteristics of the template, then deleting all templates from the reader and uploading the characteristics to the reader. After that, I do a scan and finds a match, however the raw characteristics differ from the ones uploaded, hence a different hash is generated. Therefore, it seems hashing is utterly pointless?!

Anyone else encounter this issue? After all, the reader can be used to authenticate someone, however working with hashes or matching raw characteristics 1:1 is not an option, obviously...

Is this normal? Any help much appreciated!

philippmeisberger commented 5 years ago

Hey @gitcat555 , I could not reproduce this behavior. In my case the same hash is generated. Could you provide some code which reproduces the faulty behavior?

gitcat555 commented 5 years ago

Hey @philippmeisberger , for a test I have loaded but ONE fingerprint onto the reader and I'm using the example_search.py, code below:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
PyFingerprint
Copyright (C) 2015 Bastian Raschke <bastian.raschke@posteo.de>
All rights reserved.

"""

import hashlib
from pyfingerprint.pyfingerprint import PyFingerprint

## Search for a finger
##

## Tries to initialize the sensor
try:
    f = PyFingerprint('/dev/ttyUSB0', 57600, 0xFFFFFFFF, 0x00000000)

    if ( f.verifyPassword() == False ):
        raise ValueError('The given fingerprint sensor password is wrong!')

except Exception as e:
    print('The fingerprint sensor could not be initialized!')
    print('Exception message: ' + str(e))
    exit(1)

## Gets some sensor information
print('Currently used templates: ' + str(f.getTemplateCount()) +'/'+ str(f.getStorageCapacity()))

## Tries to search the finger and calculate hash
try:
    print('Waiting for finger...')

    ## Wait that finger is read
    while ( f.readImage() == False ):
        pass

    ## Converts read image to characteristics and stores it in charbuffer 1
    f.convertImage(0x01)

    ## Searchs template
    result = f.searchTemplate()

    positionNumber = result[0]
    accuracyScore = result[1]

    if ( positionNumber == -1 ):
        print('No match found!')
        exit(0)
    else:
        print('Found template at position #' + str(positionNumber))
        print('The accuracy score is: ' + str(accuracyScore))

    ## OPTIONAL stuff
    ##

    ## Loads the found template to charbuffer 1
    f.loadTemplate(positionNumber, 0x01)

    ## Downloads the characteristics of template loaded in charbuffer 1
    characterics = str(f.downloadCharacteristics(0x01)).encode('utf-8')

    ## Hashes characteristics of template
    print('SHA-2 hash of template: ' + hashlib.sha256(characterics).hexdigest())

except Exception as e:
    print('Operation failed!')
    print('Exception message: ' + str(e))
    exit(1)

Then I use the script to scan the finger multiple times:

> root@raspi:~/development/finger # ./example_search.py 
> Currently used templates: 1/150
> Waiting for finger...
> Found template at position #0
> The accuracy score is: 136
> SHA-2 hash of template: 231b3aca7acf593a1260e79b1dbf91697c42460931477a6a02cc8e7e49922fbf
> root@raspi:~/development/finger # ./example_search.py 
> Currently used templates: 1/150
> Waiting for finger...
> Found template at position #0
> The accuracy score is: 189
> SHA-2 hash of template: 0f1c0cd015b985e355887da8feffd6971e6c8179ab06f1da0c4772afe0e4c8d5
> root@raspi:~/development/finger # ./example_search.py 
> Currently used templates: 1/150
> Waiting for finger...
> Found template at position #0
> The accuracy score is: 174
> SHA-2 hash of template: 0f1c0cd015b985e355887da8feffd6971e6c8179ab06f1da0c4772afe0e4c8d5
> root@raspi:~/development/finger # ./example_search.py 
> Currently used templates: 1/150
> Waiting for finger...
> Found template at position #0
> The accuracy score is: 200
> SHA-2 hash of template: 0f1c0cd015b985e355887da8feffd6971e6c8179ab06f1da0c4772afe0e4c8d5
> root@raspi:~/development/finger # ./example_search.py 
> Currently used templates: 1/150
> Waiting for finger...
> Found template at position #0
> The accuracy score is: 285
> SHA-2 hash of template: 0f1c0cd015b985e355887da8feffd6971e6c8179ab06f1da0c4772afe0e4c8d5
> root@raspi:~/development/finger # ./example_search.py 
> Currently used templates: 1/150
> Waiting for finger...
> Found template at position #0
> The accuracy score is: 396
> SHA-2 hash of template: 868e3ef2cd322c8ec264abf7a4268c1e5bd0713b57bfd9dba3ab21d936c425e3
> root@raspi:~/development/finger # ./example_search.py 
> Currently used templates: 1/150
> Waiting for finger...
> Found template at position #0
> The accuracy score is: 272
> SHA-2 hash of template: 868e3ef2cd322c8ec264abf7a4268c1e5bd0713b57bfd9dba3ab21d936c425e3 

As you can see, the hash is sometimes identical and then it's a completely different one. I then did a little modification to the search script to write out the raw characteristics to a file:

myFile = open("/tmp/read_raw.txt","w+" + "\n")
myFile.write(characterics) 
myFile.close()

I then move the file from tmp to a folder after each scan and name it 1.txt, 2.txt etc. and compare them with diff. When the hash is different, the characteristics are indeed different, too. But how can this be when it should actually always be the SAME template that is being loaded? And there is only a single template in the reader anyway?!

philippmeisberger commented 5 years ago

Indeed, this is really strange. I still could not reproduce it with ZFM-20:

phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 52 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88 phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 82 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88 phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 83 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88 phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 65 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88 phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 93 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88 phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 94 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88 phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 126 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88 phil@asgaard ~/Informatik/PMCW/Projekte/PyFingerprint/src/files/examples $ python2 example_search.py Currently used templates: 2/1000 Waiting for finger... Found template at position #0 The accuracy score is: 73 SHA-2 hash of template: 196c0d73f3997581dbd2231787bffc1f5920ccd8b80828fc1c47b89156913b88

Which sensor do you use?

gitcat555 commented 5 years ago

I also hav a ZFM-20 and sometimes I would get the same hash 10 or even 20 times in a row! However, it is never the same hash of the print I enrolled.

By the way: is it possible to pull the characteristics from the actual template position and skip the step of copying it to charbuffer 1?

philippmeisberger commented 5 years ago

You mean this line?

f.loadTemplate(positionNumber, 0x01)

If you delete this line you would get a different hash as you download the contents of image buffer. The stored template must be downloaded to get the same hash constantly.

gitcat555 commented 5 years ago

So it has to be downloaded to 0x01 before it can be worked with? I just meant, well, if it is possible to work with a template directly at its actual storage position. The library code does not seem to support this, but would it be possible?

philippmeisberger commented 5 years ago

Sure, you can directly access the stored templates. But the reading process (readImage()) results just in an image which has to be converted to an template by extracting the fingerprint characteristics (convertImage()). The resulting template can then be compared to the stored ones (searchTemplate()). That's the normal process. User can be recognized.

The loadTemplate() loads a stored template into a char buffer. This is only necessary if you want to download the stored characteristics to produce a hash in a constant way. If you would download the actual extracted characteristics the hash always differs as you cannot put your finger to the exact position where you enrolled it. loadTemplate() already allows you to access templates directly and work with it.

JimVanEeden commented 5 years ago

I actually have the exact same problem

Found fingerprint at position 3, accuracy 111, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 191, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 221, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 268, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 161, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 169, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 131, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 170, hash b94adebdb5ffac569d9a035eb31192d821618a2d24186d27ade4dfcb23087fea
Found fingerprint at position 3, accuracy 110, hash 8ebce69b473fffb8dbc1849da9d4e03f97dc7c0c14ee80b1c0295b2352425639
Found fingerprint at position 3, accuracy 169, hash fc78028b94bd98a7ddc55ac888b37fe4dcb5bd6e6638fe9699211dea48e6e136
Found fingerprint at position 3, accuracy 186, hash 48b2a3f7bac5153e1773d30af05d387a8ee4b00ba6eb1eeb85983399efc1a87f
Found fingerprint at position 3, accuracy 165, hash e5d329f4e3464b76ee6c9571fcc4ddf23c3add37fa87f563d7d868b618cd5203
Found fingerprint at position 3, accuracy 105, hash e5d329f4e3464b76ee6c9571fcc4ddf23c3add37fa87f563d7d868b618cd5203
Found fingerprint at position 3, accuracy 287, hash e5d329f4e3464b76ee6c9571fcc4ddf23c3add37fa87f563d7d868b618cd5203

Not sure how to solve this.

gitcat555 commented 5 years ago

At least I'm not the only one. I thought I was going mad at first! So what is the actual problem? Could it be faulty hardware? @philippmeisberger are you absolutely sure your ZFM-20 is ALWAYS producing the same hash? Give it say at least 30 rounds and try placing the finger in a slightly different way so that it will still find a match but normally in my case this causes a different hash to be produced.

tobitti0 commented 5 years ago

I have the same problem. The sensor I am using is R302. Generate a hash of the template stored in the sensor from the template ID obtained when fingerprint collation is performed and compare it with the hash stored in the user list held by the program so that an illegal list etc. is not used Created a program. However, because the template might change, it did not work as expected. Will this problem not be solved? Another method for list matching must be considered. Sorry for machine translation.

alexander-rieder commented 2 years ago

Sorry for responding to such an "old" issue - but in have the same experience with an R302.

To my understanding, the sensor works as follows when we initiate a search for a fingerprint match:

  1. Sensor searches for a match with given characteristic in the templates
  2. if it finds a matching template it retrieves the template and updates the template characteristic for a better future matching experience
Hasenko commented 2 years ago

Sorry for responding to such an "old" issue - but in have the same experience with an R302.

To my understanding, the sensor works as follows when we initiate a search for a fingerprint match:

  1. Sensor searches for a match with given characteristic in the templates
  2. if it finds a matching template it retrieves the template and updates the template characteristic for a better future matching experience

Did you find the way to this problem, if yes, can i get help please ? I have the same problem

alexander-rieder commented 2 years ago

No... not really solved the problem. I haven't found a way to disable the automatic fingerprint "optimization".

What problem are you facing / why is the optimization a problem for you?

Hasenko commented 2 years ago

No... not really solved the problem. I haven't found a way to disable the automatic fingerprint "optimization".

What problem are you facing / why is the optimization a problem for you?

Cause i want to store it in a sqlite database to be able to use 2 sensors. One to register new finger and the other to compare finger.

alexander-rieder commented 2 years ago

you still can do that. You could for example regularly retrieve the "optimized" fingerprints from the scanner which compares the finger and store it in the database.

Hasenko commented 2 years ago

Ok i will try this. Just in case, is this possible to compare finger with the image. I extract the image then i compare the 2 finger with a library of finger recognition

alexander-rieder commented 2 years ago

In my experience the image extraction is too slow..

Hasenko commented 2 years ago

In my experience the image extraction is too slow..

Hey, i'm back ! I have a question, do you know how can i compare a finger to a characteristics. If i know that, i think i can do it !

Hasenko commented 2 years ago

Nevermind, it work !! Thank you for your help @alexander-rieder !

josevargasop commented 6 months ago

Nevermind, it work !! Thank you for your help @alexander-rieder !

Can you share how you did it?

Hasenko commented 6 months ago

Nevermind, it work !! Thank you for your help @alexander-rieder !

Can you share how you did it?

Hello, yes, I can share with you how I managed to do it. It's been a while, so if something is not clearly explained, let me know. I removed all the unnecessary parts of my code, so only useful things remain. At this time I wasn't the best with coding, so my code could certainly be improved. Here, I'll explain to you how to remove fingerprint data from the sensor and store it in an external database (SQLite for me). Then, I'll explain how to do the opposite (retrieve every fingerprint data from the external database and upload it to the sensor). If you have any questions, don't hesitate.

Store fingerprint in an external database

global gout

def timer():
    global gout
    gout = False
    compteur = 11
    while (f.readImage() == False ):
        gout = True
        compteur -= 1
        time.sleep(1)
        if compteur == 0:
            gout = False
            break

# connection to the fingerprint sensor
f = PyFingerprint('/dev/ttyAMA1', 57600, 0xFFFFFFFF, 0x00000000)

# if password is false
if ( f.verifyPassword() == False ):
    # do what you want

try:
    timer()
    time.sleep(0.2)
    # if a finger is detected
    if gout is True:
        f.convertImage(0x01)

        # ask user to remove his finger

        time.sleep(1)

        # ask user to put his same finger

        time.sleep(1)

        gout = False
        timer()

        # if a second finger is detected
        if gout is True:
            f.convertImage(0x02)
            gout = False

            # if the two finger are not the same
            if ( f.compareCharacteristics() == 0 ):
                # do what you want

            # if the two finger are the same
            else:
                # store fingerprint in the sensor
                positionNumber = f.storeTemplate()
                f.loadTemplate(positionNumber = positionNumber, charBufferNumber = 1)

                # take the fingerprint out of the sensor
                cr = f.downloadCharacteristics()

                # store fingerprint of the user in "code" with some modification
                code = ','.join(str(v) for v in cr)
                # clear sensor database
                f.clearDatabase()

                # then you can store "code" in your project database

        # if the second finger is not detected
        else:
            # do what you want

    # if no finger is detected
    else:
        # do what you want

# if an error appear
except Exception as e:
    # do what you want

Obtain fingerprint data from external database and store it in the second sensor

try:
    # connection to the external database
    connection = sqlite3.connect(r"/home/pi/database/user.db", check_same_thread=False)
    cursor = connection.cursor()

    # connection to the fingerprint sensor
    f = PyFingerprint('/dev/ttyS0', 57600, 0xFFFFFFFF, 0x00000000)

    # if password is false
    if ( f.verifyPassword() == False ):
        # do what you want

    # obtain data from my external database
    req = cursor.execute('SELECT * FROM users')
    data = cursor.fetchall()

    # remove every fingerprint from the sensor
    f.clearDatabase()

    # browse all data
    for row_finger in data:
        id = row_finger[0]
        database_finger = row_finger[5] # position of fingerdata from database
        bef_carac = list(database_finger.split(',')) # remove the modification from last code

        # store data in the sensor
        carac = [int(i) for i in bef_carac]
        f.uploadCharacteristics(charBufferNumber = 1, characteristicsData = carac)
        f.storeTemplate(positionNumber = id, charBufferNumber = 1)

except Exception as e:
    # do what you want