xipher

package module
v1.19.1 Latest Latest
Warning

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

Go to latest
Published: Nov 18, 2025 License: MIT Imports: 11 Imported by: 0

README

Xipher Logo

Xipher

Secure asymmetric encryption with password-based keys

Go Reference Go Report Card Test Status Release Status License

Overview

Xipher is a collection of cryptographic primitives for password-based asymmetric encryption. It lets you share encrypted data between parties over insecure channels using public keys derived from passwords. Includes support for post-quantum algorithms.

Features

  • Asymmetric encryption using password-derived public keys
  • Stream processing with built-in compression
  • Post-quantum security (optional Kyber1024 support)
  • Available as CLI tool, Go library, WebAssembly module, and web interface
  • Optimized for both small and large data

Quick Start

Installation

CLI Tool

Homebrew (macOS):

brew install shibme/tap/xipher

Install Script (Linux/macOS):

# Latest version
curl -fsSL https://xipher.org/install/install.sh | sh

# Specific version  
curl -fsSL https://xipher.org/install/install.sh | sh -s v1.17.0

Install Script (Windows):

# PowerShell (latest version)
irm https://xipher.org/install/install.ps1 | iex

# PowerShell with specific version
$v="1.17.0"; irm https://xipher.org/install/install.ps1 | iex

Binary Download: Download from releases page

Docker:

docker run --rm -v $PWD:/data -it shibme/xipher help
Go Package
go get -u xipher.org/xipher

Basic Usage

CLI Example

Demo

Go Package Example
package main

import (
	"encoding/base32"
	"fmt"
	"xipher.org/xipher"
)

func main() {
	// Create secret key from password
	secretKey, err := xipher.NewSecretKeyForPassword([]byte("your-secure-password"))
	if err != nil {
		panic(err)
	}

	// Derive public key
	publicKey, err := secretKey.PublicKey(false)
	if err != nil {
		panic(err)
	}

	// Encrypt data
	plaintext := []byte("Hello, World!")
	ciphertext, err := publicKey.Encrypt(plaintext, true)
	if err != nil {
		panic(err)
	}

	// Decrypt data
	decrypted, err := secretKey.Decrypt(ciphertext)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Original: %s\n", plaintext)
	fmt.Printf("Decrypted: %s\n", decrypted)
}

Usage

Web Interface

Try it out at xipher.org

How it works:

  1. The receiver opens the web app and generates a key pair (keys are saved in the browser).
  2. The receiver shares their public key URL with the sender.
  3. The sender opens this URL, encrypts their data using the receiver's encryption URL, and then sends the resulting ciphertext (or encrypted link) back to the receiver.
  4. The receiver decrypts the ciphertext in the same browser where the key pair was originally generated.
sequenceDiagram
participant RX as Xipher<br>(Browser)
actor R as Receiver
actor S as Sender
participant SX as Xipher<br>(Browser)
    R-->>+RX: Opens app
    RX-->>RX: Generate keys
    RX-->>-R: Public key URL
    R->>+S: Share URL
    S-->>+SX: Open URL & encrypt
    SX-->>-S: Ciphertext
    S->>-R: Send ciphertext
    R-->>+RX: Decrypt
    RX-->>-R: Plaintext

GitHub Actions Integration

steps:
- name: Setup Xipher
  uses: shibme/xipher@v1
  with:
    version: 1.17.0  # optional

Host Your Own Web Interface

name: Publish Xipher Web
on:
  workflow_dispatch:
jobs:
  pages:
    uses: shibme/xipher/.github/workflows/pages.yaml@main

Web Assembly

<html>
<head>
	<meta charset="utf-8"/>
	<script src="https://xipher.org/wasm/wasm_exec.js"></script>
	<script>
		const go = new Go();
		WebAssembly.instantiateStreaming(
			fetch("https://xipher.org/wasm/xipher.wasm"), 
			go.importObject
		).then((result) => {
			go.run(result.instance);
		});
	</script>
</head>
<body>
	<!-- Call methods starting with 'xipher', e.g., xipherNewSecretKey() -->
</body>
</html>

Technical Details

Algorithms

Note: v1.19+ uses Go's native ML-KEM package for post-quantum crypto (FIPS 203 compliant). This breaks compatibility with previous Kyber implementations. Standard ECC encryption is unaffected.

Documentation

Contributing

Contributions are welcome. Fork the repo, make your changes, and submit a pull request. For bugs or feature requests, open an issue.

Security

This project is experimental - use with caution in production. If you find security issues, please report them.

A few things to keep in mind:

  • Password strength matters
  • Post-quantum algorithms are still evolving
  • Keep your dependencies updated

License

This project is licensed under the terms specified in the LICENSE file.

Acknowledgments

Thanks to these projects:

  • Retriever - Inspiration for web-based encryption concepts
  • StreamSaver.js - Browser file saving capabilities
  • age - Inspiration for Curve25519 and XChaCha20-Poly1305 usage

