Конкурс Распил SDK сканера отпечатков пальцев Bio Link fs80

  • Автор темы phlex
  • Дата начала
"Статья для участия в конкурсе Тестирование Веб-Приложений на проникновение"​

Предыстория

Безопасность данных всегда была, есть, и остается больной темой для всех людей и айтишников. Говорить по данной тематике можно бесконечно, иначе говоря от слов к делу. В недалёком 2014 году, когда учился на 5 курсе речь зашла о дипломе и практических навыках, полученных за всё обучение. Почему остановился на разработке, да ещё и связанной с биометрией, ответ прост – были наработки. Целью работы являлось – реализовать ПО для получения биометрических данных, иначе говоря – конечная задача свелась к получению картинки с специальными точками, по которым производится идентификация.

Что бы реализовать ПО выделил для себя основные моменты:
  • минимизировать число необходимых процедур и функций, для увеличения быстродействия и удобства дальнейшего использования;
  • вкратце описать модули разработчика, потому как лезть в дизассемблер очень затяжное дело, и скорее всего не получилось бы;
  • разработать блок схему для общего представления о функционале;
  • описать типовые решения применения.
Как видно из вышеперечисленного перечня, фронт работ обозначен. Для реализации у меня был оптический сканер fs80 и диск с коммерческим ПО BIO Link. В долгих поисках адекватно работающего SDK пришлось разочароваться, потому как столкнулся с кучей багов и ограничений разработчиков BIO Link и других вендоров. Время поджимало и остановился на официальном, бесплатно распространяемом Free Fingerprint Verification SDK. Данный комплект средств разработки поддерживает взаимодействие с множеством оптических сканеров и имеет ограничение на хранение до десяти пользователей в стандартной базе данных. Функционал SDK организован на основе алгоритма упрощенной версии VeriFinger Fingerprint Identification SDK, которая производит верификацию с эталонным качеством 1:1. SDK взаимодействует с: платформами Microsoft Windows 2000, XP, Vista, а также 32-разрядной архитектурой процессора (честно заработало и на 64- разрядном процессоре с windows 8).

После непродолжительных танцев с бубном и трассировкой Delphi – вуаля, сканы пальцев со спец точками корректно создавались. Реализация свелась к любимой всеми теории, где основными моментами стали:

Анализ биометрических данных

основываясь на законодательстве в области обработки ПДн, а именно Федеральном законе РФ "О персональных данных" (152-ФЗ), глава 2, статья 11, следует, что биометрические персональные данные – это:
  1. 1. Сведения, которые характеризуют физиологические и биологические особенности человека, на основании которых можно установить его личность (биометрические персональные данные) и которые используются оператором для установления личности субъекта персональных данных, могут обрабатываться только при наличии согласия в письменной форме субъекта персональных данных, за исключением случаев, предусмотренных частью 2 настоящей статьи.
  2. 2. Обработка биометрических персональных данных может осуществляться без согласия субъекта персональных данных в связи с реализацией международных договоров Российской Федерации о реадмиссии, в связи с осуществлением правосудия и исполнением судебных актов, а также в случаях, предусмотренных законодательством Российской Федерации об обороне, о безопасности, о противодействии терроризму, о транспортной безопасности, о противодействии коррупции, об оперативно - розыскной деятельности, о государственной службе, уголовно – исполнительным законодательством Российской Федерации, законодательством Российской Федерации о порядке выезда из Российской Федерации и въезда в Российскую Федерацию.
Исходя из официальной статистики применения биометрических методов идентификации: отпечатки пальцев – 59%; геометрия лица – 17%; радужная оболочка – 7%; геометрия руки – 7%; рисунок вен – 7%; голос – 5%; почерк – 1%; все остальное – 1%.
В качестве анализа, также можно привести экспертные оценки свойств биометрических характеристик человека:

1.png

