Sparkle Key Management Guide

This guide covers the management of EdDSA keys used for signing VibeTunnel updates with the Sparkle framework.

Overview

VibeTunnel uses Sparkle’s EdDSA (Ed25519) signatures for secure software updates. This system requires:
  • A private key (kept secret) for signing updates
  • A public key (distributed with the app) for verifying signatures

Key Locations

Public Key

  • Location: VibeTunnel/sparkle-public-ed-key.txt
  • Status: Committed to repository
  • Usage: Embedded in app via SUPublicEDKey in Info.plist
  • Current Value: AGCY8w5vHirVfGGDGc8Szc5iuOqupZSh9pMj/Qs67XI=

Private Key

  • Location: private/sparkle_private_key
  • Status: NOT in version control (in .gitignore)
  • Usage: Required for signing updates during release
  • Format: Base64-encoded key data (no comments or headers)

Initial Setup

For New Team Members

  1. Request Access
    # Contact team lead for secure key transfer
    # Keys are stored in: Dropbox/Backup/Sparkle-VibeTunnel/
    
  2. Install Private Key
    # Create private directory
    mkdir -p private
    
    # Add key file (get content from secure backup)
    echo "BASE64_PRIVATE_KEY_HERE" > private/sparkle_private_key
    
    # Verify it's ignored by git
    git status  # Should not show private/
    
  3. Verify Setup
    # Test signing with your key
    ./build/SourcePackages/artifacts/sparkle/Sparkle/bin/sign_update \
      any_file.dmg \
      -f private/sparkle_private_key
    

For New Projects

  1. Generate New Keys
    # Build Sparkle tools first
    ./scripts/build.sh
    
    # Generate new key pair
    ./build/SourcePackages/artifacts/sparkle/Sparkle/bin/generate_keys
    
  2. Save Keys
    # Copy displayed keys:
    # Private key: [base64 string]
    # Public key: [base64 string]
    
    # Save private key
    mkdir -p private
    echo "PRIVATE_KEY_BASE64" > private/sparkle_private_key
    
    # Save public key
    echo "PUBLIC_KEY_BASE64" > VibeTunnel/sparkle-public-ed-key.txt
    
  3. Update App Configuration
    • Add public key to Info.plist under SUPublicEDKey
    • Commit public key file to repository

Key Security

Best Practices

  1. Never Commit Private Keys
    • Private directory is in .gitignore
    • Double-check before committing
  2. Secure Backup
    • Store in encrypted location
    • Use password manager or secure cloud storage
    • Keep multiple secure backups
  3. Limited Access
    • Only release managers need private key
    • Use secure channels for key transfer
    • Rotate keys if compromised
  4. Key Format
    • Private key file must contain ONLY the base64 key
    • No comments, headers, or extra whitespace
    • Single line of base64 data

Example Private Key Format

SMYPxE98bJ5iLdHTLHTqGKZNFcZLgrT5Hyjh79h3TaU=

Troubleshooting

”EdDSA signature does not match” Error

Cause: Wrong private key or key format issues Solution:
  1. Verify private key matches public key
  2. Check key file has no extra characters
  3. Regenerate appcast with correct key

”Failed to decode base64 encoded key data”

Cause: Private key file contains comments or headers Solution:
# Extract just the key
grep -v '^#' your_key_backup.txt | grep -v '^$' > private/sparkle_private_key

Testing Key Pair Match

# Sign a test file
echo "test" > test.txt
./build/SourcePackages/artifacts/sparkle/Sparkle/bin/sign_update \
  test.txt \
  -f private/sparkle_private_key

# The signature should generate successfully
# Compare with production signatures to verify

Key Rotation

If keys need to be rotated:
  1. Generate New Keys
    ./build/SourcePackages/artifacts/sparkle/Sparkle/bin/generate_keys
    
  2. Update App
    • Change SUPublicEDKey in Info.plist
    • Update sparkle-public-ed-key.txt
    • Release new version with new public key
  3. Transition Period
    • Keep old private key for emergency updates
    • Sign new updates with new key
    • After all users update, retire old key

Integration with Release Process

The release scripts automatically use the private key:
  1. generate-appcast.sh
    • Expects key at private/sparkle_private_key
    • Fails if key missing or invalid
    • Signs all DMG files in releases
  2. release.sh
    • Calls generate-appcast.sh after creating DMG
    • Ensures signatures are created before pushing

Recovery Procedures

Lost Private Key

If private key is lost:
  1. Generate new key pair
  2. Update app with new public key
  3. Release update signed with old key (if possible)
  4. All future updates use new key

Compromised Private Key

If private key is compromised:
  1. Generate new key pair immediately
  2. Release security update with new public key
  3. Notify users of security update
  4. Revoke compromised key (document publicly)

Verification Commands

Verify Current Setup

# Check public key in app
/usr/libexec/PlistBuddy -c "Print :SUPublicEDKey" \
  build/Build/Products/Release/VibeTunnel.app/Contents/Info.plist

# Check private key exists
ls -la private/sparkle_private_key

# Test signing
./scripts/generate-appcast.sh --dry-run

Verify Release Signatures

# Check signature in appcast
grep "sparkle:edSignature" appcast-prerelease.xml

# Manually verify a DMG
./build/SourcePackages/artifacts/sparkle/Sparkle/bin/sign_update \
  build/VibeTunnel-1.0.0.dmg \
  -f private/sparkle_private_key

Additional Resources


For questions about key management, contact the release team lead.