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:
+11
-1
@@ -79,10 +79,20 @@ func (c *Client) getKeySigner() (cryptossh.Signer, error) {
|
||||
return nil, fmt.Errorf("failed to read key file %s: %w", keyPath, err)
|
||||
}
|
||||
|
||||
// Parse the key (support passphrase-protected keys in Phase 2)
|
||||
// Parse the key (support passphrase-protected keys)
|
||||
var signer cryptossh.Signer
|
||||
if c.host.Auth.Password != "" {
|
||||
signer, err = cryptossh.ParsePrivateKeyWithPassphrase(keyData, []byte(c.host.Auth.Password))
|
||||
} else if c.passphraseCallback != nil {
|
||||
// Try without passphrase first
|
||||
signer, err = cryptossh.ParsePrivateKey(keyData)
|
||||
if err != nil && strings.Contains(err.Error(), "encrypted") {
|
||||
// Key is encrypted, prompt for passphrase
|
||||
passphrase := c.passphraseCallback()
|
||||
if passphrase != "" {
|
||||
signer, err = cryptossh.ParsePrivateKeyWithPassphrase(keyData, []byte(passphrase))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
signer, err = cryptossh.ParsePrivateKey(keyData)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user