#sed #nvme #opal #security

bin+lib sed-key

Tool + library for controlling NVMe SED/OPAL lock states on Linux

5 releases

Uses new Rust 2024

new 0.1.5 Nov 12, 2025
0.1.4 Oct 20, 2025
0.1.2 Oct 14, 2025
0.1.1 Sep 22, 2025
0.1.0 Sep 22, 2025

#372 in Hardware support

Download history 156/week @ 2025-09-17 71/week @ 2025-09-24 28/week @ 2025-10-01 127/week @ 2025-10-08 145/week @ 2025-10-15 28/week @ 2025-10-22

302 downloads per month

MIT license

52KB
1K SLoC

sed-key

Crates.io

sed-key is a Rust command-line tool and reusable library for locking, unlocking, and querying the lock state of NVMe Self-Encrypting Drives (SED) using the TCG OPAL protocol under Linux.

It’s intentionally minimal — ideal for early-boot or recovery environments — and supports both direct CLI use and programmatic invocation from other Rust code.

It wraps the Linux ioctls for OPAL discovery and lock/unlock, providing:

  • Discovery: Check whether a drive supports OPAL/SED and parse the locking feature descriptor.
  • Locking/Unlocking: Send the OPAL_LOCK_UNLOCK command with your Admin1 password.
  • CLI: A sed-key binary to view lock status or unlock drives interactively.
  • Library API: Call do_lock, do_unlock, or do_status directly from your own code.
  • Mock Backend: Built-in simulator for hardware-free testing.
  • Feature-Gated Real Hardware Tests: Enable --features real-hardware for integration on test drives.

⚠️ Safety Warning

This software talks directly to your block devices using raw IOCTLs.
Mistakes can lock you out of your drive, or even crash a running kernel. You run this at your own risk.


Installation

With Cargo:

cargo install sed-key

CLI Usage

Check lock status of a device

sudo sed-key status /dev/nvme0n1

This prints the parsed OPAL locking feature flags and whether the device is locked.

Unlock a device

Pass the device path and optionally a password argument:

sudo sed-key unlock /dev/nvme0n1 mypassword

Lock a device again

Similarly, to lock the device:

sudo sed-key lock /dev/nvme0n1 mypassword

Noninteractive / scripting

All commands exit with nonzero on error so you can use them in shell scripts:

# Example: unlock with key from a file if the drive reports locked
if sudo sed-key status /dev/nvme0n1 | grep -q "LOCKED"; then
  sudo sed-key unlock /dev/nvme0n1 "$(cat /etc/keys/nvme0n1.key)"
fi

# Or perhaps:

# Use sed-key directly; password piped on stdin
if ! echo -n "$PW" | sed-key unlock "$dev" -; then
  rc=$?
  echo "ERROR: unlock failed for $dev (rc=$rc)" >&2
  exit $rc
fi

Testing

All tests run safely without touching hardware by default:

cargo test

Property-based tests and regression corpus ensure deterministic runs.

For real hardware tests, explicitly enable:

cargo test --features real-hardware -- --ignored

Required environment:

export SED_KEY_TEST_DEV=/dev/nvme1
export SED_KEY_TEST_PW=mysecret

Never run these on a mounted or production drive.

When running under Miri or in CI, hardware IOCTLs are replaced by a fabricated discovery page. Example:

MIRI_SED_LOCKED=1 cargo miri run -- status /dev/nvme0n1

This lets the parser and property-based tests run without touching real drives.

Building From Source

Using Cargo (standard build)

If you have Rust installed, you can build and run directly:

git clone https://github.com/daveman1010221/sed-key.git
cd sed-key
cargo build --release

Using Nix (reproducible build)

If you have Nix installed with flakes enabled:

git clone https://github.com/daveman1010221/sed-key.git
cd sed-key
nix build .#default

This Nix build performs a fully offline, reproducible release build of sed-key.

🧩 Library Integration Example

use sed_key::{do_status, do_unlock, use_mock_backend};

fn main() -> anyhow::Result<()> {
    use_mock_backend();
    do_unlock("/dev/nvme0".into(), Some("pw".into()))?;
    do_status("/dev/nvme0".into())?;
    Ok(())
}

This allows scripting or testing drive control directly from Rust code.

License

Licensed under MIT.

Dependencies

~4.5–9.5MB
~205K SLoC