Files
Linux-Hello/docs/API.md
2026-01-15 22:50:18 +01:00

16 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

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"]
}

D-Bus API

The daemon exposes a D-Bus interface for desktop integration.

Service Information

Property Value
Bus System bus
Service Name org.linuxhello.Daemon
Object Path /org/linuxhello/Manager
Interface org.linuxhello.Manager

Methods

<!-- Authenticate a user -->
<method name="Authenticate">
  <arg name="user" type="s" direction="in"/>
  <arg name="success" type="b" direction="out"/>
  <arg name="confidence" type="d" direction="out"/>
  <arg name="message" type="s" direction="out"/>
</method>

<!-- Start enrollment -->
<method name="EnrollStart">
  <arg name="user" type="s" direction="in"/>
  <arg name="label" type="s" direction="in"/>
  <arg name="frame_count" type="u" direction="in"/>
  <arg name="success" type="b" direction="out"/>
</method>

<!-- Cancel enrollment -->
<method name="EnrollCancel">
  <arg name="success" type="b" direction="out"/>
</method>

<!-- List templates for user -->
<method name="ListTemplates">
  <arg name="user" type="s" direction="in"/>
  <arg name="templates" type="as" direction="out"/>
</method>

<!-- Remove a template -->
<method name="RemoveTemplate">
  <arg name="user" type="s" direction="in"/>
  <arg name="label" type="s" direction="in"/>
  <arg name="success" type="b" direction="out"/>
</method>

<!-- Get system status -->
<method name="GetSystemStatus">
  <arg name="camera_available" type="b" direction="out"/>
  <arg name="tpm_available" type="b" direction="out"/>
  <arg name="anti_spoofing_enabled" type="b" direction="out"/>
  <arg name="enrolled_count" type="u" direction="out"/>
</method>

Properties

<property name="Version" type="s" access="read"/>
<property name="CameraAvailable" type="b" access="read"/>
<property name="TpmAvailable" type="b" access="read"/>
<property name="AntiSpoofingEnabled" type="b" access="read"/>

Signals

<!-- Enrollment progress -->
<signal name="EnrollmentProgress">
  <arg name="frames_captured" type="u"/>
  <arg name="frames_total" type="u"/>
  <arg name="status" type="s"/>
</signal>

<!-- Enrollment complete -->
<signal name="EnrollmentComplete">
  <arg name="success" type="b"/>
  <arg name="message" type="s"/>
</signal>

D-Bus Client Example (Rust with zbus)

use zbus::{Connection, proxy};

#[proxy(
    interface = "org.linuxhello.Manager",
    default_service = "org.linuxhello.Daemon",
    default_path = "/org/linuxhello/Manager"
)]
trait LinuxHelloManager {
    async fn authenticate(&self, user: &str) -> zbus::Result<(bool, f64, String)>;
    async fn list_templates(&self, user: &str) -> zbus::Result<Vec<String>>;
}

async fn authenticate_user() -> zbus::Result<()> {
    let connection = Connection::system().await?;
    let proxy = LinuxHelloManagerProxy::new(&connection).await?;

    let (success, confidence, message) = proxy.authenticate("alice").await?;
    println!("Auth: {} ({}): {}", success, confidence, message);
    Ok(())
}

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