Documentation
¶
Overview ¶
Package cryptohelpers provides utilities for loading and handling cryptographic keys used for Ed25519 signing and Curve25519 encryption in the ppatcher system.
Example ¶
Example demonstrates a complete workflow: sign, encrypt, decrypt, and verify.
package main
import (
"crypto/ed25519"
"crypto/rand"
"fmt"
"golang.org/x/crypto/nacl/box"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate Ed25519 keys for signing
signPub, signPriv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Generate Curve25519 keys for encryption
encPub, encPriv, err := box.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Original message
message := []byte("Secure message")
// Step 1: Sign the message
signature := cryptohelpers.SignPayload(signPriv, message)
fmt.Printf("1. Message signed (%d bytes)\n", len(signature))
// Step 2: Create a bundle (message + signature)
bundle := append(message, signature...)
fmt.Printf("2. Bundle created (%d bytes)\n", len(bundle))
// Step 3: Encrypt the bundle
encrypted := cryptohelpers.EncryptBundle(bundle, encPub)
fmt.Printf("3. Bundle encrypted (%d bytes)\n", len(encrypted))
// Step 4: Decrypt the bundle
decrypted, err := cryptohelpers.DecryptBundle(encrypted, encPriv)
if err != nil {
panic(err)
}
fmt.Printf("4. Bundle decrypted (%d bytes)\n", len(decrypted))
// Step 5: Split the bundle
extractedMessage, extractedSignature, err := cryptohelpers.SplitBundle(decrypted)
if err != nil {
panic(err)
}
fmt.Printf("5. Bundle split (message: %d bytes, signature: %d bytes)\n",
len(extractedMessage), len(extractedSignature))
// Step 6: Verify the signature
valid := cryptohelpers.VerifyPayload(signPub, extractedMessage, extractedSignature)
fmt.Printf("6. Signature verified: %v\n", valid)
fmt.Printf("7. Message: %s\n", extractedMessage)
}
Output: 1. Message signed (64 bytes) 2. Bundle created (78 bytes) 3. Bundle encrypted (150 bytes) 4. Bundle decrypted (78 bytes) 5. Bundle split (message: 14 bytes, signature: 64 bytes) 6. Signature verified: true 7. Message: Secure message
Index ¶
- func DecryptBundle(blob []byte, recipientPriv *[32]byte) ([]byte, error)
- func EncryptBundle(bundle []byte, recipientPub *[32]byte) []byte
- func LoadCurve25519Private(path string) *[32]byte
- func LoadCurve25519Public(path string) *[32]byte
- func LoadEd25519Private(path string) ed25519.PrivateKey
- func LoadEd25519Public(path string) ed25519.PublicKey
- func SignPayload(priv ed25519.PrivateKey, payload []byte) []byte
- func SplitBundle(bundle []byte) (payload, signature []byte, err error)
- func VerifyPayload(pub ed25519.PublicKey, payload, signature []byte) bool
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DecryptBundle ¶
DecryptBundle decrypts a blob produced by EncryptBundle.
The blob must contain:
- 24 bytes: nonce
- 32 bytes: ephemeral sender public key
- remaining bytes: ciphertext
The function returns the decrypted plaintext or an error on failure.
Example ¶
ExampleDecryptBundle demonstrates how to decrypt data encrypted with EncryptBundle.
package main
import (
"crypto/rand"
"fmt"
"golang.org/x/crypto/nacl/box"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate recipient key pair
recipientPub, recipientPriv, err := box.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Encrypt some data
originalData := []byte("Confidential information")
encrypted := cryptohelpers.EncryptBundle(originalData, recipientPub)
// Decrypt the data
decrypted, err := cryptohelpers.DecryptBundle(encrypted, recipientPriv)
if err != nil {
panic(err)
}
fmt.Printf("Decrypted: %s\n", decrypted)
fmt.Printf("Match: %v\n", string(decrypted) == string(originalData))
}
Output: Decrypted: Confidential information Match: true
func EncryptBundle ¶
EncryptBundle encrypts a signed bundle using NaCl box (Curve25519 + XSalsa20-Poly1305).
The function automatically generates a new ephemeral key pair and a 24-byte nonce. The output format is:
[24 bytes nonce] | [32 bytes ephemeralPub] | [ciphertext]
The function returns the encrypted blob or panics on failure.
Example ¶
ExampleEncryptBundle demonstrates how to encrypt data using NaCl box.
package main
import (
"crypto/rand"
"fmt"
"golang.org/x/crypto/nacl/box"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate recipient key pair
recipientPub, recipientPriv, err := box.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Encrypt data
data := []byte("Secret message")
encrypted := cryptohelpers.EncryptBundle(data, recipientPub)
fmt.Printf("Original data: %s\n", data)
fmt.Printf("Encrypted size: %d bytes\n", len(encrypted))
// Decrypt data
decrypted, err := cryptohelpers.DecryptBundle(encrypted, recipientPriv)
if err != nil {
panic(err)
}
fmt.Printf("Decrypted data: %s\n", decrypted)
}
Output: Original data: Secret message Encrypted size: 86 bytes Decrypted data: Secret message
func LoadCurve25519Private ¶
LoadCurve25519Private loads a Curve25519 (X25519) private key from a base64-encoded file.
The resulting key must be exactly 32 bytes long. The function returns a pointer to an array suitable for use with nacl/box operations, or panics if the key is invalid or cannot be loaded.
Example ¶
ExampleLoadCurve25519Private demonstrates how to load a Curve25519 private key from a file.
package main
import (
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"golang.org/x/crypto/nacl/box"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate a key pair
_, priv, err := box.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Create a temporary file
tempDir, err := os.MkdirTemp("", "cryptohelpers-example")
if err != nil {
panic(err)
}
defer os.RemoveAll(tempDir)
keyPath := filepath.Join(tempDir, "curve25519_private.key")
// Save the key in base64 format
encoded := base64.StdEncoding.EncodeToString(priv[:])
err = os.WriteFile(keyPath, []byte(encoded), 0600)
if err != nil {
panic(err)
}
// Load the key
loadedKey := cryptohelpers.LoadCurve25519Private(keyPath)
fmt.Printf("Curve25519 private key loaded successfully\n")
fmt.Printf("Key length: %d bytes\n", len(loadedKey))
}
Output: Curve25519 private key loaded successfully Key length: 32 bytes
func LoadCurve25519Public ¶
LoadCurve25519Public loads a Curve25519 (X25519) public key from a base64-encoded file.
The resulting key must be exactly 32 bytes long. The function returns a pointer to an array suitable for nacl/box encryption, or panics if the key is invalid or cannot be loaded.
Example ¶
ExampleLoadCurve25519Public demonstrates how to load a Curve25519 public key from a file.
package main
import (
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"golang.org/x/crypto/nacl/box"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate a key pair
pub, _, err := box.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Create a temporary file
tempDir, err := os.MkdirTemp("", "cryptohelpers-example")
if err != nil {
panic(err)
}
defer os.RemoveAll(tempDir)
keyPath := filepath.Join(tempDir, "curve25519_public.key")
// Save the key in base64 format
encoded := base64.StdEncoding.EncodeToString(pub[:])
err = os.WriteFile(keyPath, []byte(encoded), 0600)
if err != nil {
panic(err)
}
// Load the key
loadedKey := cryptohelpers.LoadCurve25519Public(keyPath)
fmt.Printf("Curve25519 public key loaded successfully\n")
fmt.Printf("Key length: %d bytes\n", len(loadedKey))
}
Output: Curve25519 public key loaded successfully Key length: 32 bytes
func LoadEd25519Private ¶
func LoadEd25519Private(path string) ed25519.PrivateKey
LoadEd25519Private loads an Ed25519 private key from a base64-encoded file.
The file must contain exactly one base64 string representing a 64-byte Ed25519 private key. The function returns an ed25519.PrivateKey or panics on any failure.
Example ¶
ExampleLoadEd25519Private demonstrates how to load an Ed25519 private key from a file.
package main
import (
"crypto/ed25519"
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate a key pair
_, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Create a temporary file
tempDir, err := os.MkdirTemp("", "cryptohelpers-example")
if err != nil {
panic(err)
}
defer os.RemoveAll(tempDir)
keyPath := filepath.Join(tempDir, "ed25519_private.key")
// Save the key in base64 format
encoded := base64.StdEncoding.EncodeToString(priv)
err = os.WriteFile(keyPath, []byte(encoded), 0600)
if err != nil {
panic(err)
}
// Load the key
loadedKey := cryptohelpers.LoadEd25519Private(keyPath)
fmt.Printf("Key loaded successfully\n")
fmt.Printf("Key length: %d bytes\n", len(loadedKey))
}
Output: Key loaded successfully Key length: 64 bytes
func LoadEd25519Public ¶
LoadEd25519Public loads an Ed25519 public key from a base64-encoded file.
The file must contain exactly one base64 string representing a 32-byte Ed25519 public key. The function returns an ed25519.PublicKey or panics on any failure.
Example ¶
ExampleLoadEd25519Public demonstrates how to load an Ed25519 public key from a file.
package main
import (
"crypto/ed25519"
"crypto/rand"
"encoding/base64"
"fmt"
"os"
"path/filepath"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate a key pair
pub, _, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Create a temporary file
tempDir, err := os.MkdirTemp("", "cryptohelpers-example")
if err != nil {
panic(err)
}
defer os.RemoveAll(tempDir)
keyPath := filepath.Join(tempDir, "ed25519_public.key")
// Save the key in base64 format
encoded := base64.StdEncoding.EncodeToString(pub)
err = os.WriteFile(keyPath, []byte(encoded), 0600)
if err != nil {
panic(err)
}
// Load the key
loadedKey := cryptohelpers.LoadEd25519Public(keyPath)
fmt.Printf("Public key loaded successfully\n")
fmt.Printf("Key length: %d bytes\n", len(loadedKey))
}
Output: Public key loaded successfully Key length: 32 bytes
func SignPayload ¶
func SignPayload(priv ed25519.PrivateKey, payload []byte) []byte
SignPayload creates an Ed25519 signature for the provided payload.
The function returns a 64-byte signature. It panics if the private key is invalid. No hashing is required because Ed25519 operates on the message directly.
Example ¶
ExampleSignPayload demonstrates how to sign a message using Ed25519.
package main
import (
"crypto/ed25519"
"crypto/rand"
"fmt"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate a key pair
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Sign a message
message := []byte("Hello, World!")
signature := cryptohelpers.SignPayload(priv, message)
// Verify the signature
valid := cryptohelpers.VerifyPayload(pub, message, signature)
fmt.Printf("Signature valid: %v\n", valid)
fmt.Printf("Signature length: %d bytes\n", len(signature))
}
Output: Signature valid: true Signature length: 64 bytes
func SplitBundle ¶
SplitBundle separates a payload+signature bundle into its components.
The bundle must contain at least one Ed25519 signature (64 bytes) appended to the payload. The function returns payload, signature, or an error if the bundle is malformed.
Example ¶
ExampleSplitBundle demonstrates how to split a payload+signature bundle.
package main
import (
"crypto/ed25519"
"crypto/rand"
"fmt"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate a key pair
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
// Create a signed bundle
payload := []byte("Important data")
signature := cryptohelpers.SignPayload(priv, payload)
bundle := append(payload, signature...)
fmt.Printf("Bundle size: %d bytes\n", len(bundle))
// Split the bundle
extractedPayload, extractedSignature, err := cryptohelpers.SplitBundle(bundle)
if err != nil {
panic(err)
}
fmt.Printf("Payload: %s\n", extractedPayload)
fmt.Printf("Signature length: %d bytes\n", len(extractedSignature))
// Verify the extracted signature
valid := cryptohelpers.VerifyPayload(pub, extractedPayload, extractedSignature)
fmt.Printf("Signature valid: %v\n", valid)
}
Output: Bundle size: 78 bytes Payload: Important data Signature length: 64 bytes Signature valid: true
func VerifyPayload ¶
VerifyPayload checks whether the given Ed25519 signature is valid for a payload.
It returns true for a valid signature and false otherwise. The function does not panic. This method is intended for validating the authenticity of decrypted configuration data.
Example ¶
ExampleVerifyPayload demonstrates how to verify an Ed25519 signature.
package main
import (
"crypto/ed25519"
"crypto/rand"
"fmt"
"github.com/go-extras/cryptohelpers"
)
func main() {
// Generate a key pair
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
message := []byte("Important message")
signature := cryptohelpers.SignPayload(priv, message)
// Verify with correct data
valid := cryptohelpers.VerifyPayload(pub, message, signature)
fmt.Printf("Valid signature: %v\n", valid)
// Verify with tampered data
tamperedMessage := []byte("Tampered message")
valid = cryptohelpers.VerifyPayload(pub, tamperedMessage, signature)
fmt.Printf("Tampered message valid: %v\n", valid)
}
Output: Valid signature: true Tampered message valid: false
Types ¶
This section is empty.