You are on page 1of 15

BIOMETRICS USING BLOCKCHAIN

A thesis submitted in partial fulfillment of the requirements for


the award of the degree of

B.Tech.

in

ELECTRONICS AND COMMUNICATION ENGINEERING

By ASHISH CHITALE (108119028)

RUSHIKESH KANAME (108119050)

DEPARTMENT OF
DEPARTMENT NAME
NATIONAL INSTITUTE OF TECHNOLOGY
TIRUCHIRAPPALLI-620015
MAY 2023
Figure 2.1: Structure of a Blockchain

Another important aspect of blockchain is that it uses cryptography to ensure the


integrity and security of transactions. Each block in the chain contains a cryptographic
hash of the previous block, making it impossible to alter past transactions without also

altering all subsequent blocks. Additionally, transactions are verified and approved
by a network of nodes using complex algorithms and consensus mechanisms, further
ensuring the validity of the data. The most well-known implementation of blockchain

technology is the cryptocurrency Bitcoin, but the potential applications of blockchain


go far beyond just digital currencies. It has been proposed for use in a wide range of
industries, including finance, healthcare, supply chain management, and more, as a way

to increase efficiency, security, and transparency.


In the context of biometrics, blockchain technology can be used to store and man-
age biometric data in a secure and decentralized manner, reducing the risk of data

breaches and unauthorized access. By incorporating biometric authentication into the


blockchain, users can maintain control over their own data and grant access to third par-
ties as needed, while maintaining the privacy and security of their sensitive information.

2.2 IPFS

IPFS, an acronym for InterPlanetary File System, is a revolutionary protocol and net-

work that facilitates a distributed method for storing and accessing files in a decentral-

5
4.1 Proposed Architecture

Figure 4.1: Proposed Architecture

We used image processing techniques to convert the fingerprint image to a binary for-
mat, such as black and white pixels, where black represents the fingerprint ridges and

white represents the valleys. Once we have the binary data, we will apply the AES
encryption algorithm to encrypt the data. This can be done using a software library or
a programming language that supports AES encryption. After encryption, we saved the

encrypted data to our IPFS system. The encrypted data will look like random bytes of
data and will not be readable in its encrypted form without the secret key. To decrypt

11
can be used for various purposes, such as verifying the identity of the user and detecting

any modifications or tampering with the data.

Data Encryption

After obtaining the data hash for the fingerprint image, we apply encryption using the
AES algorithm to ensure data security before uploading it to the IPFS. This process

ensures the immutability feature of the entire system. By encrypting the template, we
render it useless to malicious attackers, since decryption without the appropriate key is
virtually impossible, even through brute-force attacks. This step serves to augment the

system’s security by adding an extra layer of protection.

6.1.3 Storing the Data On IPFS

The encrypted data is stored on the IPFS, which functions as a decentralized file system.
By leveraging IPFS, we reduce the gas price required to deploy smart contracts and
execute commands on the ethereum test network. After successfully storing the data on

IPFS, a corresponding CID or IPFS ID is generated, which we subsequently store on


the ethereum test network.

Figure 6.2: Data sent to IPFS Successfully

21
6.1.4 Upload the CID on Ethereum Test Network

After obtaining the CID, we proceed to upload it onto the Ethereum test network using

Hardhat, which is an inbuilt JavaScript library. For our simulation, we utilized Georli
as our test network, as it does not entail any real monetary expenses. We created and
deployed smart contracts for data uploading and retrieval using remix IDE. Metamask

wallet was used for deploying these smart contracts.

Figure 6.3: smart contracts to upload and retrive data from Ethereum Test Net

Figure 6.4: Data sent to Ethereum Network Successfully

22
6.2 User Verification

In this section, we will delve into user verification, which entails collecting user input
and comparing it against the encrypted user data that we possess. Since the data we

possess is encrypted, we need to decrypt it before performing the comparison. Addi-


tionally, we will explore the fingerprint matching algorithm utilized in this project.

6.2.1 Getting User Input

For User Verification also we need to get inputs from user like user email and user
fingerprint. The image below shows the same.

Figure 6.5: Verify user Input Form

6.2.2 Retrieving the Storage Data

