Python library for communicating with Yubico YubiKey hardware authentication tokens
—
Comprehensive YubiKey configuration system supporting all operational modes including Yubico OTP, OATH-HOTP, and challenge-response with full control over device settings, flags, and security parameters.
Create and initialize YubiKey configuration objects with version compatibility checking.
class YubiKeyConfig:
def __init__(self, ykver=None, capabilities=None, update=False, swap=False, zap=False):
"""
Initialize YubiKey configuration object.
Parameters:
- ykver (tuple): YubiKey version tuple for compatibility checking
- capabilities (YubiKeyCapabilities): Device capabilities object
- update (bool): True for configuration update (preserves other slot)
- swap (bool): True to swap configuration slots after writing
- zap (bool): True to clear configuration slot
"""
def version_required(self):
"""
Get minimum YubiKey version required for this configuration.
Returns:
tuple: Minimum version tuple (major, minor, build)
"""Basic configuration creation:
import yubico
from yubico.yubikey_config import YubiKeyConfig
yk = yubico.find_yubikey()
# Create new configuration
cfg = YubiKeyConfig()
# Or use device-specific initialization
cfg = yk.init_config()
# Check version requirements
min_version = cfg.version_required()
print(f"Minimum version required: {min_version}")Configure YubiKey for standard Yubico OTP validation with Yubico's authentication servers.
def mode_yubikey_otp(self, private_uid, aes_key):
"""
Configure YubiKey for Yubico OTP mode.
Parameters:
- private_uid (bytes): 6-byte private UID
- aes_key (bytes): 16-byte AES key
Raises:
InputError: If parameters are invalid
"""Yubico OTP configuration example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
import os
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Generate random private UID and AES key
private_uid = os.urandom(6)
aes_key = os.urandom(16)
# Configure for Yubico OTP
cfg.mode_yubikey_otp(private_uid, aes_key)
# Write to slot 1
yk.write_config(cfg, slot=1)
print("Yubico OTP configured")Configure YubiKey for OATH-HOTP (RFC 4226) authentication.
def mode_oath_hotp(self, secret, digits=6, factor_seed=None, omp=0x0, tt=0x0, mui=''):
"""
Configure YubiKey for OATH-HOTP mode.
Parameters:
- secret (bytes): HOTP secret key (up to 20 bytes)
- digits (int): Number of digits in HOTP output (6 or 8)
- factor_seed (int): Initial counter value
- omp (int): Moving factor seed
- tt (int): Truncation offset
- mui (str): Management Unit Identifier
Raises:
InputError: If parameters are invalid
"""OATH-HOTP configuration example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
import base32
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Use standard base32-encoded secret
secret_b32 = "JBSWY3DPEHPK3PXP"
secret = base32.b32decode(secret_b32)
# Configure for OATH-HOTP with 6 digits
cfg.mode_oath_hotp(secret, digits=6, factor_seed=1)
# Write to slot 2
yk.write_config(cfg, slot=2)
print("OATH-HOTP configured")Configure YubiKey for challenge-response authentication using HMAC-SHA1 or Yubico protocols.
def mode_challenge_response(self, secret, type='HMAC', variable=True, require_button=False):
"""
Configure YubiKey for challenge-response mode.
Parameters:
- secret (bytes): Secret key (up to 20 bytes for HMAC, 16 bytes for Yubico)
- type (str): Challenge type - 'HMAC' for HMAC-SHA1 or 'OTP' for Yubico
- variable (bool): Variable length response (HMAC only)
- require_button (bool): Require button press for challenge-response
Raises:
InputError: If parameters are invalid
"""Challenge-response configuration example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
import os
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Generate random secret for HMAC-SHA1
secret = os.urandom(20)
# Configure for HMAC challenge-response
cfg.mode_challenge_response(
secret=secret,
type='HMAC',
variable=True,
require_button=False
)
# Write to slot 1
yk.write_config(cfg, slot=1)
print("Challenge-response configured")
# Test the configuration
challenge = b"test challenge"
response = yk.challenge_response(challenge, slot=1)
print(f"Response: {response.hex()}")Set various cryptographic keys and access codes for YubiKey security.
def aes_key(self, data):
"""
Set AES128 key for YubiKey operations.
Parameters:
- data (bytes): 16-byte AES key
Raises:
InputError: If key length is invalid
"""
def unlock_key(self, data):
"""
Set access code required for re-programming this configuration.
Parameters:
- data (bytes): 6-byte access code
"""
def access_key(self, data):
"""
Set new access code for future programming operations.
Parameters:
- data (bytes): 6-byte access code
"""Key management example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
import os
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Set AES key
aes_key = os.urandom(16)
cfg.aes_key(aes_key)
# Set access code for future programming
access_code = os.urandom(6)
cfg.access_key(access_code)
# Configure mode and write
cfg.mode_yubikey_otp(os.urandom(6), aes_key)
yk.write_config(cfg, slot=1)Control YubiKey behavior through various configuration flags.
def ticket_flag(self, which, new=None):
"""
Get or set ticket flags.
Parameters:
- which (str): Flag name (e.g., 'APPEND_CR', 'APPEND_TAB')
- new (bool): New flag value, or None to query current value
Returns:
bool: Current flag value if new is None
"""
def config_flag(self, which, new=None):
"""
Get or set configuration flags.
Parameters:
- which (str): Flag name (e.g., 'SEND_REF', 'TICKET_FIRST')
- new (bool): New flag value, or None to query current value
Returns:
bool: Current flag value if new is None
"""
def extended_flag(self, which, new=None):
"""
Get or set extended flags.
Parameters:
- which (str): Flag name (e.g., 'SERIAL_BTN_VISIBLE', 'SERIAL_USB_VISIBLE')
- new (bool): New flag value, or None to query current value
Returns:
bool: Current flag value if new is None
"""Configuration flags example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Set ticket flags
cfg.ticket_flag('APPEND_CR', True) # Append carriage return
cfg.ticket_flag('APPEND_TAB', False) # Don't append tab
# Set configuration flags
cfg.config_flag('SEND_REF', True) # Send reference string first
cfg.config_flag('TICKET_FIRST', False)
# Set extended flags
cfg.extended_flag('SERIAL_BTN_VISIBLE', True) # Serial visible after button press
cfg.extended_flag('SERIAL_USB_VISIBLE', False) # Serial not visible via USB
# Query current flag values
cr_flag = cfg.ticket_flag('APPEND_CR')
print(f"APPEND_CR flag: {cr_flag}")Configure the fixed string (Token Identifier) portion of YubiKey output.
def fixed_string(self, data=None):
"""
Get or set fixed string (Token Identifier).
The fixed string is the first part of YubiKey OTP output and can be
used to identify the specific YubiKey or user.
Parameters:
- data (bytes): Fixed string data (up to 16 bytes), or None to query
Returns:
bytes: Current fixed string if data is None
"""Fixed string configuration example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Set custom fixed string (Token Identifier)
token_id = b"mytoken001"
cfg.fixed_string(token_id)
# Configure Yubico OTP mode
cfg.mode_yubikey_otp(os.urandom(6), os.urandom(16))
# Write configuration
yk.write_config(cfg, slot=1)
print(f"Token ID set to: {token_id}")Enable advanced YubiKey features and modes.
def enable_extended_scan_code_mode(self):
"""
Enable extended scan code mode.
Allows YubiKey to output characters not available in basic scan code mode.
"""
def enable_shifted_1(self):
"""
Enable shifted character 1 before output.
Prepends shifted character 1 to YubiKey output.
"""Advanced configuration example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Enable advanced features
cfg.enable_extended_scan_code_mode()
cfg.enable_shifted_1()
# Configure and write
cfg.mode_yubikey_otp(os.urandom(6), os.urandom(16))
yk.write_config(cfg, slot=1)Export configuration objects as binary data or frames for transmission.
def to_string(self):
"""
Export configuration as 64-byte binary string.
Returns:
bytes: 64-byte configuration data
"""
def to_frame(self, slot=1):
"""
Export configuration as YubiKeyFrame object.
Parameters:
- slot (int): Target configuration slot
Returns:
YubiKeyFrame: Frame object ready for transmission
"""Configuration export example:
import yubico
from yubico.yubikey_config import YubiKeyConfig
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Configure YubiKey
cfg.mode_challenge_response(os.urandom(20))
# Export as binary data
config_data = cfg.to_string()
print(f"Configuration size: {len(config_data)} bytes")
# Export as frame
frame = cfg.to_frame(slot=1)
print(f"Frame command: {frame.command}")The configuration system includes automatic validation and version compatibility checking:
import yubico
from yubico.yubikey_config import YubiKeyConfig, YubiKeyConfigError
try:
yk = yubico.find_yubikey()
cfg = yk.init_config()
# Invalid configuration will raise error
cfg.mode_oath_hotp(b"too_long_secret_key_data", digits=10) # Invalid
except YubiKeyConfigError as e:
print(f"Configuration error: {e.reason}")
except yubico.yubikey_base.YubiKeyVersionError as e:
print(f"Version compatibility error: {e.reason}")Install with Tessl CLI
npx tessl i tessl/pypi-python-yubico