Skip to main content

Overview

suSHi takes security seriously. All sensitive credentials are encrypted at rest, authentication is handled securely, and connections use industry-standard encryption protocols. Core Security Principles:
  • Encryption at Rest: All credentials encrypted with AES-256
  • Zero Knowledge: Your master password is never stored
  • Secure Transmission: All connections use TLS/SSL
  • Minimal Privileges: Access controls based on JWT authentication

Encryption Architecture

suSHi uses a multi-layered encryption approach:

Credential Encryption

What Gets Encrypted

The following sensitive data is encrypted before storage:

Private Keys

SSH private key content (RSA, ECDSA, Ed25519)

Passphrases

Private key passphrases for encrypted keys
Not encrypted: Machine names, hostnames, ports, usernames, and organization names. These are considered non-sensitive metadata.

Encryption Algorithm

suSHi uses AES-256-CFB (Advanced Encryption Standard, 256-bit, Cipher Feedback mode):
// Encryption implementation
func EncryptString(text, password, salt string) (string, string, error) {
    // 1. Derive 256-bit key from password using PBKDF2
    key := pbkdf2.Key(
        []byte(password),
        []byte(salt),
        10000,      // Iterations
        32,         // Key length (256 bits)
        sha256.New  // Hash function
    )
    
    // 2. Create AES cipher block
    block, err := aes.NewCipher(key)
    
    // 3. Generate random IV (Initialization Vector)
    iv := make([]byte, aes.BlockSize)
    rand.Read(iv)
    
    // 4. Encrypt using CFB mode
    ciphertext := make([]byte, len(text))
    stream := cipher.NewCFBEncrypter(block, iv)
    stream.XORKeyStream(ciphertext, []byte(text))
    
    // 5. Encode to base64 for storage
    encodedCiphertext := base64.StdEncoding.EncodeToString(ciphertext)
    encodedIV := base64.StdEncoding.EncodeToString(iv)
    
    return encodedCiphertext, encodedIV, nil
}
AES-256: Industry-standard symmetric encryption, proven secureCFB Mode: Stream cipher mode, works well with variable-length dataPBKDF2: Password-based key derivation, slows down brute force attacksRandom IV: Each encrypted value uses unique IV, prevents pattern recognitionBase64 Encoding: Safe text encoding for database storage

Key Derivation with PBKDF2

PBKDF2 (Password-Based Key Derivation Function 2) converts your master password into an encryption key: Parameters:
  • Password: Your master password (provided at connection time)
  • Salt: Unique per-user salt (stored in database)
  • Iterations: 10,000 rounds
  • Key Length: 32 bytes (256 bits)
  • Hash Function: SHA-256
Why 10,000 iterations? Each iteration makes brute force attacks slower. 10,000 is a balance between:
  • Security: Slows down attackers significantly
  • Performance: Fast enough for real-time decryption
  • Compatibility: Well-tested iteration count
Increasing iterations improves security but slows down encryption/decryption. 10,000 is currently recommended by security standards.

Initialization Vectors (IV)

Each encrypted field gets a unique, random IV:
// Generate random IV
iv := make([]byte, aes.BlockSize)  // 16 bytes
rand.Read(iv)                      // Cryptographically secure randomness
Why IVs matter:
  • Encrypting the same data twice produces different ciphertext
  • Prevents pattern analysis attacks
  • Each private key and passphrase has its own IV
Storage:
{
  "private_key": "base64_encrypted_data",
  "iv_private_key": "base64_iv",
  "passphrase": "base64_encrypted_data",
  "iv_passphrase": "base64_iv"
}

Decryption Process

When you connect to a machine:
1

Request Connection

You click Connect on a machine in the dashboard
2

Enter Master Password

You provide your master password (used for decryption)
3

Fetch Encrypted Data

Server retrieves encrypted private key, passphrase, and IVs from database
4

Derive Decryption Key

PBKDF2 derives key from your password and stored salt
5

Decrypt Credentials