In order to authenticate user input against the data stored in our system, it is necessary
for both sets of information to be in the same format. However, since our stored data is
encrypted, it must be decrypted prior to comparison. To encrypt the data, we utilized

23
based on the distance between their descriptors.

We used this algorithm because it can handle variations in fingerprint orientation,


which is a critical factor in matching fingerprints accurately. SIFT uses a technique
called orientation assignment to assign a canonical orientation to each keypoint in the

fingerprint image, allowing it to match fingerprints that have been rotated with respect
to each other. Overall, SIFT is a powerful fingerprint matching algorithm that can
effectively match fingerprints under a wide range of variations, making it a popular

choice in biometric identification systems.

6.2.5 Authenticate User Data

Upon receiving the user input, we retrieved all the stored data within our system. In our
proposed system, the user’s data is compared with all other available user data to verify

its authenticity. This verification process is used to determine whether the user’s data
is already present within the system, and if not, it is subsequently added. Furthermore,
this verification procedure can be utilized to detect the manipulation or presence of

counterfeit data. If the user is verified successfully, success verdict will be shown on
user’s screen as shown below.

Figure 6.6: User Verified Successfully

25
blockchain networks may prioritize smaller transactions, leading to longer confirmation

times and higher fees for larger file uploads.


However, our proposed architecture takes a different approach by uploading the
IPFS CID, whose size remains constant at 32 bytes for every input. This means that the

amount of gas consumed in our case is constant, regardless of the size of the input. This
makes our system more efficient and scalable.

File Size(B) Gas Consumed(in gas units) Gas consumed using our System(in gas units)
107 223559 5057
938 465001 5103
4610 665595 4080
10111 1064139 5009
12379 1383016 4912

Table 7.2: Cost analysis of Traditional system vs cost analysis of our system

Figure 7.1: Cost analysis of our system against the Traditional system

7.2 Time analysis

As the size of the uploaded file increases, the processing time required for the trans-
action to be included in a block on the Ethereum blockchain also increases. This is

27
because larger files consume more gas, which in turn demands more computational re-

sources and processing time. For instance, a transaction involving the upload of a small
file of a few bytes may be processed and added to a block relatively quickly. In contrast,
a transaction involving a larger file of several megabytes could take several minutes or

even hours to be processed and included in a block, depending on the congestion of the
network and the gas price set by the user. The figure below represents time analysis of
our improved system against Traditional system.

Figure 7.2: Time analysis of our system against the Traditional system

7.3 Security Analysis

Our system employs blockchain, a highly secure technology. To enhance security, we

have incorporated AES encryption, which makes our system almost impervious to se-
curity breaches. AES-128 encryption offers a key space of 2128 , indicating that there
are 2128 potential keys that can be utilized for data decryption. Assuming that a hacker

gains access to a supercomputer capable of testing 1016 keys per second, it would still
take them around 1017 seconds, equivalent to 3.17 × 109 years, to perform a brute force
attack and test all possible keys.

28
Appendix A

Code Attachments

A.1 Register User

This part of code handles taking user input. When user enters his details in front end part
and clicks on enter button, events are fired in the back end. Those events are handled
by following functions.
1
2 % import e x p r e s s from "express" ;
3 % import m u l t e r from "multer" ;
4 % import F i n g e r p r i n t 2 from "fingerprintjs2" ;
5 % import * a s IPFS from "ipfs-core" ;
6
7 const upload = multer ( ) ;
8 c o n s t app = e x p r e s s ( ) ;
9 c o n s t node = a w a i t IPFS . c r e a t e ( ) ;
10
11 // use body-parser middleware to parse request bodies
12 app . u s e ( e x p r e s s . u r l e n c o d e d ( { e x t e n d e d : t r u e } ) ) ;
13
14 // set the view engine to ejs
15 app . s e t ( "view engine" , "ejs" ) ;
16
17 // render the form template
18 app . g e t ( "/" , ( r e q , r e s ) => {
19 r e s . r e n d e r ( "form" ) ;
20 }) ;
21

22 // handle form submission