Documentation

Overview

Package xipher provides a curated collection of cryptographic primitives for performing key/password-based asymmetric encryption.

Xipher allows secure data sharing between two parties over an insecure channel using asymmetric encryption. The sender encrypts data using a public key (usually derived from a password) and shares the encrypted data with the receiver. The receiver decrypts the data using the corresponding secret key or password.

Key features:

  • Password-based public key generation
  • Stream cipher with compression support
  • Post-quantum cryptography using Kyber1024
  • Stream processing for memory efficiency

Example usage:

// Create a secret key from password
secretKey, err := xipher.NewSecretKeyForPassword([]byte("mypassword"))
if err != nil {
	panic(err)
}

// Generate public key
publicKey, err := secretKey.PublicKey(false)
if err != nil {
	panic(err)
}

// Encrypt data
plaintext := []byte("Hello, World!")
ciphertext, err := publicKey.Encrypt(plaintext, true, true)
if err != nil {
	panic(err)
}

// Decrypt data
decrypted, err := secretKey.Decrypt(ciphertext)
if err != nil {
	panic(err)
}

Package xipher provides a curated collection of cryptographic primitives for performing key/password-based asymmetric encryption with support for post-quantum cryptography.

Overview

Xipher enables secure data sharing between two parties over an insecure channel using asymmetric encryption. The sender encrypts data using a public key (usually derived from a password) and shares the encrypted data with the receiver. The receiver decrypts the data using the corresponding secret key or password.

Key Features

• Password-based public key generation using Argon2 key derivation • Stream cipher with optional compression for memory efficiency • Post-quantum cryptography support using Kyber1024 • Stream processing for handling large files efficiently • Base32 encoding for human-readable ciphertext • Both symmetric and asymmetric encryption modes

Architecture

The package is built around two main types:

SecretKey: Represents a cryptographic secret key that can be either password-based or directly generated from random data. It supports both symmetric and asymmetric encryption operations.

PublicKey: Represents a cryptographic public key for asymmetric encryption. It contains the actual public key material and associated metadata.

Key Types

Xipher supports two types of keys:

Direct Keys: Generated from cryptographically secure random data (64 bytes). These provide maximum entropy and are suitable when key management is handled separately.

Password-based Keys: Derived from passwords using Argon2 key derivation function. These are more convenient for human use but require secure password practices.

Encryption Modes

Symmetric Encryption: Uses the secret key directly for encryption/decryption. This is faster and suitable when the same party encrypts and decrypts.

Asymmetric Encryption: Uses public key for encryption and secret key for decryption. This enables secure communication between different parties.

Post-Quantum Cryptography

Xipher supports post-quantum cryptography using the Kyber1024 algorithm, providing resistance against quantum computer attacks. This can be enabled when generating public keys by setting the pq parameter to true.

Basic Usage Examples

## Password-based Encryption

// Create a secret key from password
secretKey, err := xipher.NewSecretKeyForPassword([]byte("my-secure-password"))
if err != nil {
	return err
}

// Generate public key (standard ECC)
publicKey, err := secretKey.PublicKey(false)
if err != nil {
	return err
}

// Encrypt data
plaintext := []byte("Hello, World!")
ciphertext, err := publicKey.Encrypt(plaintext, true, true)
if err != nil {
	return err
}

// Decrypt data
decrypted, err := secretKey.Decrypt(ciphertext)
if err != nil {
	return err
}

## Direct Key Generation

// Generate a random secret key
secretKey, err := xipher.NewSecretKey()
if err != nil {
	return err
}

// Export key for storage
keyString, err := secretKey.String()
if err != nil {
	return err
}

// Later, import the key
importedKey, err := xipher.ParseSecretKeyStr(keyString)
if err != nil {
	return err
}

## Post-Quantum Encryption

// Create secret key
secretKey, err := xipher.NewSecretKeyForPassword([]byte("quantum-safe-password"))
if err != nil {
	return err
}

// Generate post-quantum public key
pqPublicKey, err := secretKey.PublicKey(true) // true enables post-quantum
if err != nil {
	return err
}

// Encrypt with post-quantum cryptography
ciphertext, err := pqPublicKey.Encrypt([]byte("quantum-safe message"), true, true)
if err != nil {
	return err
}

## Stream Processing

// Encrypt large files efficiently
inputFile, err := os.Open("largefile.txt")
if err != nil {
	return err
}
defer inputFile.Close()

outputFile, err := os.Create("encrypted.xct")
if err != nil {
	return err
}
defer outputFile.Close()

// Stream encryption
err = publicKey.EncryptStream(outputFile, inputFile, true, true)
if err != nil {
	return err
}

// Stream decryption
encryptedFile, err := os.Open("encrypted.xct")
if err != nil {
	return err
}
defer encryptedFile.Close()