AES-256-CFB decrypts the private key and passphrase using derived key and IVs
6

Establish SSH Connection

Decrypted credentials used to connect to remote machine
7

Discard Plaintext

Decrypted credentials exist only in memory during connection, never stored
// Decryption implementation
func DecryptString(encodedCiphertext, encodedIV, password, salt string) (string, error) {
    // 1. Decode base64
    ciphertext, _ := base64.StdEncoding.DecodeString(encodedCiphertext)
    iv, _ := base64.StdEncoding.DecodeString(encodedIV)
    
    // 2. Derive key (same as encryption)
    key := pbkdf2.Key(
        []byte(password),
        []byte(salt),
        10000,
        32,
        sha256.New
    )
    
    // 3. Create cipher
    block, _ := aes.NewCipher(key)
    
    // 4. Decrypt
    plaintext := make([]byte, len(ciphertext))
    stream := cipher.NewCFBDecrypter(block, iv)
    stream.XORKeyStream(plaintext, ciphertext)
    
    return string(plaintext), nil
}
Decryption only happens when you explicitly connect to a machine. Credentials are never decrypted for listing or viewing machines.

Password Security

Master Password

Your master password is critical for security:
suSHi never stores your master password anywhere:
  • Not in database
  • Not in logs
  • Not in session storage
  • Not in cookies
You must enter it each time you connect to a machine.
Lost password = lost accessIf you forget your master password, there’s no recovery mechanism. Your encrypted credentials cannot be decrypted. You’ll need to delete and re-add your machines with new credentials.

Password Best Practices

Use Password Manager

Store your master password in a reputable password manager like 1Password, Bitwarden, or LastPass.

Enable 2FA on OAuth

Use two-factor authentication on your Google/GitHub accounts for additional security.

Rotate Regularly

Change your master password periodically (every 3-6 months).

Unique Per Service

Don’t reuse your master password on any other service.

Authentication Security

JWT Tokens

After OAuth login, suSHi issues JWT (JSON Web Tokens):
{
  "header": {
    "alg": "HS256",
    "typ": "JWT"
  },
  "payload": {
    "username": "[email protected]",
    "exp": 1234567890,
    "iat": 1234564290
  },
  "signature": "..."
}
Token Properties:
  • Stateless: No server-side session storage
  • Signed: HMAC-SHA256 signature prevents tampering
  • Expiring: Tokens expire after set duration
  • Bearer: Sent in Authorization: Bearer <token> header
JWT tokens are signed with a server secret. Tampering with the token invalidates the signature, causing authentication to fail.

Authorization Checks

Every API request validates:
  1. JWT Validity: Token signature and expiration
  2. User Extraction: Username from token payload
  3. Ownership: User owns the requested resource
// Example authorization check
func GetMachine(config Config, w http.ResponseWriter, r *http.Request) {
    // Extract username from JWT
    username, err := utils.GetUsernameFromToken(r)
    if err != nil {
        return http.StatusUnauthorized
    }
    
    // Fetch machine with ownership check
    machine, err := database.GetAMachine(config, machineID, username, "user")
    if err != nil {
        return http.StatusNotFound  // Not found or not authorized
    }
    
    // Return machine
    return machine
}
You can only access machines you own. Cross-user access is prevented by database queries that filter by owner.

Connection Security

TLS/SSL Encryption

All connections to suSHi use TLS 1.2+ encryption:
Web dashboard and API:
  • Encrypted with TLS 1.2 or higher
  • Certificate validation
  • Forward secrecy (ECDHE key exchange)

Network Security

All three connection segments are encrypted:
  1. Browser ↔ suSHi: TLS 1.2+ (HTTPS/WSS)
  2. suSHi ↔ Machine: SSH protocol encryption
  3. End-to-end: No plaintext transmission at any point

Database Security

Encrypted Fields