23 app . p o s t ( "/addFingerprint" , u p l o a d . s i n g l e ( "image" ) , a s y n c ( r e q , r e s )
=> {
24 c o n s t b u f f e r = B u f f e r . from ( r e q . f i l e . b u f f e r ) ;
25 c o n s t b y t e S t r i n g = b u f f e r . t o S t r i n g ( "binary" ) ;
26

27 c o n s t f i n g e r p r i n t T e m p l a t e = F i n g e r p r i n t 2 . x64hash128 ( b y t e S t r i n g ) ;
28
29 c o n s t r e s u l t = a w a i t node . add ( {
30 p a t h : $ { r e q . body . e m a i l } . t x t ,
31 c o n t e n t : JSON . s t r i n g i f y ( {
32 name : r e q . body . name ,

33
33 e m a i l : r e q . body . e m a i l ,
34 hashedTemplate : f ing erp rin tTe mp lat e ,
35
36 }) ,
37 }) ;
38
39 console . log ( r e s u l t . cid . t o S t r i n g ( ) ) ;
40
41 c o n s t chunks = [ ] ;
42 f o r a w a i t ( c o n s t chunk o f node . c a t ( r e s u l t . c i d ) ) {
43 c h u n k s . p u s h ( chunk ) ;
44 }
45

46 c o n s t r e t r i e v e d M e t a d a t a = JSON . p a r s e ( c h u n k s . t o S t r i n g ( ) ) ;
47
48 console . log ( retrievedMetadata ) ;
49 }) ;
50
51 // start the server
52 c o n s t PORT = p r o c e s s . env . PORT | | 3 0 0 0 ;
53 app . l i s t e n ( PORT , ( ) => {
54 c o n s o l e . l o g ( S e r v e r l i s t e n i n g on p o r t $ {PORT} ) ;
55 }) ;

A.2 Data Preprocessing

In this section we have mentioned all the steps involved in data preprocessing including
data hashing and encryption. Function to decrypt the data is also incuded here.
1
2
3
4 // using canvas to encrypt the image to binary data
5 c o n s t c a n v a s = document . c r e a t e E l e m e n t ( ’canvas’ ) ;
6

7 //function to generate a random key for aes encryption


8
9 c o n s t g e n e r a t e K e y = ( k e y S i z e ) => {
10 //const keySize = 256; // key size in bits (256-bit key for AES
-256)
11 c o n s t key = C r y p t o J S . l i b . WordArray . random ( k e y S i z e / 8 ) ; // key in
WordArray format
12 c o n s t keyHex = key . t o S t r i n g ( ) ; // key in hexadecimal string
format
13 r e t u r n keyHex ;
14 }
15
16 // function to decrypt the data
17
18 c o n s t d e c r y p t D a t a = ( e n c r y p t e d S t r i n g , key ) => {
19 c o n s t d e c r y p t e d = C r y p t o J S . AES . d e c r y p t ( e n c r y p t e d S t r i n g , key ) ;
20 c o n s t d e c r y p t e d D a t a = d e c r y p t e d . t o S t r i n g ( CryptoJS . enc . Utf8 ) ;
21 return decryptedData ;
22 }
23

34
24

25 // code to convert an image to binary data using canvas


26 //Get the binary data: Use the toDataURL method of the canvas
element to get the binary data in base64 format.
27 c o n s t d a t a = c a n v a s . toDataURL ( ’registerFingerprint/jpeg’ ) ;
28 //console.log(data:${data});
29

30 //generate a key to encrypt the data


31 c o n s t key = g e n e r a t e K e y ( 1 2 8 ) ;
32 //console.log(key: ${key}\n);
33
34 // encrypt the ’data’ using aes with the help of ’key’
35 c o n s t e n c r y p t e d = C r y p t o J S . AES . e n c r y p t ( d a t a , key ) ;
36
37 // conver the data to string as it is an object now
38 const encryptedString = encrypted . toString () ;
39 //console.log(encryptedString: ${encryptedString});

A.3 Connect To IPFS


1 import { c r e a t e } from "ipfs-http-client"
2
3 // connect to ipfs daemon API server
4
5 const c l i e n t = create () ;
6
7
8 c l i e n t . i d ( ) . t h e n ( i n f o => {
9 c o n s o l e . l o g ( "Connected to IPFS with peer ID: " , i n f o . i d ) ;
10 } ) . c a t c h ( e r r o r => {
11 c o n s o l e . l o g ( "here error" ) ;
12 c o n s o l e . e r r o r ( "Error connecting to IPFS: " , e r r o r ) ;
13 }) ;
14
15