decryptedFile, err := os.Create("decrypted.txt")
if err != nil {
	return err
}
defer decryptedFile.Close()

err = secretKey.DecryptStream(decryptedFile, encryptedFile)
if err != nil {
	return err
}

Key Derivation Parameters

For password-based keys, you can customize the Argon2 parameters:

// High-security configuration
secretKey, err := xipher.NewSecretKeyForPasswordAndSpec(
	[]byte("my-password"),
	32,  // iterations (higher = more secure, slower)
	128, // memory in MB (higher = more secure, more memory)
	4,   // threads (higher = faster on multi-core)
)

Format Specifications

## Key Formats

Secret keys are encoded with the "XSK_" prefix followed by base32-encoded data. Public keys are encoded with the "XPK_" prefix followed by base32-encoded data.

## Ciphertext Format

Encrypted data can be output in two formats: • Binary format: Raw encrypted bytes • Encoded format: "XCT_" prefix + base32-encoded encrypted data

The encoded format is human-readable and safe for text-based transmission.

Security Considerations

• Use strong passwords for password-based keys (consider using passphrases) • Store direct keys securely (they cannot be recovered if lost) • Consider using post-quantum cryptography for long-term security • Use compression carefully (it may leak information about plaintext patterns) • Validate all inputs when parsing keys or ciphertext from external sources

Error Handling

The package defines several specific error types for different failure modes: • errInvalidPassword: Empty or invalid password provided • errInvalidCiphertext: Malformed ciphertext data • errInvalidPublicKey: Invalid public key format • errInvalidSecretKey: Invalid secret key format • errDecryptionFailedPwdRequired: Password required for decryption • errDecryptionFailedKeyRequired: Direct key required for decryption

Performance Notes

• Stream processing is more memory-efficient for large data • Compression reduces ciphertext size but adds CPU overhead • Post-quantum cryptography increases key sizes and processing time • Password-based key derivation is intentionally slow for security

Compatibility

Xipher maintains backward compatibility for encrypted data. Newer versions can decrypt data encrypted with older versions, but older versions may not support features introduced in newer versions (like post-quantum cryptography).

Example (BasicPasswordEncryption)

Example_basicPasswordEncryption demonstrates basic password-based encryption and decryption.

// Create a secret key from password
secretKey, err := NewSecretKeyForPassword([]byte("my-secure-password"))
if err != nil {
	log.Fatal(err)
}

// Generate public key for encryption
publicKey, err := secretKey.PublicKey(false)
if err != nil {
	log.Fatal(err)
}

// Encrypt some data
plaintext := []byte("Hello, World!")
ciphertext, err := publicKey.Encrypt(plaintext, true, true)
if err != nil {
	log.Fatal(err)
}

// Decrypt the data
decrypted, err := secretKey.Decrypt(ciphertext)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Original: %s\n", plaintext)
fmt.Printf("Decrypted: %s\n", decrypted)
Output:

Original: Hello, World!
Decrypted: Hello, World!
Example (CustomKDFParameters)

Example_customKDFParameters demonstrates using custom Argon2 parameters for key derivation.

password := []byte("my-password")

// Low-security, fast configuration (for testing)
fastKey, err := NewSecretKeyForPasswordAndSpec(password, 1, 8, 1)
if err != nil {
	log.Fatal(err)
}

// High-security configuration
secureKey, err := NewSecretKeyForPasswordAndSpec(password, 32, 128, 4)
if err != nil {
	log.Fatal(err)
}

// Both keys work for encryption/decryption
testData := []byte("test message")

// Test fast key
fastPubKey, _ := fastKey.PublicKey(false)
fastCiphertext, _ := fastPubKey.Encrypt(testData, true, true)
fastDecrypted, _ := fastKey.Decrypt(fastCiphertext)

// Test secure key
securePubKey, _ := secureKey.PublicKey(false)
secureCiphertext, _ := securePubKey.Encrypt(testData, true, true)
secureDecrypted, _ := secureKey.Decrypt(secureCiphertext)

fmt.Printf("Fast key works: %t\n", bytes.Equal(testData, fastDecrypted))
fmt.Printf("Secure key works: %t\n", bytes.Equal(testData, secureDecrypted))
fmt.Printf("Different ciphertexts: %t\n", !bytes.Equal(fastCiphertext, secureCiphertext))
Output:

Fast key works: true
Secure key works: true
Different ciphertexts: true
Example (DirectKeyGeneration)

Example_directKeyGeneration demonstrates generating and using direct (non-password-based) keys.

// Generate a random secret key
secretKey, err := NewSecretKey()
if err != nil {
	log.Fatal(err)
}

// Export key as string for storage
keyString, err := secretKey.String()
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Key starts with: %s\n", keyString[:4])

// Later, import the key from string
importedKey, err := ParseSecretKeyStr(keyString)
if err != nil {
	log.Fatal(err)
}

