How to Access Your YubiKey in Go on Windows

Written by @pheonix | Published 2026/01/19
Tech Story Tags: golang-security | yubikey-go-integration | yubikey-piv-go | piv-go-windows | hardware-security-keys-go | go-smart-card-windows | yubikey-signing-go | secure-authentication-go

TLDRProgrammatic access lets you integrate YubiKeys directly into a Go application on Windows. On Windows, `piv.Cards()` uses the built-in WinSCard API to detect connected smart card devices.via the TL;DR App

YubiKeys are fantastic for securing authentication and cryptography, but integrating them directly into a Go application on Windows takes a few extra steps. In this article, we’ll walk through accessing a YubiKey in Go on Windows, step by step.

Installing piv-go

Install the piv-go module:

go get github.com/go-piv/piv-go/piv

Listing Connected YubiKeys on Windows

The following Go code will show you all the YubiKeys connected to your machine:

package main

import (
    "fmt"
    "github.com/go-piv/piv-go/piv"
)

func main() {
    cards, err := piv.Cards()
    if err != nil {
        panic(err)
    }

    if len(cards) == 0 {
        fmt.Println("No YubiKeys detected")
        return
    }

    for _, card := range cards {
        fmt.Println("Found YubiKey:", card)
    }
}

Accessing a PIV Slot on Windows

This Go program detects a connected YubiKey (PIV smart card) on Windows, opens it via piv-go, and reads the certificate from the PIV Authentication slot. It then prints the certificate’s subject details.

package main

import (
    "crypto/x509"
    "fmt"
    "github.com/go-piv/piv-go/piv"
)

func main() {
    cards, err := piv.Cards()
    if err != nil || len(cards) == 0 {
        panic("No YubiKeys detected")
    }

    yk, err := piv.Open(cards[0])
    if err != nil {
        panic(err)
    }
    defer yk.Close()

    cert, err := yk.Certificate(piv.SlotAuthentication)
    if err != nil {
        panic(err)
    }

    fmt.Println("Certificate Subject:", cert.Subject)
}

Signing Data on Windows

This Go program opens a connected YubiKey PIV device on Windows, retrieves the private key from the PIV Authentication slot, and uses it to sign a SHA-256 digest of some data. It then prints the resulting signature in hex.

package main

import (
    "crypto"
    "crypto/rand"
    "fmt"
    "github.com/go-piv/piv-go/piv"
)

func main() {
    cards, err := piv.Cards()
    if err != nil || len(cards) == 0 {
        panic("No YubiKeys detected")
    }

    yk, err := piv.Open(cards[0])
    if err != nil {
        panic(err)
    }
    defer yk.Close()

    key, err := yk.PrivateKey(piv.SlotAuthentication, nil)
    if err != nil {
        panic(err)
    }

    data := []byte("Hello, secure Windows world!")
    hash := crypto.SHA256.New()
    hash.Write(data)
    digest := hash.Sum(nil)

    signature, err := key.(crypto.Signer).Sign(rand.Reader, digest, crypto.SHA256)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Signed data: %x\n", signature)
}

Wrapping Up

On Windows, piv-go leverages native WinSCard APIs to access YubiKeys, making it straightforward to use PIV slots and sign data. Programmatic access keeps your private keys secure and opens doors for custom authentication workflows on Windows systems.


Published by HackerNoon on 2026/01/19