16
17
18 e x p o r t a s y n c f u n c t i o n addImageToIPFS ( i m a g e D a t a ) {
19 c o n s t a d d e d = a w a i t c l i e n t . add ( i m a g e D a t a ) ;
20 c o n s o l e . log ( added . c i d . t o S t r i n g ( ) ) ;
21 return added . c i d . t o S t r i n g ( ) ;
22 }
23
24 // function to add data on ipfs
25
26 a s y n c f u n c t i o n add ( ) {
27 c o n s t i m a g e U r l = ’https://imageurl.jpg’ ;
28 c o n s t response = await f e t c h ( imageUrl ) ;
29 c o n s t imageData = a w a i t r e s p o n s e . blob ( ) ;
30 c o n s t c i d = a w a i t addImageToIPFS ( i m a g e D a t a ) ;
31 c o n s o l e . l o g ( Image a d d e d t o IPFS w i t h CID $ { c i d } ) ;
32 }
33

34 add ( ) ;

35
A.4 FingerPrint Matching
1 // Define the fingerprints to compare
2 c o n s t f i n g e r p r i n t 1 = document . g e t E l e m e n t B y I d ( ’fingerprint1’ ) ;
3 c o n s t f i n g e r p r i n t 2 = document . g e t E l e m e n t B y I d ( ’fingerprint2’ ) ;
4
5 // Load the jsfeat library
6 j s f e a t = r e q u i r e ( ’jsfeat’ ) ;
7

8 // Define a function to detect features in a fingerprint image


9 f u n c t i o n d e t e c t F e a t u r e s ( img ) {
10 c o n s t c a n v a s = document . c r e a t e E l e m e n t ( ’canvas’ ) ;
11 c a n v a s . w i d t h = img . w i d t h ;
12 c a n v a s . h e i g h t = img . h e i g h t ;
13 c o n s t c t x = c a n v a s . g e t C o n t e x t ( ’2d’ ) ;
14 c t x . drawImage ( img , 0 , 0 ) ;
15 c o n s t i m a g e D a t a = c t x . g e t I m a g e D a t a ( 0 , 0 , img . w i d t h , img . h e i g h t ) ;
16 c o n s t j s f e a t I m g = new j s f e a t . m a t r i x t ( img . w i d t h , img . h e i g h t , j s f e a t
. U8 t | j s f e a t . C1 t ) ;
17 j s f e a t . i m g p r o c . g r a y s c a l e ( i m a g e D a t a . d a t a , img . w i d t h , img . h e i g h t ,
jsfeatImg ) ;
18 j s f e a t . imgproc . e q u a l i z e h i s t o g r a m ( j s f e a t I m g , j s f e a t I m g ) ;
19 const corners = [ ] ;
20 j s f e a t . fast corners . set threshold (20) ;
21 j s f e a t . f a s t c o r n e r s . d e t e c t ( jsfeatImg , corners , 5) ;
22 return c o r n e r s ;
23 }
24
25 // Define a function to compute descriptors for a set of keypoints
26 f u n c t i o n c o m p u t e D e s c r i p t o r s ( img , k e y p o i n t s ) {
27 c o n s t c a n v a s = document . c r e a t e E l e m e n t ( ’canvas’ ) ;
28 c a n v a s . w i d t h = img . w i d t h ;
29 c a n v a s . h e i g h t = img . h e i g h t ;
30 c o n s t c t x = c a n v a s . g e t C o n t e x t ( ’2d’ ) ;
31 c t x . drawImage ( img , 0 , 0 ) ;
32 c o n s t i m a g e D a t a = c t x . g e t I m a g e D a t a ( 0 , 0 , img . w i d t h , img . h e i g h t ) ;
33 c o n s t j s f e a t I m g = new j s f e a t . m a t r i x t ( img . w i d t h , img . h e i g h t , j s f e a t
. U8 t | j s f e a t . C1 t ) ;
34 j s f e a t . i m g p r o c . g r a y s c a l e ( i m a g e D a t a . d a t a , img . w i d t h , img . h e i g h t ,
jsfeatImg ) ;
35 c o n s t d e s c r i p t o r s = new j s f e a t . m a t r i x t ( k e y p o i n t s . l e n g t h , 1 2 8 ,
j s f e a t . U8 t | j s f e a t . C1 t ) ;
36 j s f e a t . surf . dense descriptors ( jsfeatImg , keypoints , d e s c r i p t o r s ) ;
37 return d e s c r i p t o r s ;
38 }
39
40 // Define a function to match descriptors between two images
41 function matchDescriptors ( descriptors1 , descriptors2 ) {
42 const matches = [ ] ;
43 const d i s t s = [ ] ;
44 j s f e a t . m a t u t i l . f i l l ( d i s t s , 255) ;
45 j s f e a t . imgproc . m a t c h d e s c r i p t o r s b r u t e f o r c e ( d e s c r i p t o r s 1 ,
d e s c r i p t o r s 2 , matches , d i s t s ) ;
46 const filteredMatches = [ ] ;
47 const distThreshold = 0.2;
48 f o r ( l e t i = 0 ; i < m a t c h e s . l e n g t h ; i ++) {
49 if ( dists [ i ] < distThreshold ) {

36
50 f i l t e r e d M a t c h e s . push ( matches [ i ] ) ;
51 }
52 }
53 return f i l t e r e d M a t c h e s ;
54 }
55
56 // Call the SIFT functions to compare the fingerprints
57 const keypoints1 = detectFeatures ( fingerprint1 ) ;
58 const keypoints2 = detectFeatures ( fingerprint2 ) ;
59 const descriptors1 = computeDescriptors ( fingerprint1 , keypoints1 ) ;
60 const descriptors2 = computeDescriptors ( fingerprint2 , keypoints2 ) ;
61 const matches = m at c h De s c ri p t o rs ( d e s c r i p t o r s 1 , d e s c r i p t o r s 2 ) ;
62