// Use the imported key
publicKey, err := importedKey.PublicKey(false)
if err != nil {
	log.Fatal(err)
}

// Test encryption/decryption
plaintext := []byte("Test message")
ciphertext, err := publicKey.Encrypt(plaintext, true, true)
if err != nil {
	log.Fatal(err)
}

decrypted, err := importedKey.Decrypt(ciphertext)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Encryption works: %t\n", bytes.Equal(plaintext, decrypted))
Output:

Key starts with: XSK_
Encryption works: true
Example (FileEncryption)

Example_fileEncryption demonstrates encrypting and decrypting files.

// Create a temporary file with test data
tempFile, err := os.CreateTemp("", "xipher_test_*.txt")
if err != nil {
	log.Fatal(err)
}
defer os.Remove(tempFile.Name())

testData := "This is test file content for encryption."
tempFile.WriteString(testData)
tempFile.Close()

// Create secret key
secretKey, err := NewSecretKeyForPassword([]byte("file-password"))
if err != nil {
	log.Fatal(err)
}

publicKey, err := secretKey.PublicKey(false)
if err != nil {
	log.Fatal(err)
}

// Encrypt file
inputFile, err := os.Open(tempFile.Name())
if err != nil {
	log.Fatal(err)
}
defer inputFile.Close()

encryptedFile, err := os.CreateTemp("", "xipher_encrypted_*.xct")
if err != nil {
	log.Fatal(err)
}
defer os.Remove(encryptedFile.Name())
defer encryptedFile.Close()

err = publicKey.EncryptStream(encryptedFile, inputFile, true, true)
if err != nil {
	log.Fatal(err)
}
encryptedFile.Close()

// Decrypt file
encryptedFile, err = os.Open(encryptedFile.Name())
if err != nil {
	log.Fatal(err)
}
defer encryptedFile.Close()

decryptedFile, err := os.CreateTemp("", "xipher_decrypted_*.txt")
if err != nil {
	log.Fatal(err)
}
defer os.Remove(decryptedFile.Name())
defer decryptedFile.Close()

err = secretKey.DecryptStream(decryptedFile, encryptedFile)
if err != nil {
	log.Fatal(err)
}
decryptedFile.Close()

// Verify content
decryptedContent, err := os.ReadFile(decryptedFile.Name())
if err != nil {
	log.Fatal(err)
}

fmt.Printf("File encryption successful: %t\n", string(decryptedContent) == testData)
Output:

File encryption successful: true
Example (KeyValidation)

Example_keyValidation demonstrates validating key and ciphertext strings.

// Generate a secret key
secretKey, err := NewSecretKey()
if err != nil {
	log.Fatal(err)
}

keyString, _ := secretKey.String()
publicKey, _ := secretKey.PublicKey(false)
pubKeyString, _ := publicKey.String()

// Encrypt some data
ciphertext, _ := publicKey.Encrypt([]byte("test"), true, true)
ciphertextString := string(ciphertext)

// Validate formats
fmt.Printf("Valid secret key: %t\n", IsSecretKeyStr(keyString))
fmt.Printf("Valid public key: %t\n", IsPubKeyStr(pubKeyString))
fmt.Printf("Valid ciphertext: %t\n", IsCTStr(ciphertextString))

// Test invalid formats
fmt.Printf("Invalid secret key: %t\n", IsSecretKeyStr("invalid"))
fmt.Printf("Invalid public key: %t\n", IsPubKeyStr("invalid"))
fmt.Printf("Invalid ciphertext: %t\n", IsCTStr("invalid"))
Output:

Valid secret key: true
Valid public key: true
Valid ciphertext: true
Invalid secret key: false
Invalid public key: false
Invalid ciphertext: false
Example (PostQuantumCryptography)

Example_postQuantumCryptography demonstrates using post-quantum cryptography.

// Create secret key
secretKey, err := NewSecretKeyForPassword([]byte("quantum-safe-password"))
if err != nil {
	log.Fatal(err)
}

// Generate post-quantum public key (Kyber1024)
pqPublicKey, err := secretKey.PublicKey(true) // true enables post-quantum
if err != nil {
	log.Fatal(err)
}

// Generate standard ECC public key for comparison
eccPublicKey, err := secretKey.PublicKey(false) // false uses ECC
if err != nil {
	log.Fatal(err)
}

// Get key sizes
pqKeyBytes, _ := pqPublicKey.Bytes()
eccKeyBytes, _ := eccPublicKey.Bytes()

fmt.Printf("Post-quantum key is larger: %t\n", len(pqKeyBytes) > len(eccKeyBytes))

// Encrypt with post-quantum cryptography
plaintext := []byte("quantum-safe message")
ciphertext, err := pqPublicKey.Encrypt(plaintext, true, true)
if err != nil {
	log.Fatal(err)
}