Основные биометрические данные человека рассматриваются по 4-м критериям, а именно: Универсальность - это применение в различных задачах (контроль доступа, идентификация, аутентификация). Уникальность – свойство, зависящее от источника получаемой информации с возможностью идентификации личности 1:1. Стабильность — это способность источника данных функционировать, не меняя своих структурных свойств. Собираемость – это возможность получения биометрической характеристики от каждого индивидуума в реальном времени.

В практическом применении метода биометрических характеристик главным параметром является универсальность и уникальность той или иной технологии.

Анализ алгоритмов получения биометрических данных и методов идентификации при помощи особых точек на отпечатках пальцев;

Отпечаток пальца состоит из хребтов и впадин, которые образуют папиллярный рисунок (рисунок 1). Отпечаток имеет два вида признаков: глобальные и локальные. Глобальные признаки описывают общее положение папиллярных линий.

2.png

Рисунок 1 - Отпечаток пальца с отмеченными папиллярными линиями

Локальные признаки отпечатков пальцев описывают расположение линий в окрестности минуций. Минуция - такая точка отпечатка пальца, где папиллярная линия обрывается или разделяется на две. Из этих двух типов могут быть составлены более сложные виды минуций (рисунок 2).

3.png

Рисунок 2 - Разные виды минуций

Особые точки на отпечатках пальца относятся к глобальным признакам и бывают двух видов: точка ядра и точка дельты. Ядро - точка отпечатка пальца, которую огибает максимальное количество папиллярных линий (рисунок 3).
4.png

Рисунок 3 - Точка ядра на отпечатке пальца

Дельта - точка отпечатка пальца, вокруг которой папиллярные линии расходятся в трех разных направлениях (рисунок 4).
5.png

Рисунок 4 - Точка дельты на отпечатке пальца

Локальные признаки, в отличие от глобальных, у каждого человека являются индивидуальными. Поэтому для идентификации пользуются методом распознавания по минуциям. Т.е. информация, полученная в результате съема отпечатка со сканнера, сравнивается с информацией в базе данных. Данный метод имеет ряд недостатков, таких как трудоемкость, чувствительность к локальному растяжению и плохая масштабируемость.

Также на положении особых точек основывается классификация отпечатков пальцев. Тип отпечатка пальца - еще один вид глобальных признаков. Отпечатки разделяются на три основных типа: спираль, петля и дуга (рис. 5).
6.png

Рисунок 5 - Отпечатки типа «Петля», «Спираль» и «Дуга»

Для определения особых точек на отпечатке пальца существует четыре основных подхода к определению особых точек: метод индекса Пуанкаре; метод комплексных фильтров 1 степени; метод комплексных фильтров 2 степени; метод индекса Пуанкаре с преобразованием Хафа.
Метод индекса Пуанкаре и метод комплексных фильтров 1 степени, реализованы евклидовым расстоянием между особыми точками, что является наиболее распространёнными методами. Углубляться в мат часть не вижу смысла, получится copy/past.

Адекватно описать функционал получения биометрических данных пользователя собственного ПО;

Для решения поставленных целей, будет использоваться часть комплекта разработчика, связанная с языком программирования Object Pascal: Nffv.pas; NffvUser.pas; UserList.pas; Util.pas
Рассмотрим модуль Nffv.pas, который является контейнером методов и классов для использования бесплатной версии SDK.
Вначале остановимся на типе данных для отображения статуса сканера (листинг 1):

Листинг 1.
Код:
type
TNffvStatus = ( nfesNone = 0, nfesTemplateCreated = 1,
{ временные данные сканера(подключение базы/инициализация драйвера). }
  nfesNoScanner = 2, { наличие сканнера }
  nfesScannerTimeout = 3, { сканер находится в ожидании}
  nfesUserCanceled = 4, { отменение действий пользователем }
  nfesQualityCheckFailed = 100 { наличие ошибок}
);
Базовым классом для отображения процедур и функций, с которыми взаимодействует программа, является TNffv = class (листинг 2):

Листинг 2.
Код:
type
  TNffv = class
  private
  public
  Constructor Create(databaseName: string; password: string); overload;
  { Создание нового экземпляра обьекта TNffv(параметры базы данных, пароля и  модулей сканера). }
