Yubikey (Yubico) Personalization Tool PowerShell Commandline (CLI): Program Random Static Passwords (example)

Title image of Yubikey and Powershell logos

In writing this, I hope I am not the only one who has encountered this scenario. You get the call or ticket: “Can you check on the Windows device XXXXX? It is not normal and performing strangely.” Being a diligent systems administrator, you log into device XXXXX to take a look. As the desktop background renders, you start to see warnings and notifications from your antivirus/antimalware solution: “infections detected, cannot be quarantined: Trojan.Emotet …” (or some other credential-stealing malware variant). Yikes! And you just logged in with your privileged account!

Probably best to assume your privileged credentials are now compromised or otherwise in the wild.

Although this specific scenario may not occur a lot, I believe it is advisable to change or rotate your privileged account password more frequently than you would other accounts. If you use a Yubikey (and the good old static password configuration), you can script the reset process with Powershell to save yourself some keystrokes, time and panic if you must reset your password in a hurry.

If you do not have a Yubikey already, you need one. Or two so you have a backup.

In this post, I will share a PowerShell based approach to quickly generate a new random, static password on a Yubikey and subsequently change your local or domain account password.

Install the YubiKey Personalization Tool command-line interface (CLI)

It is worth noting, there are 2 Yubikey command line interfaces. “YubiKey Personalization Tool” contains ykpersonalize.exe and is what I will cover in this post.

There is also “YubiKey Manager” which contains ykman.exe; there is some overlap between the tools but I found ykpersonalize.exe (YubiKey Personalization Tool CLI) to be the path of least resistance.

There is not an “install” for ykpersonalize on Windows - simply download the appropriate version from Yubico, extract the archive, and place the files somewhere on your device. I opted to create a folder under %LOCALAPPDATA%\Programs for a “per user” experience under my account.

%LOCALAPPDATA%\Programs\Yubico

And the structure under that folder (example):

Extracted/unzipped YubiKey Personalization Tool CLI folder structure on Windows

Use PowerShell to call ykpersonalize and generate a random, static password in your Yubikey

Under Windows, ykpersonalize does not require elevation to interact with the Yubikey. That being the case, I wanted to create a function or script I could run to quickly do the following:

1) Collect the current credentials for any services/accounts I planned to reset my password for

2) Generate a random, static password in the Yubikey that complies with most password policy requirements (note: the generated portion should comprise only part of your complete password - more specifically, the end of it. For security, prepend a password of your choosing to the generated password to create a “something you know” and “something you have” scenario.)

3) Set the new static password on the Yubikey to the new password on services/accounts

The YubiKey Personalization Tool CLI is well documented at these links:

Even so, a little tinkering was required to achieve what I was looking for. My hang-up was the functionality of the -ofixed and -a switches. In brief, you can generate a new static password on the Yubikey with these PowerShell commands:

# Create an alias for ykpersonalize pointing the the "install" location
set-alias ykpersonalize "$env:localappdata\Programs\Yubico\bin\ykpersonalize.exe"

# Generate a random hex (AES key) to serve as entropy (randomness source) for ykpersonalize
$RandomHex = (((32)|%{((1..$_)|%{('{0:X}' -f (random(16)))})}) -Join "").ToLower()

# Run ykpersonalize to generate a random static password in Yubikey's config slot 2
ykpersonalize -2 -a"$RandomHex" -ostatic-ticket -oshort-ticket -ostrong-pw1 -ostrong-pw2 -y

If you run the sample above, you should end up with a random, 16 character password generated on your Yubikey in configuration slot 2. You can long-press the button to release and view the password (assuming you used configuration slot 2 as I did).

The magic is the -a switch - this specifies a “randomness source” in the form of a hex AES key that the Yubikey uses to generate the static password. If you fail to specify an AES key (-a), ykpersonalize will throw an error like this:

Yubikey personalization error: no randomness source available

The human version of the functionality of the switches I used is as follows:

  • -2 = programs the second configuration slot on Yubikeys that have one (if not, use -1 for slot 1)
  • -a = specify the 32 character (hex) AES key used as a randomness source to generate the static password
  • -ostatic-ticket = option -> configuration flag: generate and store a static password
  • -oshort-ticket = option -> configuration flag: limit the static password length to 16 characters
  • -ostrong-pw1 = option -> configuration flag: ensure the first 2 letters of the static password are upper case
  • -ostrong-pw2 = option -> configuration flag: ensure the static password contains numbers (in addition to letters)
  • -y = bypass the confirmation prompt and write the configuration immediately