// Decrypt with the same secret key
decrypted, err := secretKey.Decrypt(ciphertext)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Post-quantum encryption works: %t\n", bytes.Equal(plaintext, decrypted))
Output:

Post-quantum key is larger: true
Post-quantum encryption works: true
Example (StreamProcessing)

Example_streamProcessing demonstrates efficient stream processing for large data.

// Create secret key
secretKey, err := NewSecretKeyForPassword([]byte("stream-password"))
if err != nil {
	log.Fatal(err)
}

// Generate public key
publicKey, err := secretKey.PublicKey(false)
if err != nil {
	log.Fatal(err)
}

// Simulate large data with a string reader
largeData := strings.Repeat("This is a large file content. ", 1000)
dataReader := strings.NewReader(largeData)

// Encrypt using stream processing
var encryptedBuffer bytes.Buffer
err = publicKey.EncryptStream(&encryptedBuffer, dataReader, true, true)
if err != nil {
	log.Fatal(err)
}

// Decrypt using stream processing
var decryptedBuffer bytes.Buffer
err = secretKey.DecryptStream(&decryptedBuffer, &encryptedBuffer)
if err != nil {
	log.Fatal(err)
}

// Verify the data
decryptedData := decryptedBuffer.String()
fmt.Printf("Stream processing successful: %t\n", largeData == decryptedData)
fmt.Printf("Original size: %d bytes\n", len(largeData))
fmt.Printf("Encrypted data is smaller due to compression: %t\n", encryptedBuffer.Len() < len(largeData))
Output:

Stream processing successful: true
Original size: 30000 bytes
Encrypted data is smaller due to compression: true
Example (SymmetricEncryption)

Example_symmetricEncryption demonstrates using secret keys for symmetric encryption.

// Create secret key
secretKey, err := NewSecretKeyForPassword([]byte("symmetric-password"))
if err != nil {
	log.Fatal(err)
}

// Encrypt directly with secret key (symmetric mode)
plaintext := []byte("Symmetric encryption is faster!")
ciphertext, err := secretKey.Encrypt(plaintext, true, true)
if err != nil {
	log.Fatal(err)
}

// Decrypt with the same secret key
decrypted, err := secretKey.Decrypt(ciphertext)
if err != nil {
	log.Fatal(err)
}

fmt.Printf("Symmetric encryption works: %t\n", bytes.Equal(plaintext, decrypted))
Output:

Symmetric encryption works: true

Index

Examples

Constants

This section is empty.

Variables

View Source
var (

	// Info contains application metadata and build information.
	// This structure is populated at build time and provides runtime
	// access to version, build details, and platform information.
	Info = struct {
		AppName     string `json:"appName"`     // Application name
		AppNameLC   string `json:"appNameLC"`   // Application name in lowercase
		Art         string `json:"art"`         // ASCII art logo
		Description string `json:"description"` // Application description
		Version     string `json:"version"`     // Version string
		BuiltAt     string `json:"builtAt"`     // Build timestamp
		ReleaseURL  string `json:"releaseURL"`  // Release URL
		FullCommit  string `json:"fullCommit"`  // Full commit hash
		Web         string `json:"web"`         // Website URL
		Platform    string `json:"platform"`    // Target platform (OS/architecture)
		GoVersion   string `json:"goVersion"`   // Go version used for building
	}{
		AppName:     appName,
		AppNameLC:   appNameLowerCase,
		Art:         art,
		Description: description,
		Version:     version,
		BuiltAt:     commitDate,
		ReleaseURL:  releaseURL,
		FullCommit:  fullCommit,
		Web:         web,
		Platform:    runtime.GOOS + "/" + runtime.GOARCH,
		GoVersion:   runtime.Version(),
	}
)

Build-time variables set by the build system.

Functions

func IsCTStr added in v1.13.0

func IsCTStr(str string) bool

IsCTStr validates whether a string is a properly formatted ciphertext string. It checks if the string starts with the xipher ciphertext prefix "XCT_".

Parameters:

  • str: String to validate

Returns true if the string appears to be xipher-encoded ciphertext.

Example:

if xipher.IsCTStr(ciphertext) {
	// This is xipher-encoded ciphertext
	decrypted, err := secretKey.Decrypt([]byte(ciphertext))
}

func IsPubKeyStr added in v1.13.0

func IsPubKeyStr(pubKeyStr string) bool

IsPubKeyStr validates whether a string is a properly formatted public key string. It checks the format but does not validate the cryptographic content.

Parameters:

  • pubKeyStr: String to validate

Returns true if the string matches the expected public key format.

Example:

if xipher.IsPubKeyStr(keyString) {
	publicKey, err := xipher.ParsePublicKeyStr(keyString)
	// ...
}

func IsSecretKeyStr added in v1.13.0

func IsSecretKeyStr(secretKeyStr string) bool