Credential storage in database:
-- Example machine record
CREATE TABLE machines (
    id INT PRIMARY KEY,
    name VARCHAR(255),              -- Plaintext
    hostname VARCHAR(255),          -- Plaintext
    port VARCHAR(10),               -- Plaintext
    username VARCHAR(255),          -- Plaintext
    private_key TEXT,               -- ENCRYPTED
    iv_private_key VARCHAR(255),    -- IV for private_key
    passphrase TEXT,                -- ENCRYPTED
    iv_passphrase VARCHAR(255),     -- IV for passphrase
    owner_id VARCHAR(255),          -- Plaintext (username/email)
    owner_type VARCHAR(50)          -- Plaintext ('user' or 'org')
);

Access Controls

  • Database Credentials: Stored in environment variables, never in code
  • Connection Pooling: Limited concurrent connections
  • Prepared Statements: Prevents SQL injection
  • Row-level Security: Queries filter by owner

Threat Model & Mitigations

Threat: Attacker gains access to databaseImpact: Attacker gets encrypted credentials but cannot decrypt without master passwordsMitigation:
  • All sensitive data encrypted at rest
  • Master passwords never stored
  • PBKDF2 slows brute force attacks
  • Unique salt per user
Threat: Attacker intercepts network trafficImpact: Cannot decrypt TLS-encrypted trafficMitigation:
  • All connections use TLS 1.2+
  • Certificate validation enforced
  • HSTS headers recommended
  • No plaintext transmission
Threat: Attacker steals JWT tokenImpact: Temporary access until token expiresMitigation:
  • Short-lived tokens (configurable)
  • Secure cookie flags (HttpOnly, Secure)
  • Token rotation on sensitive operations
  • IP-based anomaly detection (recommended)
Threat: Attacker tries many passwordsImpact: Limited by PBKDF2 iterations and rate limitingMitigation:
  • PBKDF2 with 10,000 iterations
  • Rate limiting on authentication endpoints
  • Account lockout after failed attempts
  • Captcha on login (recommended)
Threat: Malicious administratorImpact: Cannot decrypt credentials without master passwordsMitigation:
  • Zero-knowledge architecture
  • Audit logging of all operations
  • Multi-person access controls
  • Regular security audits

Security Best Practices

For Users

1

Strong Master Password

Choose a strong, unique password for encrypting your credentials
2

Enable 2FA

Enable two-factor authentication on your OAuth provider accounts
3

Use SSH Keys

Prefer SSH keys over passwords for machine authentication
4

Rotate Credentials

Regularly update SSH keys and passwords on your machines
5

Log Out

Always log out when done, especially on shared computers
6

Monitor Access

Review access logs periodically for suspicious activity

For Administrators

Keep Updated

Regularly update suSHi to get security patches

Secure Database

Use strong database passwords and restrict network access

Enable Logging

Log all authentication and access attempts

Backup Encrypted

Encrypt database backups and store securely

Rate Limiting

Implement rate limiting on all public endpoints

Network Isolation

Run suSHi in isolated network with firewall rules

Compliance & Standards

suSHi’s security measures align with:
  • OWASP Top 10: Protections against common web vulnerabilities
  • NIST Guidelines: Password storage and key derivation
  • PCI DSS: Encryption at rest and in transit (where applicable)
  • GDPR: User data protection and privacy
For compliance documentation or security audit reports, contact your suSHi administrator or vendor.

Reporting Security Issues

If you discover a security vulnerability:
  1. Do not open a public GitHub issue
  2. Email security concerns to the maintainers privately
  3. Provide detailed reproduction steps
  4. Allow reasonable time for fixes before disclosure
Responsible disclosure helps protect all users. Please report security issues privately.

Security Roadmap

Planned security enhancements:
  • Hardware security module (HSM) integration
  • Certificate pinning for mobile apps
  • Audit log dashboard
  • IP allowlisting per machine
  • Biometric authentication options
  • Zero-trust architecture components

Next Steps

OAuth Authentication

Learn how to sign in securely with Google or GitHub

Machine Management

Understand how credentials are stored when adding machines

Build docs developers (and LLMs) love