Files
sslh-multiplex-lab/internal/ssh/passphrase.go
2026-01-29 00:03:02 +00:00

69 lines
1.7 KiB
Go

package ssh
import (
"crypto/rand"
"fmt"
"math/big"
)
const (
lowercaseChars = "abcdefghijklmnopqrstuvwxyz"
uppercaseChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
digitChars = "0123456789"
// Exclude shell-problematic characters: $ ` \ " '
// $ causes variable expansion, ` is command substitution, \ is escape, " and ' are quotes
// These can cause issues when used in shell commands or when copying from terminal
specialChars = "!@#%^&*()_+-=[]{}|;:,.<>?"
allChars = lowercaseChars + uppercaseChars + digitChars + specialChars
)
func GenerateSecurePassphrase(length int) (string, error) {
if length < 32 {
length = 32
}
passphrase := make([]byte, length)
for i := 0; i < length; i++ {
idx, err := rand.Int(rand.Reader, big.NewInt(int64(len(allChars))))
if err != nil {
return "", fmt.Errorf("failed to generate random character: %w", err)
}
passphrase[i] = allChars[idx.Int64()]
}
passphraseStr := string(passphrase)
if err := validatePassphrase(passphraseStr); err != nil {
return "", fmt.Errorf("generated passphrase failed validation: %w", err)
}
return passphraseStr, nil
}
func validatePassphrase(passphrase string) error {
hasLower := false
hasUpper := false
hasDigit := false
hasSpecial := false
for _, char := range passphrase {
switch {
case 'a' <= char && char <= 'z':
hasLower = true
case 'A' <= char && char <= 'Z':
hasUpper = true
case '0' <= char && char <= '9':
hasDigit = true
default:
hasSpecial = true
}
}
if !hasLower || !hasUpper || !hasDigit || !hasSpecial {
return fmt.Errorf("passphrase must contain at least one lowercase, uppercase, digit, and special character")
}
return nil
}