IsSecretKeyStr validates whether a string is a properly formatted secret key string. It checks the format but does not validate the cryptographic content.

Parameters:

  • secretKeyStr: String to validate

Returns true if the string matches the expected secret key format.

Example:

if xipher.IsSecretKeyStr(keyString) {
	secretKey, err := xipher.ParseSecretKeyStr(keyString)
	// ...
}

Types

type PublicKey

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

PublicKey represents a cryptographic public key for asymmetric encryption. It contains the actual public key material and associated metadata.

func ParsePublicKey

func ParsePublicKey(pubKeyBytes []byte) (*PublicKey, error)

ParsePublicKey parses a public key from its binary representation. It supports both direct and password-based public keys.

Parameters:

  • pubKeyBytes: Binary representation of the public key

Returns an error if the format is invalid or parsing fails.

Example:

publicKey, err := xipher.ParsePublicKey(keyBytes)
if err != nil {
	return err
}

func ParsePublicKeyStr added in v1.13.0

func ParsePublicKeyStr(pubKeyStr string) (*PublicKey, error)

ParsePublicKeyStr parses a public key from its string representation. The string must have the correct prefix and format (base32 encoded).

Parameters:

  • pubKeyStr: String representation of the public key (e.g., "XPK_...")

Returns an error if the string format is invalid or decoding fails.

Example:

publicKey, err := xipher.ParsePublicKeyStr("XPK_ABCDEF...")
if err != nil {
	return err
}

func (*PublicKey) Bytes

func (publicKey *PublicKey) Bytes() ([]byte, error)

Bytes returns the binary representation of the public key. The format includes version, type, and optionally KDF specification, followed by the actual public key material.

Returns an error if serialization fails.

Example:

pubKeyBytes, err := publicKey.Bytes()
if err != nil {
	return err
}
// Store or transmit pubKeyBytes

func (*PublicKey) Encrypt

func (publicKey *PublicKey) Encrypt(data []byte, compress, encode bool) (ciphertext []byte, err error)

Encrypt encrypts the given data using the public key in asymmetric mode. This is a convenience method for encrypting small amounts of data in memory.

Parameters:

  • data: Plaintext data to encrypt
  • compress: If true, compresses data before encryption (reduces size)
  • encode: If true, base32-encodes the output with "XCT_" prefix

Returns the encrypted ciphertext or an error if encryption fails.

Example:

plaintext := []byte("Hello, World!")
ciphertext, err := publicKey.Encrypt(plaintext, true, true)
if err != nil {
	return err
}
// ciphertext is now encrypted and optionally compressed/encoded

func (*PublicKey) EncryptStream

func (publicKey *PublicKey) EncryptStream(dst io.Writer, src io.Reader, compress, encode bool) (err error)

EncryptStream encrypts data from src and writes the encrypted result to dst using the public key in asymmetric mode. This is efficient for large data streams.

Parameters:

  • dst: Destination writer for encrypted output
  • src: Source reader for plaintext input
  • compress: If true, compresses data before encryption (reduces size)
  • encode: If true, base32-encodes the output with "XCT_" prefix

Returns an error if encryption fails at any stage.

Example:

file, _ := os.Open("largefile.txt")
defer file.Close()
var encrypted bytes.Buffer
err := publicKey.EncryptStream(&encrypted, file, true, true)

func (*PublicKey) NewEncryptingWriter

func (publicKey *PublicKey) NewEncryptingWriter(dst io.Writer, compress, encode bool) (writer io.WriteCloser, err error)

NewEncryptingWriter creates a streaming writer that encrypts data using the public key in asymmetric mode. The writer encrypts data as it's written and outputs the result to dst.

Parameters:

  • dst: Destination writer for encrypted output
  • compress: If true, compresses data before encryption (reduces size)
  • encode: If true, base32-encodes the output with "XCT_" prefix

Returns a WriteCloser that must be closed to finalize encryption. The Close() method is essential for proper encryption completion.

Example:

var buf bytes.Buffer
writer, err := publicKey.NewEncryptingWriter(&buf, true, true)
if err != nil {
	return err
}
writer.Write([]byte("Hello, World!"))
writer.Close() // Essential for proper encryption
ciphertext := buf.Bytes()

func (*PublicKey) String added in v1.13.0

func (publicKey *PublicKey) String() (string, error)

String returns the string representation of the public key. The string format is base32-encoded with the "XPK_" prefix.

Returns an error if serialization fails.

Example:

pubKeyString, err := publicKey.String()
if err != nil {
	return err
}
fmt.Println("Public key:", pubKeyString) // XPK_ABCDEF...

type SecretKey

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

SecretKey represents a cryptographic secret key that can be either password-based or directly generated from random data. It supports both symmetric and asymmetric encryption operations and maintains internal state for efficient key derivation.

func NewSecretKey

func NewSecretKey() (*SecretKey, error)

