file

package
v1.0.0-beta.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 15, 2025 License: Apache-2.0 Imports: 13 Imported by: 0

README

Secure FileSystem Signer

This package provides a secure implementation of a signer that stores cryptographic keys on the filesystem. The implementation follows security best practices to ensure that private keys are never stored in plain text on disk.

Features

  • Secure Key Storage: Private keys are encrypted using AES-GCM before being stored on disk
  • Passphrase Protection: Keys are protected by a user-provided passphrase
  • In-Memory Operation: Once loaded, keys remain in memory for signing operations
  • Automatic Key Generation: If keys don't exist, they are automatically generated
  • Thread Safety: Concurrent access to the signer is protected by mutex locks

Security Measures

  1. Encryption: Private keys are encrypted using AES-GCM, a secure authenticated encryption mode
  2. Permissions: Key files are stored with 0600 permissions (readable and writable only by the owner)
  3. Directory Creation: Key directories are created with 0700 permissions
  4. No Plain Text: Private keys are never stored in plain text on disk
  5. Passphrase Derivation: A key derivation function is used to derive encryption keys from passphrases

Usage

// Create a new signer (or load existing keys)
passphrase := []byte("your-secure-passphrase")
keyPath := "/path/to/secure/keys.json"
signer, err := NewFileSystemSigner(keyPath, passphrase)
if err != nil {
    // Handle error
}

// Sign a message
message := []byte("Message to sign")
signature, err := signer.Sign(message)
if err != nil {
    // Handle error
}

// Get the public key
pubKey, err := signer.GetPublic()
if err != nil {
    // Handle error
}

Production Considerations

For production use, consider the following enhancements:

  1. Stronger KDF: Replace the simple key derivation function with Argon2 or PBKDF2
  2. Secure Passphrase Handling: Implement secure methods for obtaining and handling passphrases

Implementation Details

The FileSystemSigner stores keys in a JSON file with the following structure:

{
  "priv_key_encrypted": "...", // Base64-encoded encrypted private key
  "nonce": "...",             // Base64-encoded nonce for AES-GCM
  "pub_key": "..."            // Base64-encoded public key
}

The encryption process:

  1. Generate a random nonce
  2. Derive an encryption key from the passphrase
  3. Encrypt the private key using AES-GCM with the derived key and nonce
  4. Store the encrypted private key, nonce, and public key in the JSON file

The decryption process:

  1. Read the JSON file
  2. Derive the encryption key from the passphrase
  3. Decrypt the private key using AES-GCM with the derived key and stored nonce
  4. Load the keys into memory for use

Documentation

Overview

File Remote Signer implements the Signer interface using a file to store the keys.

The keys are stored in a file in the local filesystem.

passphrase := []byte("your-secure-passphrase")
keyPath := "/path/to/secure/keys.json"

// Create or load a signer
signer, err := NewFileSystemSigner(keyPath, passphrase)
if err != nil {
	panic(err)
}

// Sign a message
message := []byte("Message to sign")
signature, err := signer.Sign(message)
if err != nil {
	panic(err)
}

// Get the public key
pubKey, err := signer.GetPublic()
if err != nil {
	panic(err)
}

// Verify the signature (typically done by another party)
valid, err := pubKey.Verify(message, signature)
if err != nil {
	panic(err)
}
Example

Example demonstrates how to use the FileSystemSigner

// In a real application, you would use a secure passphrase
passphrase := []byte("your-secure-passphrase")
keyPath := "/path/to/secure/keys.json"

// Create or load a signer
signer, err := CreateFileSystemSigner(keyPath, passphrase)
if err != nil {
	panic(err)
}

// Sign a message
message := []byte("Message to sign")
signature, err := signer.Sign(message)
if err != nil {
	panic(err)
}

// Get the public key
pubKey, err := signer.GetPublic()
if err != nil {
	panic(err)
}

// Verify the signature (typically done by another party)
valid, err := pubKey.Verify(message, signature)
if err != nil {
	panic(err)
}

if valid {
	// Signature is valid
} else {
	// Signature is invalid
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateFileSystemSigner

func CreateFileSystemSigner(keyPath string, passphrase []byte) (signer.Signer, error)

CreateFileSystemSigner creates a new key pair and saves it encrypted to disk.

func ExportPrivateKey

func ExportPrivateKey(keyPath string, passphrase []byte) ([]byte, error)

ExportPrivateKey decrypts and returns the raw private key from the key file. It is intended for key backup and migration purposes. WARNING: Handle the returned private key with extreme care.

func ImportPrivateKey

func ImportPrivateKey(keyPath string, privKeyBytes []byte, passphrase []byte) error

ImportPrivateKey encrypts a raw private key and saves it to the key file. It will overwrite an existing key file if one exists. WARNING: This is a destructive operation.

func LoadFileSystemSigner

func LoadFileSystemSigner(keyPath string, passphrase []byte) (signer.Signer, error)

LoadFileSystemSigner loads existing keys from an encrypted file on disk.

Types

type FileSystemSigner

type FileSystemSigner struct {
	// contains filtered or unexported fields
}

FileSystemSigner implements a signer that securely stores keys on disk and loads them into memory only when needed.

func (*FileSystemSigner) GetAddress

func (s *FileSystemSigner) GetAddress() ([]byte, error)

GetAddress returns the address of the signer

func (*FileSystemSigner) GetPublic

func (s *FileSystemSigner) GetPublic() (crypto.PubKey, error)

GetPublic returns the public key

func (*FileSystemSigner) Sign

func (s *FileSystemSigner) Sign(message []byte) ([]byte, error)

Sign signs a message using the private key

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL