#security-key #yubi-key #encryption #configuration #encryption-key

challenge_response

Perform HMAC-SHA1 and OTP challenges with YubiKey, OnlyKey and NitroKey, in pure Rust

47 releases (5 breaking)

Uses old Rust 2015

0.5.28 Sep 13, 2024
0.5.24 Aug 31, 2024
0.5.13 Jul 3, 2024
0.5.8 Feb 25, 2024

#138 in Authentication

Download history 162/week @ 2024-07-30 77/week @ 2024-08-06 552/week @ 2024-08-13 426/week @ 2024-08-20 1161/week @ 2024-08-27 585/week @ 2024-09-03 495/week @ 2024-09-10 179/week @ 2024-09-17 185/week @ 2024-09-24 351/week @ 2024-10-01 170/week @ 2024-10-08 153/week @ 2024-10-15 158/week @ 2024-10-22 145/week @ 2024-10-29 129/week @ 2024-11-05 108/week @ 2024-11-12

574 downloads per month
Used in 2 crates

MIT/Apache

51KB
1K SLoC

challenge-response

Latest Version Documentation Build Status Dependency Status MIT licensed Apache-2.0 licensed

challenge-response is a Rust library for performing challenge-response operations (hashing and encryption) using security keys like the YubiKey and the OnlyKey.

Current features

Supported devices

  • YubiKey 2.2 and later
  • OnlyKey (untested)
  • NitroKey (untested)

Usage

Add this to your Cargo.toml

[dependencies]
challenge_response = "0"

nusb backend (EXPERIMENTAL)

You can enable the experimental nusb backend by adding the following to your Cargo.toml manifest:

[dependencies]
challenge_response = { version = "0", default-features = false, features = ["nusb"] }

The nusb backend has the advantage of not depending on libusb, thus making it easier to add challenge_response to your dependencies.

Perform a Challenge-Response (HMAC-SHA1 mode)

If you are using a YubiKey, you can configure the HMAC-SHA1 Challenge-Response with the Yubikey Personalization GUI.

extern crate challenge_response;
extern crate hex;

use challenge_response::config::{Config, Mode, Slot};
use challenge_response::ChallengeResponse;
use std::ops::Deref;

fn main() {
    let mut cr_client = match ChallengeResponse::new() {
        Ok(c) => c,
        Err(e) => {
            eprintln!("{}", e.to_string());
            return;
        }
    };

    let device = match cr_client.find_device() {
        Ok(d) => d,
        Err(e) => {
            eprintln!("Device not found: {}", e.to_string());
            return;
        }
    };

    println!(
        "Vendor ID: {:?} Product ID {:?}",
        device.vendor_id, device.product_id
    );

    let config = Config::new_from(device)
        .set_variable_size(true)
        .set_mode(Mode::Sha1)
        .set_slot(Slot::Slot2);

    // Challenge can not be greater than 64 bytes
    let challenge = String::from("mychallenge");
    // In HMAC Mode, the result will always be the
    // SAME for the SAME provided challenge
    let hmac_result = cr_client
        .challenge_response_hmac(challenge.as_bytes(), config)
        .unwrap();

    // Just for debug, lets check the hex
    let v: &[u8] = hmac_result.deref();
    let hex_string = hex::encode(v);

    println!("{}", hex_string);
}

Configure Yubikey (HMAC-SHA1 mode)

Note, please read about the initial configuration Alternatively you can configure the yubikey with the official Yubikey Personalization GUI.

extern crate challenge_response;
extern crate rand;

use challenge_response::config::{Command, Config};
use challenge_response::configure::DeviceModeConfig;
use challenge_response::hmacmode::{
    HmacKey, HmacSecret, HMAC_SECRET_SIZE,
};
use challenge_response::ChallengeResponse;
use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};

fn main() {
    let mut cr_client = match ChallengeResponse::new() {
        Ok(y) => y,
        Err(e) => {
            eprintln!("{}", e.to_string());
            return;
        }
    };

    let device = match cr_client.find_device() {
        Ok(d) => d,
        Err(e) => {
            eprintln!("Device not found: {}", e.to_string());
            return;
        }
    };

    println!(
        "Vendor ID: {:?} Product ID {:?}",
        device.vendor_id, device.product_id
    );

    let config = Config::new_from(device)
        .set_command(Command::Configuration2);

    let mut rng = thread_rng();

    // Used rand here, but you can set your own secret:
    // let secret: &HmacSecret = b"my_awesome_secret_20";
    let secret: Vec<u8> = rng
        .sample_iter(&Alphanumeric)
        .take(HMAC_SECRET_SIZE)
        .collect();
    let hmac_key: HmacKey = HmacKey::from_slice(&secret);

    let mut device_config = DeviceModeConfig::default();
    device_config.challenge_response_hmac(&hmac_key, false, false);

    if let Err(err) =
        cr_client.write_config(config, &mut device_config)
    {
        println!("{:?}", err);
    } else {
        println!("Device configured");
    }
}

Credits

This library was originally a fork of the yubico_manager library.

License

MIT or Apache-2.0

Dependencies

~2–11MB
~142K SLoC