NewSecretKey creates a new secret key from cryptographically secure random data. This type of key is not password-based and provides maximum entropy. It's suitable for applications where key management is handled separately.

The generated key is 64 bytes of cryptographically secure random data.

Returns an error if random number generation fails.

Example:

secretKey, err := xipher.NewSecretKey()
if err != nil {
	return err
}
// Save the key for later use
keyString, _ := secretKey.String()

func NewSecretKeyForPassword

func NewSecretKeyForPassword(password []byte) (*SecretKey, error)

NewSecretKeyForPassword creates a new secret key derived from the given password. It uses default KDF parameters for key derivation (16 iterations, 64MB memory, 1 thread).

This is the most common way to create a secret key for password-based encryption. The resulting key can be used for both symmetric and asymmetric operations.

Parameters:

  • password: The password to derive the key from (must not be empty)

Returns an error if the password is empty or key derivation fails.

Example:

secretKey, err := xipher.NewSecretKeyForPassword([]byte("my-secure-password"))
if err != nil {
	return err
}

func NewSecretKeyForPasswordAndSpec

func NewSecretKeyForPasswordAndSpec(password []byte, iterations, memory, threads uint8) (*SecretKey, error)

NewSecretKeyForPasswordAndSpec creates a new secret key with custom KDF parameters. This allows fine-tuning of the key derivation process for specific security or performance requirements.

Parameters:

  • password: The password to derive the key from (must not be empty)
  • iterations: Number of Argon2 iterations (higher = more secure, slower)
  • memory: Memory usage in MB (higher = more secure, more memory)
  • threads: Number of parallel threads (higher = faster on multi-core systems)

Returns an error if any parameter is invalid or key derivation fails.

Example:

// High-security configuration: more iterations and memory
secretKey, err := xipher.NewSecretKeyForPasswordAndSpec(
	[]byte("my-secure-password"), 32, 128, 4)

func ParseSecretKey

func ParseSecretKey(key []byte) (*SecretKey, error)

ParseSecretKey parses a secret key from its binary representation. The key must be exactly secretKeyLength bytes and have the correct format.

Parameters:

  • key: Binary representation of the secret key

Returns an error if the key format is invalid or the length is incorrect. Only supports direct (non-password-based) keys.

func ParseSecretKeyStr added in v1.13.0

func ParseSecretKeyStr(secretKeyStr string) (*SecretKey, error)

ParseSecretKeyStr parses a secret key from its string representation. The string must have the correct prefix and format (base32 encoded).

Parameters:

  • secretKeyStr: String representation of the secret key (e.g., "XSK_...")

Returns an error if the string format is invalid or decoding fails.

Example:

secretKey, err := xipher.ParseSecretKeyStr("XSK_ABCDEF...")
if err != nil {
	return err
}

func SecretKeyFromSeed added in v1.16.0

func SecretKeyFromSeed(seed [secretKeyBaseLength]byte) (*SecretKey, error)

SecretKeyFromSeed creates a new secret key from the given 64-byte seed. This allows creating deterministic keys from known seed material.

Parameters:

  • seed: Exactly 64 bytes of seed material

The seed should be cryptographically secure random data or derived from a secure source. This function does not validate the entropy of the seed.

Example:

var seed [64]byte
copy(seed[:], someSecureRandomData)
secretKey, err := xipher.SecretKeyFromSeed(seed)

func (*SecretKey) Bytes

func (secretKey *SecretKey) Bytes() ([]byte, error)

Bytes returns the binary representation of the secret key. This only works for direct (non-password-based) keys, as password-based keys cannot be serialized without compromising security.

The returned bytes include version and type headers followed by the key material.

Returns an error for password-based keys.

Example:

keyBytes, err := secretKey.Bytes()
if err != nil {
	// Handle password-based key or other error
	return err
}
// Store keyBytes securely

func (*SecretKey) Decrypt

func (secretKey *SecretKey) Decrypt(ciphertext []byte) (data []byte, err error)

Decrypt decrypts the given ciphertext and returns the original plaintext. This is a convenience method for decrypting small amounts of data in memory. It automatically handles both base32-encoded and binary ciphertext formats.

Parameters:

  • ciphertext: Encrypted data to decrypt

Returns the decrypted plaintext or an error if decryption fails.

Example:

// Decrypt data encrypted with the corresponding public key
plaintext, err := secretKey.Decrypt(ciphertext)
if err != nil {
	return err
}
fmt.Println("Decrypted:", string(plaintext))

func (*SecretKey) DecryptStream

func (secretKey *SecretKey) DecryptStream(dst io.Writer, src io.Reader) (err error)

DecryptStream decrypts data from src and writes the decrypted result to dst. This is efficient for large encrypted data streams and automatically handles both base32-encoded and binary ciphertext formats.

Parameters:

  • dst: Destination writer for decrypted output
  • src: Source reader containing encrypted data

