local-cred is a secure local credential management library written in Go. It provides a unified interface for managing cryptographic keys and performing encryption/signing operations, leveraging platform-specific security hardware and storage mechanisms.
- Platform Specific Security:
- Windows & Linux: Uses TPM 2.0 (Trusted Platform Module) for secure key storage and operations.
- macOS: Uses the system Keychain for secure key storage.
- Cryptographic Operations:
- Encryption (DEK - Data Encryption Key):
- AES-256-GCM
- XChaCha20-Poly1305
- Signing:
- ECDSA (P-256)
- Ed25519
- ML-DSA-87 (Post-Quantum Cryptography)
- Encryption (DEK - Data Encryption Key):
- Key Hierarchy:
- KEK (Key Encryption Key): Protected by the platform (TPM or Keychain). Used to encrypt DEKs and Signing Keys.
- DEK (Data Encryption Key): Encrypted by KEK. Used to encrypt actual data.
- Signing Key: Encrypted by KEK. Used to sign data.
- Secure Memory: Uses
memguardto protect sensitive key material in memory (where applicable).
go get github.com/snowmerak/local-cred- Windows/Linux: A TPM 2.0 module is required (or a simulator for testing).
- macOS: Access to the system Keychain.
On Windows and Linux, local-cred uses the TPM to protect the Key Encryption Key (KEK).
package main
import (
"fmt"
"log"
"github.com/snowmerak/local-cred/keystore/tpm"
)
func main() {
// 1. Initialize TPM Client
// Note: In a real application, you might need to configure the TPM transport.
// This example assumes a default setup or simulator.
// See tpm.OpenTPM in the library for details on connection.
// For Windows, it automatically connects to the system TPM.
// Initialize a Store to save the encrypted keys (blobs).
// You can use the provided BadgerStore, PebbleStore, or implement your own tpm.Store interface.
// Option A: Use BadgerDB
store, err := tpm.NewBadgerDB("./badger-data")
// Option B: Use PebbleDB
// store, err := tpm.NewPebbleDB("./pebble-data")
if err != nil {
log.Fatal(err)
}
defer store.Close()
client, err := tpm.NewTPMClient() // You might need to pass transport
if err != nil {
log.Fatal(err)
}
defer client.Close()
ops, err := tpm.NewTPMOps(client, store)
if err != nil {
log.Fatal(err)
}
defer ops.Close()
kekName := "my-app-kek"
// 2. Create/Load a Data Encryption Key (DEK)
// Supported algos: "AES256GCM", "XChaCha20Poly1305"
encryptor, encryptedDEK, err := ops.CreateDEK(kekName, "AES256GCM")
if err != nil {
log.Fatal(err)
}
// Save encryptedDEK to your storage for later use
// Encrypt data
plaintext := []byte("Secret Data")
ciphertext, err := encryptor.Encrypt(plaintext)
if err != nil {
log.Fatal(err)
}
// Decrypt data
decrypted, err := encryptor.Decrypt(ciphertext)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Decrypted: %s\n", decrypted)
// 3. Create/Load a Signing Key
// Supported algos: "ECDSA-P256", "Ed25519", "ML-DSA-87"
signer, encryptedPriv, pubKey, err := ops.CreateSigningKey(kekName, "ML-DSA-87")
if err != nil {
log.Fatal(err)
}
// Save encryptedPriv and pubKey to your storage
// Sign data
msg := []byte("Message to sign")
signature, err := signer.Sign(msg)
if err != nil {
log.Fatal(err)
}
// Verify signature
valid := signer.Verify(msg, signature)
fmt.Printf("Signature Valid: %v\n", valid)
}On macOS, local-cred uses the system Keychain to store the KEK.
package main
import (
"fmt"
"log"
"github.com/snowmerak/local-cred/keystore/keychain"
)
func main() {
serviceName := "my-app-service"
client := keychain.NewKeychainClient(serviceName)
kekName := "my-app-kek"
// 1. Create/Load a Data Encryption Key (DEK)
encryptor, encryptedDEK, err := client.CreateDEK(kekName, "XChaCha20Poly1305")
if err != nil {
log.Fatal(err)
}
// Save encryptedDEK
// Encrypt/Decrypt...
// ...
// 2. Create/Load a Signing Key
signer, encryptedPriv, pubKey, err := client.CreateSigningKey(kekName, "Ed25519")
if err != nil {
log.Fatal(err)
}
// Save encryptedPriv and pubKey
// Sign/Verify...
// ...
}The TPM implementation uses the TPM to wrap a "Key Encryption Key" (KEK). This KEK never leaves the TPM in plaintext.
- KEK Creation: A primary key (SRK) in the TPM is used to wrap a generated AES key (the KEK).
- DEK/Signing Key Creation: New keys are generated in software (using secure memory), then encrypted (wrapped) by the KEK using the TPM.
- Usage: To use a key, the encrypted blob is loaded into the TPM, unwrapped by the KEK inside the TPM, and then used for operations.
The Keychain implementation uses the macOS Keychain to store the KEK securely.
- KEK Storage: The KEK is stored as a generic password item in the Keychain.
- Operations: The KEK is retrieved from the Keychain into secure memory (
memguard) to perform encryption/decryption of DEKs and Signing Keys in software.