As you can see, the -ofixed switch can be omitted, although it is used extensively in the Yubico examples. Almost all of the configuration flags I used manipulated the length and complexity of the generated password. I did this to ensure compliance with password policies across various legacy systems.

-a should be a random hexadecimal string. If you specify the same AES key each time you run the ykpersonalize command, your generated static password will be the same every time. The process requires generating a random 32 character hex string each time you run ykpersonalize.

Speaking of which, the $RandomHex variable is generated based on the awesome work of Forty3 from Code Golf on Stack Exchange. I made a minor adjustment to Forty3’s PowerShell code that generates a random uuid string.

To flesh things out further, I put together this snippet (also available as a gist).

It uses the base logic of the original command to generate a new static password on the Yubikey, then reset the password of the user running the PowerShell session to the new static password (requires pressing the button on the Yubikey to release it twice).

# Create an alias for ykpersonalize pointing the the "install" location
set-alias ykpersonalize "$env:localappdata\Programs\Yubico\bin\ykpersonalize.exe"

# Provide an opportunity to insert the yubikey before continuing
Read-Host -Prompt "Ensure Yubikey is inserted then press Enter to continue"

# Add a new line for formatting/tidiness
write-host " "

# Generate a random, 32 character hex string to serve as the randomness source for generating
# the new static password on the Yubikey. Based heavily on Forty3's POSH code from:
# https://codegolf.stackexchange.com/questions/58442/generate-random-uuid
$RandomHex = (((32)|%{((1..$_)|%{('{0:X}' -f (random(16)))})}) -Join "").ToLower()

# Run ykpersonalize to generate the static password on the Yubikey (in slot 2)
ykpersonalize -2 -a"$RandomHex" -ostatic-ticket -oshort-ticket -ostrong-pw1 -ostrong-pw2 -y

# Wait a second, then add a new line for formatting/tidiness
sleep 1
write-host " "

# Have the user enter their own password to prepend the Yubikey random, static password (improves security)
# See https://support.yubico.com/support/solutions/articles/15000006480-understanding-core-static-password-features
write-host "Resetting password for $env:username - enter a personal password and without pressing enter, long-press the button on your Yubikey to append the generated static password when prompted (twice) ..."

# Determine if the account is a local account or domain account and run the respective "net use"
# command to reset the password. In most cases, the account is local if %userdomain% and %computername% match
if($env:userdomain -like "*$env:computername") {
     net user "$env:username" *
} else {
     net user "$env:username" * /domain
}

# Zero out variables
$NewPassword = ""
$RandomHex = ""

# Add new lines and output for formatting/tidiness
write-host " "
write-host "DONE"
write-host " "

Once done, the account password is reset and you can login by typing your personal password, then long pressing the button on your Yubikey to release the generated password.

For a more detailed look at the construction of a secure, static password on Yubikey, see:

Example of combining a "known" personal password with a Yubikey randomly generated, static password (something you "have") to improve static password security

In this example, the personal portion (something I “know”) of the static password is Abc123. The random (generated) portion of the static password is LNtr45ucdhdtlril (something I “have” - this is emitted from the Yubikey).

Closing thoughts

It is worth noting, static passwords on the Yubikey are not the most secure authentication option. Be that as it may, I have found that the convenience and versatility of static passwords outweigh the risks. I would argue that frequently changing or rotating static passwords (concatenated with your own secure password) on the Yubikey offers added protection to this approach.

Here are a few examples of where Yubikey static passwords shine:

  • Across platforms and devices (Windows, macOS, Linux, etc.)
  • Physical servers in a datacenter (with USB ports)
  • Virtual servers via SSH, RDP, etc. access
  • The VMware Remote Console (no copy/paste)
  • Windows UAC (User Account Control) elevation screens (no copy/paste)
  • Broken devices where smartcard authentication, FIDO, etc. are no longer working properly
  • Air-gapped devices with no network access

However you choose to proceed, stay secure (or at least more secure than your slowest friends) to avoid being eaten by the compromised credential bear!