14 KiB
Linux Hello API Documentation
This document provides a high-level overview of the Linux Hello API for developers who want to integrate with, extend, or understand the facial authentication system.
Table of Contents
- Architecture Overview
- Security Model
- Authentication Flow
- Crate Structure
- Key APIs
- Extension Points
- Configuration
- IPC Protocol
Architecture Overview
Linux Hello uses a pipeline architecture for facial authentication:
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Authentication Pipeline │
├─────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌───────────┐ ┌─────────────┐ ┌───────────┐ ┌──────────┐ │
│ │ Camera │──▶│ Face │──▶│ Anti- │──▶│ Embedding │──▶│ Template │ │
│ │ Capture │ │ Detection │ │ Spoofing │ │Extraction │ │ Matching │ │
│ └──────────┘ └───────────┘ └─────────────┘ └───────────┘ └──────────┘ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ ▼ │
│ camera/ detection/ anti_spoofing/ embedding/ matching/ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
Components
| Component | Purpose | Module |
|---|---|---|
| Camera Capture | Acquire IR frames from webcam | camera |
| Face Detection | Locate faces in frames | detection |
| Anti-Spoofing | Verify liveness (prevent photos/videos) | anti_spoofing |
| Embedding Extraction | Generate face feature vector | embedding |
| Template Matching | Compare against enrolled templates | matching |
Security Model
Linux Hello implements defense-in-depth security:
Layer 1: Hardware Security
- IR Camera Requirement: Only infrared cameras are accepted
- TPM Integration: Templates encrypted with hardware-bound keys
- PCR Binding: Optional boot configuration verification
Layer 2: Biometric Security
- Anti-Spoofing: Multiple liveness detection methods
- IR reflection analysis
- Depth estimation
- Texture analysis (LBP)
- Blink detection
- Micro-movement tracking
Layer 3: Data Security
- Encrypted Storage: AES-256-GCM for templates at rest
- Secure Memory: Sensitive data zeroized on drop
- Memory Locking: Prevents swapping to disk
Layer 4: Access Control
- IPC Authorization: Peer credential verification
- Rate Limiting: Prevents brute-force attacks
- Permission Checks: Users can only manage their own templates
Authentication Flow
┌──────────────────────────────────────────────────────────────────────────────┐
│ Authentication Sequence │
└──────────────────────────────────────────────────────────────────────────────┘
PAM Module Daemon Storage
│ │ │
│ 1. Authenticate(user) │ │
│───────────────────────▶│ │
│ │ │
│ │ 2. Load templates │
│ │─────────────────────────▶│
│ │ │
│ │ 3. Capture frame │
│ │ ◄──── IR Camera │
│ │ │
│ │ 4. Detect face │
│ │ 5. Anti-spoofing check │
│ │ 6. Extract embedding │
│ │ 7. Match templates │
│ │ │
│ 8. Auth result │ │
│◄───────────────────────│ │
│ │ │
Crate Structure
linux-hello-common
Shared types and utilities used by all components.
// Key exports
use linux_hello_common::{
Config, // System configuration
Error, Result, // Error handling
FaceTemplate, // Template data structure
TemplateStore, // File-based storage
};
linux-hello-daemon
Core authentication functionality and services.
// Camera access
use linux_hello_daemon::{
enumerate_cameras, // List available cameras
Camera, // Camera control
CameraInfo, // Camera metadata
Frame, PixelFormat, // Frame data
};
// Face processing
use linux_hello_daemon::{
FaceDetection, FaceDetect, // Detection types
EmbeddingExtractor, // Embedding trait
cosine_similarity, // Distance metrics
match_template, MatchResult, // Matching
};
// Security
use linux_hello_daemon::{
AntiSpoofingDetector, LivenessResult, // Anti-spoofing
SecureEmbedding, SecureBytes, // Secure memory
TpmStorage, SoftwareTpmFallback, // Encryption
};
// IPC
use linux_hello_daemon::{
IpcServer, IpcClient, // Server/client
IpcRequest, IpcResponse, // Messages
};
Key APIs
Camera API
use linux_hello_daemon::{enumerate_cameras, Camera, Frame};
// Find IR camera
let cameras = enumerate_cameras()?;
let ir_camera = cameras.iter()
.find(|c| c.is_ir)
.ok_or("No IR camera found")?;
// Capture frames
let mut camera = Camera::open(&ir_camera.device_path)?;
camera.start()?;
let frame: Frame = camera.capture_frame()?;
Face Detection API
use linux_hello_daemon::{FaceDetect, SimpleFaceDetector, FaceDetection};
// Create detector
let detector = SimpleFaceDetector::new(0.5); // confidence threshold
// Detect faces
let detections: Vec<FaceDetection> = detector.detect(
&frame.data,
frame.width,
frame.height
)?;
// Convert to pixel coordinates
if let Some(face) = detections.first() {
let (x, y, w, h) = face.to_pixels(frame.width, frame.height);
}
Embedding API
use linux_hello_daemon::{
EmbeddingExtractor, PlaceholderEmbeddingExtractor,
cosine_similarity, euclidean_distance, similarity_to_distance,
};
use image::GrayImage;
// Extract embedding
let extractor = PlaceholderEmbeddingExtractor::new(128);
let face_image = GrayImage::new(112, 112); // cropped face
let embedding: Vec<f32> = extractor.extract(&face_image)?;
// Compare embeddings
let similarity = cosine_similarity(&embedding1, &embedding2);
let distance = similarity_to_distance(similarity);
Template Matching API
use linux_hello_daemon::{match_template, MatchResult, average_embeddings};
use linux_hello_common::FaceTemplate;
// Match against stored templates
let result: MatchResult = match_template(
&probe_embedding,
&stored_templates,
0.6 // distance threshold
);
if result.matched {
println!("Match found: {:?}", result.matched_label);
}
// Create averaged template for enrollment
let avg_embedding = average_embeddings(&multiple_embeddings)?;
Anti-Spoofing API
use linux_hello_daemon::anti_spoofing::{
AntiSpoofingDetector, AntiSpoofingConfig, AntiSpoofingFrame, LivenessResult
};
let config = AntiSpoofingConfig::default();
let mut detector = AntiSpoofingDetector::new(config);
let frame = AntiSpoofingFrame {
pixels: frame_data,
width: 640,
height: 480,
is_ir: true,
face_bbox: Some((x, y, w, h)),
timestamp_ms: 0,
};
let result: LivenessResult = detector.check_frame(&frame)?;
if result.is_live {
// Proceed with authentication
}
Secure Memory API
use linux_hello_daemon::{SecureEmbedding, SecureBytes};
// Automatically zeroized on drop
let secure_emb = SecureEmbedding::new(embedding);
// Constant-time comparison
let bytes1 = SecureBytes::new(data1);
let bytes2 = SecureBytes::new(data2);
let equal = bytes1.constant_time_eq(&bytes2);
IPC API
use linux_hello_daemon::ipc::{IpcClient, IpcServer, IpcRequest, IpcResponse};
// Client usage
let client = IpcClient::default();
let response = client.authenticate("username").await?;
if response.success {
println!("Authenticated!");
}
// Server setup
let mut server = IpcServer::new("/run/linux-hello/auth.sock");
server.set_auth_handler(|user| async move {
// Perform authentication
Ok(true)
});
server.start().await?;
Extension Points
Custom Face Detector
Implement the FaceDetect trait:
use linux_hello_daemon::{FaceDetect, FaceDetection};
use linux_hello_common::Result;
struct MyDetector { /* ... */ }
impl FaceDetect for MyDetector {
fn detect(&self, image_data: &[u8], width: u32, height: u32)
-> Result<Vec<FaceDetection>>
{
// Custom detection logic
Ok(vec![])
}
}
Custom Embedding Extractor
Implement the EmbeddingExtractor trait:
use linux_hello_daemon::EmbeddingExtractor;
use linux_hello_common::Result;
use image::GrayImage;
struct MyExtractor { /* ... */ }
impl EmbeddingExtractor for MyExtractor {
fn extract(&self, face_image: &GrayImage) -> Result<Vec<f32>> {
// Custom embedding extraction
Ok(vec![])
}
}
Custom TPM Storage
Implement the TpmStorage trait:
use linux_hello_daemon::tpm::{TpmStorage, EncryptedTemplate};
use linux_hello_common::Result;
struct MyStorage { /* ... */ }
impl TpmStorage for MyStorage {
fn is_available(&self) -> bool { true }
fn initialize(&mut self) -> Result<()> { Ok(()) }
fn encrypt(&self, user: &str, plaintext: &[u8]) -> Result<EncryptedTemplate> { /* ... */ }
fn decrypt(&self, user: &str, encrypted: &EncryptedTemplate) -> Result<Vec<u8>> { /* ... */ }
fn create_user_key(&mut self, user: &str) -> Result<()> { Ok(()) }
fn remove_user_key(&mut self, user: &str) -> Result<()> { Ok(()) }
}
Configuration
Configuration is stored in /etc/linux-hello/config.toml:
[general]
log_level = "info"
timeout_seconds = 5
[camera]
device = "auto" # or "/dev/video0"
ir_emitter = "auto"
resolution = [640, 480]
fps = 30
[detection]
model = "blazeface"
min_face_size = 80
confidence_threshold = 0.9
[embedding]
model = "mobilefacenet"
distance_threshold = 0.6
[anti_spoofing]
enabled = true
depth_check = true
liveness_model = true
temporal_check = true
min_score = 0.7
[tpm]
enabled = true
pcr_binding = false
IPC Protocol
The daemon communicates via Unix socket using JSON messages.
Socket Location
/run/linux-hello/auth.sock
Request Format
{"action": "authenticate", "user": "username"}
{"action": "enroll", "user": "username", "label": "default", "frame_count": 5}
{"action": "list", "user": "username"}
{"action": "remove", "user": "username", "label": "default"}
{"action": "ping"}
Response Format
{
"success": true,
"message": "Authentication successful",
"confidence": 0.95,
"templates": ["default", "backup"]
}
Error Handling
All operations return Result<T, Error> where Error is defined in linux_hello_common::Error:
use linux_hello_common::{Error, Result};
match operation() {
Ok(result) => { /* success */ }
Err(Error::NoCameraFound) => { /* no IR camera */ }
Err(Error::NoFaceDetected) => { /* face not visible */ }
Err(Error::AuthenticationFailed) => { /* no match */ }
Err(Error::UserNotEnrolled(user)) => { /* not enrolled */ }
Err(e) => { /* other error */ }
}
Building Documentation
Generate HTML documentation:
cargo doc --workspace --no-deps --open
Documentation is generated at target/doc/linux_hello_daemon/index.html.
See Also
- README.md - Project overview and quick start
- BENCHMARKS.md - Performance benchmarks
- Source code documentation:
cargo doc --open