Constructor Create(databaseName: string; password: string; scannerModules: string); overload;
{конструктор, инициализирующий сканер, от параметров //обьекта TNffv}
  Destructor  Destroy; override;
{деструктор объекта}
  procedure RemoveUsers;
{очистка стандартной базы данных}
  procedure RemoveUser(index: LongInt);
{удаление пользователя по индексу в базе}
  function GetUserCount: LongInt;
{Получение номера пользователей контейнера Nffv}
  function GetUserByIndex(index: LongInt): TNffvUser;
{возвращает индекс выбранного пользователя}
  function GetUserById(id: LongInt): TNffvUser;
{возвращает идентификатор выбранного пользователя}
  function GetUserIndexById(id: LongInt): LongInt;
{возвращает индекс параметром идентификатора}
  procedure Cancel;
{Отменна сканирования отпечатков}
  function Enroll(timeout: LongWord; var engineStatus: TNffvStatus): TNffvUser;
{Получение отпечатка }
  function Verify(user: TNffvUser; timeout: LongWord; var engineStatus: TNffvStatus): LongInt;
{Сравнение пользователей}
  function GetQualityThreshold: Byte;
{Порог качества изображения}
  procedure SetQualityThreshold(threshold: Byte);
{Выставляем порог качества}
  function GetMatchingThreshold: LongInt;
{Устанавливаем минимальное значение соответствия схожести}
  procedure SetMatchingThreshold(threshold: LongInt);
{Минимальное значение схожести отпечатков}

  end;

  function GetAvailableScannerModules(): String;
{Обьявление модулей сканера}
  function NffvGetInfo(): TNLibraryInfo;
{обьявление Nffv библиотеки}
  function EngineStatusString(status: TNffvStatus): string;
{Строковое сообщение о TNffv статусе аппарата}
  procedure NffvFreeMemory(point: PChar); stdcall; external dllName;
{высвобождаем память созданную в работе движка}
Рассмотрим модуль NffvUser.pas, содержащий класс TNffvUser для работы с пользователем (листинг 3):

Листинг 3.
Код:
type
  TNffvUser = class
  private
  _handle: Pointer;

  public
  Constructor Create(handle: Pointer);
{Создаём новый экземпляр TNffvUser}

  property Handle: Pointer read _handle;
{метод  хэндла}

  function GetId(): LongInt;
{Получаем идентификатор пользователя}
  function GetImage(): TBitmap;
{Получаем изображение отпечатка пальца}
Рассмотрим модуль UserList.pas. Основное назначение модуля взаимодействия со стандартной базой данных (листинг 4):

Листинг 4.
Код:
type

  TUser = class
{класс для работы с пользователями}
  Public
  UserName: string; {имя пользователя}
  UserID: LongInt; {идентификатор пользователя}
  constructor Create(const Name   : String;
{конструктор класса}
  const ID : Integer);
{идентификатор пользователя}
  end;
Рассмотрим класс, отображающий процедуры и функции, для работы с пользователями является TUser = class (листинг 5):

Листинг 5.
Код:
TUserDatabase = class(TList)
{класс для работы со стандартной базой данных}
  private
  _databaseName: String;{привязка ini файла к базе данных}
  public
  procedure Save;
{процедура сохранения ланных пользователя}
  function GetById(id: LongInt): TUser;
{получение идентификатора}

  Constructor Create(databaseName: string);
{конструктор класса}
  Destructor  Destroy; override;
{деструктор класса}
  end;
В модуле Util.pas, рассматривается: исполнение программы, возникновение ошибки, определение рабочей платформы из под которой происходит запуск программы и взаимодействие с минуцией (листинг 6):

Листинг 6.
Код:
type
TNLibraryInfo = record
{запись о разработчиках SDK}
  Title: array[0..63] of Char;{экспорт названия}
  Product: array[0..63] of Char;{продукт}
  Company: array[0..63] of Char;{компания}
  Copyright: array[0..63] of Char;{авторское право}
  VersionMajor: Integer;{главная версия}
  VersionMinor: Integer;{порядковая версия}
  VersionBuild: Integer;{версия сборки}
  VersionRevision: Integer;{версия доработки}
  DistributorId: Integer;{идентификатор дистрибьютора }
  SerialNumber: Integer;{серийный номер}
end;

  function Succeeded(Res: Integer): Boolean;
{функция вызываемая при успешном выполнении работы программы}
  function Failed(Res: Integer): Boolean;
{функция вызываемая при выполнении //неудачного сканирования}
  procedure RaiseError(msg: String; Err: Integer); overload;
{процедура исполняемая при возникновении ошибки}
  procedure RaiseError(msg: String); overload;
{процедура исполняемая при возникновении ошибки}
  function GetOS: String;
{функция получения рабочей платформы}
  function MatchingThresholdToString(value: Integer): string;
{перевод значения минуции в строковый параметр}
  function MatchingThresholdFromString(value: string): Integer;
{вызов параметра минуции из строки}
Рассмотрим основной функционал, который будет использован в собственном программном обеспечении. Переменная Engine, класса TNffv, заключает в себе работу базового класса отображения процедур и функций, с которыми взаимодействует программа (листинг 7):

Функция Failed выдаёт ошибку, в случае если Res < 0

Листинг 7.
Код:
function Failed(Res: Integer): Boolean;
begin
  Result := Res < 0;
end;
Функция GetAvailableScannerModules, класса TNffv, получает доступ к модулям сканера(листинг 8):

Листинг 8.
Код:
function GetAvailableScannerModules(): String;
var res: Integer;{}
  str: PChar;
  str2: String;
  resultString: String;
begin
  res := NffvGetAvailableScannerModulesA(str);
{в переменную res записываем строковый параметр срабатывания сканера}
  str2 := string(str);
{переводим значение указателя в строковый параметр}
  resultString := str2;
{в результирующую строку записываем строку с значением параметра}
  if (Failed(res)) then
  begin
    RaiseError('невозможно получить доступ к модулям сканера.', res);
  end;
{обработка ошибки}
  Result := resultString;
  NffvFreeMemory(str);
  end;
В случае возникновения ошибки при обращении к данной функции выводится сообщение об ошибке «невозможно получить доступ к модулям сканера».
Для того чтобы подключить сканнер Futronic Fs80, прописываем код(листинг 9):

Листинг 9.
Код:
Engine := TNffv.Create('fingers.db', '', 'Futronic');
Создается новый экземпляр класса TNffv от названия базы без пароля с выбранным сканером.
Engine.RemoveUsers чистка стандартной базы данных приведена процедурой RemoveUsers(листинг 10):

Листинг 10.
Код:
procedure TNffv.RemoveUsers;
  var res: Integer;
begin
  res := NffvClearUsers();
{переменной присваиваем обнуление базы данных}
  if (Failed(res)) then
  begin
    RaiseError('удаление пользователей невозможно.', res);
  end;
{при возникновении ошибки выводится сообщение «удаление пользователей невозможно»}
end;
NffvClearUsers – функция очистки базы данных импортируемая из библиотеки разработчика SDK.Сканирование отпечатка произведено функцией добавления пользователя с параметром ожидания сканера в 2 секунды и статусом добавления пользователя(листинг 11):

Листинг 11.
Код:
_user := Engine.Enroll(2000, _engineStatus);
Функция добавления пользователя TNffv.Enroll(листинг 12):

Листинг 12.
Код:
function TNffv.Enroll(timeout: Cardinal; var engineStatus: TNffvStatus): TNffvUser;
  var res: Integer;
      engStatus: Integer;
      handle: Pointer;
begin
  res := NffvEnroll(timeout, engStatus, handle);
{значение переменной рассчитано из времени, значения статуса сканирования, и значения хэндла}
  if (Failed(res)) then
  begin
    RaiseError(' добавление пользователя невозможно.', res);
  end;
{при возникновении ошибки выводится сообщение «добавление пользователя невозможно»}
  engineStatus := TNffvStatus(engStatus);
{значение статуса = числовому значению состояния сканирования}
  if (engineStatus = nfesTemplateCreated) then
{если числовое значение статуса = значению созданного шаблона }
  begin
    Result := TNffvUser.Create(handle);
{создаём пользователя по его хэндлу}
  end
  else
    Result := nil;
{иначе в результат записывается нулевое значение}
end;
_user.GetImage получение картинки отпечатка пальца функцией GetImage(листинг 13):

Листинг 13.
Код:
function TNffvUser.GetImage: TBitmap;
var res: Integer;
    nBitmap: TBitmap;
    pBitmap: HBitmap;
begin
  res := NffvUserGetHBitmap(_handle, pBitmap);
{получаем числовое значение картинки от _handle и pBitmap}
  if (Failed(res)) then
  begin
    RaiseError('получить изображение невозможно.', res);
{при возникновении ошибки выводится сообщение «получить изображение невозможно»}
  end;
  nBitmap := TBitmap.Create;
  nBitmap.Handle := pBitmap;
  Result := nBitmap;
end;
Картинка получается из функции NffvUserGetHBitmap, экспортируемой из библиотеки разработчика. В приведенных выше листингах отражен основной функционал корректной работы со сканером fs80. Софтина получилась довольно таки простая, использовал кнопку(t.Button) - для получения скана отпечатка и поле ввода текста(t.Edit) – для ввоода названия скана.

И непосредственно сам обработчик.

Листинг 14.
Код:
procedure TForm2.Button1Click(Sender: TObject);
begin
  Engine :=  nil;
  _allModuleString := GetAvailableScannerModules;
  try
  Engine := TNffv.Create('fingers.db', '', 'Futronic'); //Подключаем наш //сканер
  Engine.RemoveUsers;                                 //Чистим базу
  _user := Engine.Enroll(2000, _engineStatus);       //Сканируем //отпечаток
  if (_engineStatus = nfesTemplateCreated) then         //Если //сосканировался делаем дальше
  begin
   Bitmap := _user.GetImage;          //Получаем картинку и пишем ее в //имадж
   randomize;
   bitmap.SaveToFile(Edit1.Text); //сохраняем ее в папке с проэктом с //именем пользователя
   Engine.RemoveUsers;
   FreeAndNil(Engine); //очищаем память движка
   ShowMessage(‘… Done’);
  end
  else {какой error}  ;
except
  MessageDlg(‘невозможно запустить сканер или создать/загрузить базу данных.’ + #13#10 +
       ‘пожалуйста проверьте:’ + #13#10 + ‘ – правильно ли введён пароль;’  + #13#10 + ‘ – правильность названия базы данных;’ +  #13#10 +‘ – правильно ли подключен сканер.’, mtError, [mbOK], 0);
  FreeAndNil(Engine);
  Exit;
end;
end;
С моей точки зрения софтина проста и от части уникальна потому, что получение информации производится перехватом получаемого изображения на стадии обработки данных стандартного функционала программы. Судите строго или матом ругайтесь –ваше право, потому как заниматься разработкой с 0 – не было времени, но костыль решил проблему. К сожалению сверку с полученным сканом не предоставлю, потому как инфа на другом винте, который сдох.

Рассмотреть типовые решения применения сканера отпечатков пальцев;

Типовыми решениями могут быть: реализация многофакторной аутентификации, доступ к информации\ресурсу, физический доступ, интеграция со сторонней б\д для поиска информации о человеке, и тд. Забыл добавить, драйвера для корректной работы fs80 с помощью самописной софтины либо SDK подходят не все, надо экспериментировать, какие-то находил рабочие.

Если у кого будут вопросы консультационного характера, с радостью отвечу на все вопросы.
 
Последнее редактирование модератором:

Vander

CodebyTeam
Gold Team
16.01.2016
1 420
4 353
BIT
2
Впервые, на форуме тема подобного рода, надеюсь вникнуть, а там и вопросы появятся:)
 

just user

New member
25.09.2020
2
0
BIT
0
А почему отпечаток руки менее уникальный, чем отпечаток пальца?
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!