Development over
This commit is contained in:
450
docs/API.md
Normal file
450
docs/API.md
Normal file
@@ -0,0 +1,450 @@
|
||||
# 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](#architecture-overview)
|
||||
- [Security Model](#security-model)
|
||||
- [Authentication Flow](#authentication-flow)
|
||||
- [Crate Structure](#crate-structure)
|
||||
- [Key APIs](#key-apis)
|
||||
- [Extension Points](#extension-points)
|
||||
- [Configuration](#configuration)
|
||||
- [IPC Protocol](#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.
|
||||
|
||||
```rust
|
||||
// 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.
|
||||
|
||||
```rust
|
||||
// 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
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
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:
|
||||
|
||||
```rust
|
||||
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:
|
||||
|
||||
```rust
|
||||
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:
|
||||
|
||||
```rust
|
||||
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`:
|
||||
|
||||
```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
|
||||
|
||||
```json
|
||||
{"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
|
||||
|
||||
```json
|
||||
{
|
||||
"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`:
|
||||
|
||||
```rust
|
||||
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:
|
||||
|
||||
```bash
|
||||
cargo doc --workspace --no-deps --open
|
||||
```
|
||||
|
||||
Documentation is generated at `target/doc/linux_hello_daemon/index.html`.
|
||||
|
||||
## See Also
|
||||
|
||||
- [README.md](../README.md) - Project overview and quick start
|
||||
- [BENCHMARKS.md](BENCHMARKS.md) - Performance benchmarks
|
||||
- Source code documentation: `cargo doc --open`
|
||||
Reference in New Issue
Block a user