Returns an error if decryption fails at any stage.

Example:

encryptedFile, _ := os.Open("encrypted.txt")
defer encryptedFile.Close()
decryptedFile, _ := os.Create("decrypted.txt")
defer decryptedFile.Close()
err := secretKey.DecryptStream(decryptedFile, encryptedFile)

func (*SecretKey) Encrypt

func (secretKey *SecretKey) Encrypt(data []byte, compress, encode bool) (ciphertext []byte, err error)

Encrypt encrypts the given data using the secret key in symmetric mode. This is a convenience method for encrypting small amounts of data in memory.

Parameters:

  • data: Plaintext data to encrypt
  • compress: If true, compresses data before encryption (reduces size)
  • encode: If true, base32-encodes the output with "XCT_" prefix

Returns the encrypted ciphertext or an error if encryption fails.

Example:

plaintext := []byte("Hello, World!")
ciphertext, err := secretKey.Encrypt(plaintext, true, true)
if err != nil {
	return err
}
// ciphertext is now encrypted and optionally compressed/encoded

func (*SecretKey) EncryptStream

func (secretKey *SecretKey) EncryptStream(dst io.Writer, src io.Reader, compress, encode bool) (err error)

EncryptStream encrypts data from src and writes the encrypted result to dst using the secret key in symmetric mode. This is efficient for large data streams.

Parameters:

  • dst: Destination writer for encrypted output
  • src: Source reader for plaintext input
  • compress: If true, compresses data before encryption (reduces size)
  • encode: If true, base32-encodes the output with "XCT_" prefix

Returns an error if encryption fails at any stage.

Example:

file, _ := os.Open("largefile.txt")
defer file.Close()
var encrypted bytes.Buffer
err := secretKey.EncryptStream(&encrypted, file, true, true)

func (*SecretKey) NewDecryptingReader

func (secretKey *SecretKey) NewDecryptingReader(src io.Reader) (io.Reader, error)

NewDecryptingReader creates a streaming reader that decrypts data from src. It automatically detects whether the input is base32-encoded (with "XCT_" prefix) or in binary format, and handles both symmetric and asymmetric decryption.

Parameters:

  • src: Source reader containing encrypted data

Returns a reader that provides decrypted plaintext data.

Example:

encryptedFile, _ := os.Open("encrypted.txt")
defer encryptedFile.Close()
decryptedReader, err := secretKey.NewDecryptingReader(encryptedFile)
if err != nil {
	return err
}
// Read decrypted data from decryptedReader
plaintext, _ := io.ReadAll(decryptedReader)

func (*SecretKey) NewEncryptingWriter

func (secretKey *SecretKey) NewEncryptingWriter(dst io.Writer, compress, encode bool) (writer io.WriteCloser, err error)

NewEncryptingWriter creates a streaming writer that encrypts data using the secret key in symmetric mode. The writer encrypts data as it's written and outputs the result to dst.

Parameters:

  • dst: Destination writer for encrypted output
  • compress: If true, compresses data before encryption (reduces size)
  • encode: If true, base32-encodes the output with "XCT_" prefix

Returns a WriteCloser that must be closed to finalize encryption. The Close() method is essential for proper encryption completion.

Example:

var buf bytes.Buffer
writer, err := secretKey.NewEncryptingWriter(&buf, true, true)
if err != nil {
	return err
}
writer.Write([]byte("Hello, World!"))
writer.Close() // Essential for proper encryption
ciphertext := buf.Bytes()

func (*SecretKey) PublicKey

func (secretKey *SecretKey) PublicKey(pq bool) (*PublicKey, error)

PublicKey derives the public key corresponding to this secret key. The public key can be used for encryption, while the secret key is needed for decryption.

Parameters:

  • pq: If true, uses post-quantum cryptography (Kyber1024); if false, uses ECC

Post-quantum cryptography provides resistance against quantum computer attacks but results in larger key sizes and ciphertext.

Returns an error if key derivation fails.

Example:

// Standard ECC public key
pubKey, err := secretKey.PublicKey(false)

// Post-quantum public key
pqPubKey, err := secretKey.PublicKey(true)

func (*SecretKey) String added in v1.13.0

func (secretKey *SecretKey) String() (string, error)

String returns the string representation of the secret key. The string format is base32-encoded with the "XSK_" prefix. This only works for direct (non-password-based) keys.

Returns an error for password-based keys.

Example:

keyString, err := secretKey.String()
if err != nil {
	return err
}
fmt.Println("Secret key:", keyString) // XSK_ABCDEF...

Source Files

  • xipher_commons.go
  • xipher_const.go
  • xipher_crypto.go
  • xipher_doc.go
  • xipher_kdf.go
  • xipher_keys.go

Directories

Path Synopsis
internal
cli command
sharedlib command
wasm command

Jump to

Keyboard shortcuts

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