enigmastick
Documentation menu
On this page

Documentation / Integration

Using Rust.

Open a device, send a typed request, and work with owned results.

Add the host library

The package name is enigma. While working from sibling checkouts, add a path dependency to your application’s Cargo.toml:

TOML
[dependencies]
enigma = { path = "../enigma-host" }

The current crate uses edition 2024 and a synchronous USB interface. It exposes Device, request/response types, and structured errors at the crate root.

Connect and list keys

Rust
use enigma::{Device, EnigmaError, KeyListFilter};

fn main() -> Result<(), EnigmaError> {
    let mut stick = Device::open()?;
    let status = stick.status()?;
    println!("Token: {:?}", status.token);
    println!("Session: {:?}", status.session);

    let keys = stick.list_keys(KeyListFilter::default())?;
    for key in keys.keys {
        println!("0x{:08X} {}", key.id, key.label);
    }

    stick.close()?;
    Ok(())
}

Device::open() selects a single matching device. Multiple candidates cause an error. Methods borrow the handle mutably so requests are made sequentially.

Sign with an existing key

This function accepts an existing signing-key ID and a PIN supplied by your application. Read the PIN with an appropriate hidden-input prompt; the core library does not prompt for you.

Rust
use enigma::{Device, EnigmaError, SessionState, SignRequest};

fn sign_message(
    stick: &mut Device,
    pin: &str,
    key_id: u32,
    message: &[u8],
) -> Result<Box<[u8]>, EnigmaError> {
    if stick.status()?.session != SessionState::Authenticated {
        stick.authenticate(pin)?;
    }

    let signed = stick.sign(SignRequest { key_id, message })?;
    Ok(signed.signature)
}

The response owns its signature bytes. The key type determines whether the firmware produces an RSA-PSS signature, an ECDSA signature, or an HMAC.

This example propagates errors to its caller. A session can expire after the status check, so the caller must still handle authentication-required responses. Explicitly lock the token at the end of your application’s workflow, including its error path.

Generate a key

Key creation uses a GenerateKeyRequest. Supply a compatible type, usage, size, label, and timestamp:

Rust
use enigma::{GenerateKeyRequest, KeyType, KeyUsage};

let request = GenerateKeyRequest {
    key_type: KeyType::Ec,
    key_usage: KeyUsage::Sign,
    key_size: 256,
    label: "example-signing-key",
    timestamp: 0, // Replace with your application's Unix timestamp.
};
// With an authenticated handle:
// let created = stick.generate_key(request)?;

Use the returned ID for later requests. Do not repeat key creation automatically after a timeout. The current library has a fixed 10-second transaction timeout; slow RSA generation may exceed it.

Handle structured errors

EnigmaError distinguishes USB errors, protocol errors, device errors, invalid arguments, and discovery failures. A device error includes a DeviceErrorCode and message. Branch on the enum when deciding what to do.

verify() currently verifies HMACs. To verify RSA or ECDSA signatures on the host, export the public key and use a compatible cryptography library.

Full reference

The Rust API reference lists the current public methods and types. See mechanisms for formats, key sizes, and limits.