feat: Phase 2 Security Enhancement

- pkg/crypto: AES-256-GCM encryption with PBKDF2 key derivation
  - 100k iterations, 16-byte salt, SHA-256
  - Encrypt/Decrypt/IsEncrypted/HashPassword
- Storage layer encryption:
  - JSONStorage.SetPassword() enables transparent encrypt/decrypt
  - readJSON auto-decrypts, replace* auto-encrypts
- pkg/knownhosts: TOFU host key verification
  - Verify/Add/Remove host keys
  - HostKeyCallback for SSH config
- SSH client security:
  - SetHostKeyCallback() replaces InsecureIgnoreHostKey()
  - SetPassphraseCallback() for encrypted private keys
  - getKeySigner() tries passphrase on encrypted keys
- Models: AppConfig gains EncryptionEnabled, PasswordHash, KnownHostsFile
This commit is contained in:
swanadiva
2026-06-25 13:28:46 +07:00
parent a1cd3d5dc0
commit 611b794fc7
7 changed files with 445 additions and 8 deletions
+22 -5
View File
@@ -18,10 +18,12 @@ import (
// Client represents an SSH client
type Client struct {
host *models.Host
timeout time.Duration
client *cryptossh.Client
config *cryptossh.ClientConfig
host *models.Host
timeout time.Duration
client *cryptossh.Client
config *cryptossh.ClientConfig
hostKeyCallback cryptossh.HostKeyCallback
passphraseCallback func() string // called to get passphrase for encrypted keys
}
// NewClient creates a new SSH client
@@ -32,6 +34,16 @@ func NewClient(host *models.Host, timeout time.Duration) *Client {
}
}
// SetHostKeyCallback sets the host key verification callback
func (c *Client) SetHostKeyCallback(cb cryptossh.HostKeyCallback) {
c.hostKeyCallback = cb
}
// SetPassphraseCallback sets the callback for getting key passphrases
func (c *Client) SetPassphraseCallback(cb func() string) {
c.passphraseCallback = cb
}
// Connect establishes an SSH connection
func (c *Client) Connect(ctx context.Context) error {
// Create SSH configuration
@@ -69,9 +81,14 @@ func (c *Client) dialTCP(ctx context.Context, address string) (net.Conn, error)
// setupConfig creates SSH client configuration
func (c *Client) setupConfig() error {
hostKeyCallback := cryptossh.InsecureIgnoreHostKey()
if c.hostKeyCallback != nil {
hostKeyCallback = c.hostKeyCallback
}
config := &cryptossh.ClientConfig{
User: c.host.Username,
HostKeyCallback: cryptossh.InsecureIgnoreHostKey(), //nolint:gosec // Phase 1 - will be improved in Phase 2
HostKeyCallback: hostKeyCallback,
Timeout: c.timeout,
}