Um leitor de impressões digitais

Há qualquer coisa de particularmente interessante em encontrar um periférico antigo e, em vez de simplesmente tentar fazê-lo funcionar, perguntar: o que será que este objeto ainda consegue fazer?

Achei no lixo, esses dias, um pequeno leitor de impressões digitais da Microsoft. Nem sei dizer que grande utilidade prática esse objeto ainda tem hoje.

Através de buscas na internet descobri que um sensor desses utiliza os princípios da luz e da refração interna para capturar o desenho das cristas e valas do dedo. Quando o dedo toca a superfície de vidro, as áreas de contato direto (cristas) alteram o caminho da luz por reflexão frustrada, enquanto os espaços vazios (valas) refletem a luz de maneira diferente, permitindo que um sensor crie uma imagem em alto contraste. Além disso um sensor de proximidade permite ao dispositivo saber quando realizar a captura da imagem.

Liguei-o ao meu HP xw4600, que tem sido uma espécie de bancada de experiências para estas coisas, e fui ver o que o Linux tinha a dizer sobre ele. A primeira resposta veio do lsusb:

Bus 005 Device 002: ID 045e:00bd Microsoft Corp. Fingerprint Reader

O dispositivo estava vivo. O passo seguinte foi olhar com um pouco mais de atenção para o dispositivo:

lsusb -v -d 045e:00bd

O resultado mostrou um dispositivo USB 2.0 a funcionar a Full Speed, 12 Mbps. Não havia ali uma interface genérica de scanner ou de câmara que pudesse ser simplesmente aberta por um programa qualquer. A interface era:

bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol

Ou seja, o leitor não se apresentava ao computador como uma simples fonte de imagens. Havia alguma coisa entre o sensor e o sistema operativo que teria de saber falar a língua daquele aparelho.

Tenho instalado no MX Linux o libfprint, uma biblioteca open source para leitores de impressões digitais. Ao experimentar:

fprintd-list "$USER"

o sistema respondeu:

found 1 devices
Device at /net/reactivated/Fprint/Device/0
Using device /net/reactivated/Fprint/Device/0
User guilherme has no fingers enrolled for Digital Persona U.are.U 4000/4000B/4500.

O leitor Microsoft é um Digital Persona U.are.U 4000/4000B/4500.

A utilização habitual do libfprint é bastante clara: cadastrar uma impressão digital e depois utilizá-la para autenticação. Experimentei:

fprintd-enroll "$USER"

O sistema pediu um dedo. Coloquei-o sobre o leitor. E apareceu:

Enrolling right-index-finger finger.
Enroll result: enroll-stage-passed

Funcionava. Mas, naquele momento, a minha curiosidade já era outra. Se o leitor consegue capturar uma impressão digital, será que consigo simplesmente obter a imagem? Queria chegar um pouco mais perto daquilo que o aparelho efetivamente produz.

O fprintd é uma interface relativamente confortável para utilizar leitores de impressões digitais. Para este experimento, porém, era interessante descer um nível e conversar diretamente com o libfprint. Instalei os headers de desenvolvimento e comecei a consultar a API disponível no sistema. Os próprios headers instalados no sistema mostraram o caminho. O arquivo fp-image.h tinha a possibilidade de acessar diretamente um FpImage. A função que me interessava acabou sendo:

fp_device_capture_sync()

Ela permite pedir ao dispositivo uma captura e receber de volta um FpImage. Escrevi um pequeno programa em C que abre o dispositivo, espera pelo dedo, captura uma imagem e grava os dados como um arquivo PGM. O PGM é um formato extremamente simples para imagens em tons de cinza, já falamos dele aqui no blog.

O programa começou por ser executado normalmente:

./capture_fingerprint

Mas o Linux respondeu:

libusb: error [get_usbfs_fd] libusb couldn't open USB device
libusb: error [get_usbfs_fd] libusb requires write access to USB device nodes
Could not open device: USB error on device 045e:00bd : Access denied

Mais uma camada do objeto aparecia. O fprintd conseguia utilizar o leitor, mas o meu pequeno programa não tinha permissão para abrir diretamente o dispositivo USB. Para confirmar que esse era o único problema, executei:

sudo ./capture_fingerprint

E então aconteceu.

Opening fingerprint reader...
Place your finger on the reader...
Capture successful!
Image size: 384 x 290
Image data: 111360 bytes
Saved: finger_001.pgm

O arquivo finger_001.pgm tinha acabado de transformar aquilo que, alguns minutos antes, era apenas um dispositivo USB identificado como 045e:00bd numa coisa muito mais concreta: um conjunto de pixels que podia ser guardado, aberto e analisado.

Abri o arquivo no GIMP.

Depois de confirmar que a captura funcionava, fiz uma pequena alteração no programa. Em vez de sempre gravar:

finger_001.pgm

queria que cada captura tivesse a data e a hora. Passei a usar nomes como:

finger_2026-08-12_11-00-43.pgm

Assim evita que uma nova captura simplesmente destrua a anterior. E também não queria terminar com um programa que precisasse ser executado como root. A solução foi criar uma regra udev:

SUBSYSTEM=="usb", ATTR{idVendor}=="045e", ATTR{idProduct}=="00bd", MODE="0660", GROUP="plugdev"

O meu utilizador já fazia parte do grupo plugdev. Depois de recarregar as regras e voltar a ligar o leitor, o dispositivo passou a aparecer com permissões:

crw-rw---- 1 root plugdev ...

E finalmente:

./capture_fingerprint

Ainda preciso ver o que cria aquele retângulo escuro no centro da imagem, talvez o leitor já tenha passado dias melhores… O que o programa faz simplesmente é receber um FpImage fornecido pelo libfprint. O driver pode fazer algum processamento, normalização ou outra transformação antes de entregar essa imagem à aplicação, isso eu já não sei.

Bom, não se trata apenas de fazer um aparelho antigo funcionar. Trata-se de descobrir as camadas que normalmente não vemos: identificação USB, driver, biblioteca, API, permissões, imagem, formato de arquivo. Cada camada que se torna compreensível reduz um pouco a opacidade do objeto.

Uma das coisas que mais gosto nestas experiências com tecnologia descartada: muitas vezes não sabemos exatamente onde vamos chegar quando pegamos num objeto.

O programinha e a regra udev estão disponíveis aqui: https://github.com/refotografia/Microsoft-Fingerprint-Reader-Thing