YubiKey OTP Verification Library
A Rust library for working with YubiKey One-Time Passwords (OTP), including modhex encoding/decoding functionality.
Overview
The YubiKey OTP output is provided in the Modhex character set. The Modhex character set uses characters common across the majority of latin alphabet QWERTY keyboard layouts, allowing for functionality regardless of the language set.
Modhex Character Set
The modhex character set provides a direct substitution for hexadecimal characters:
| Hex | a |
b |
c |
d |
e |
f |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Modhex | l |
n |
r |
t |
u |
v |
c |
b |
d |
e |
f |
g |
h |
i |
j |
k |
Features
- Hex to Modhex conversion: Convert hexadecimal strings to modhex format
- Modhex to Hex conversion: Convert modhex strings back to hexadecimal
- Byte array support: Direct conversion between byte arrays and modhex
- OTP decryption: Full YubiKey OTP decryption with AES-128-ECB
- Data extraction: Parse all embedded OTP data (counters, timestamp, etc.)
- CRC validation: Built-in CRC16 checksum verification
- Validation functions: Check if strings contain valid hex or modhex characters
- Error handling: Comprehensive error types for invalid characters
- Minimal dependencies: Uses only AES crate for cryptographic operations
Installation
Add this to your Cargo.toml:
[]
= "0.1.0"
Usage
Basic Modhex Operations
use ;
// Convert hex to modhex
let hex = "0123456789abcdef";
let modhex = hex_to_modhex?;
assert_eq!;
// Convert modhex back to hex
let hex_result = modhex_to_hex?;
assert_eq!;
// Validate modhex strings
let yubikey_otp = "cccccdcfgvjubvnccblhhktldthvurhdrbvbtnvjtttr";
assert!;
Working with Byte Arrays
use ;
// Convert bytes to modhex
let bytes = ;
let modhex = bytes_to_modhex;
assert_eq!;
// Convert modhex back to bytes
let result_bytes = modhex_to_bytes?;
assert_eq!;
OTP Decryption
use decrypt_otp;
// Your YubiKey configuration
let aes_key = ;
let expected_public_id = Some;
// Decrypt a YubiKey OTP
let otp = "cccccdcfgvjubvnccblhhktldthvurhdrbvbtnvjtttr";
match decrypt_otp
Error Handling
use ;
match hex_to_modhex
API Reference
Functions
hex_to_modhex(hex_str: &str) -> Result<String, ModhexError>
Convert a hexadecimal string to modhex format. Accepts both uppercase and lowercase hex characters.
modhex_to_hex(modhex_str: &str) -> Result<String, ModhexError>
Convert a modhex string to hexadecimal format (lowercase output).
bytes_to_modhex(bytes: &[u8]) -> String
Convert a byte array to modhex string representation.
modhex_to_bytes(modhex_str: &str) -> Result<Vec<u8>, ModhexError>
Convert a modhex string to a byte vector. The modhex string must have even length.
is_valid_modhex(s: &str) -> bool
Check if a string contains only valid modhex characters.
is_valid_hex(s: &str) -> bool
Check if a string contains only valid hexadecimal characters (0-9, a-f, A-F).
decrypt_otp(otp: &str, aes_key: &[u8; 16], expected_public_id: Option<&str>, expected_private_id: Option<&[u8; 6]>) -> Result<DecryptedOtp, OtpError>
Decrypt and validate a YubiKey OTP using AES-128-ECB. Returns a DecryptedOtp struct containing all embedded data.
Error Types
ModhexError
InvalidHexCharacter(char): Invalid character found in hex stringInvalidModhexCharacter(char): Invalid character found in modhex string
OtpError
InvalidOtpFormat: Invalid OTP format or lengthModhexError(ModhexError): Modhex conversion errorInvalidPrivatePartLength: Invalid private part length (must be 32 characters)DecryptionError: AES decryption failedInvalidHex: Invalid hex string conversion
DecryptedOtp
Structure containing decrypted OTP data:
public_id: Public ID (first 12 characters)private_id: Private ID as hex string with colonsusage_counter: Usage counter (increments with each use)timestamp: Internal timestamp (~8Hz counter)session_counter: Session counter (increments each power-on)random: Random value as hex string with colonschecksum: CRC16 checksum as hex string with colonsvalid: Whether the CRC checksum is validpublic_id_valid: Whether the public ID matches expected value
Examples
YubiKey OTP Processing
use ;
// Example YubiKey OTP
let otp = "cccccdcfgvjubvnccblhhktldthvurhdrbvbtnvjtttr";
let hex_otp = process_yubikey_otp?;
println!;
Complete OTP Verification
use ;
use is_valid_modhex;
// Usage
let aes_key = ;
let public_id = "cccccdcfgvju";
let private_id = ;
let otp = "cccccdcfgvjubvnccblhhktldthvurhdrbvbtnvjtttr";
match verify_yubikey_otp
Key Configuration
To use the OTP decryption functionality, you'll need:
- Public ID: The first 12 characters of your YubiKey OTP
- AES Key: The 16-byte AES key programmed into your YubiKey (for validation)
- Private ID: The 6-byte private identifier (for validation)
These values are set during YubiKey personalization and are unique to each device.
Testing
Run the test suite:
License
This project is licensed under the MIT License - see the LICENSE file for details.