63 // Print the number of matches


64 console . log ( matches . l e n g t h ) ;

A.5 Smart Contracts

This sections provides the smart contracts written in solidity language. The smart con-

tracts were written and deployed using remix ide.


1
2 pragma s o l i d i t y >=0.7.0 < 0 . 9 . 0 ;
3 c o n t r a c t ImgStorage {
4
5 s t r u c t Fing {
6 s t r i n g name ;
7 string hashid ;
8 }
9
10
11 Fing [ ] d at a ;
12 f u n c t i o n p u s h ( s t r i n g memory name , s t r i n g memory h a s h i d ) p u b l i c {
13 F i n g memory f i n g 1 ;
14 f i n g 1 . name = name ;
15 fing1 . hashid = hashid ;
16 d a t a . push ( f i n g 1 ) ;
17 }
18
19
20 f u n c t i o n r e t u r n D a t a ( ) p u b l i c view r e t u r n s ( F i n g [ ] memory ) {
21 return data ;
22 }
23
24 }
25

26 % C o n t r a c t t o u p l o a d and r e t r i v e d a t a
27
28 pragma s o l i d i t y >=0.7.0 < 0 . 9 . 0 ;
29
30 c o n t r a c t ImageUpload {
31

32 / / D e c l a r e a b y t e s v a r i a b l e t o s t o r e t h e image
33 b y t e s p u b l i c image ;
34

37
35 / / D e c l a r e an e v e n t t o e m i t when a new image i s u p l o a d e d
36 e v e n t NewImage ( b y t e s i m a g e ) ;
37
38 / / F u n c t i o n t o u p l o a d t h e image t o t h e b l o c k c h a i n
39 f u n c t i o n u p l o a d I m a g e ( s t r i n g memory i m a g e ) p u b l i c {
40 image = b y t e s ( i m a g e ) ;
41 e m i t NewImage ( image ) ;
42 }
43
44 / / F u n c t i o n t o g e t t h e u p l o a d e d image
45 f u n c t i o n g e t I m a g e ( ) p u b l i c view r e t u r n s ( b y t e s memory ) {
46 r e t u r n image ;
47 }
48
49 }

38

You might also like