package main import ( "crypto/aes" "crypto/cipher" "crypto/rand" "crypto/sha256" "encoding/base64" "errors" "flag" "fmt" "io" "log" "os" survey "github.com/AlecAivazis/survey/v2" // survey package ) // admin need set env: ENCRYPTION_KEY // the default value: ")ZLxR6X@h5tYGhkwin [options] Options: -action enc|dec -password password (if empty, will be prompted) `) } action := flag.String("action", "", "action to perform: enc or dec") password := flag.String("password", "", "password") flag.Parse() if *action != "enc" && *action != "dec" { fmt.Println("Invalid action. Use -action=enc or -action=dec") os.Exit(1) } // use survey to prompt for missing values var inputPassword string if *password == "" { survey.AskOne(&survey.Password{Message: "Enter password:\n"}, password) inputPassword = *password } inputPassword = *password if *action == "enc" { encryptedPassword, err := Encrypt(inputPassword, "") if err != nil { log.Fatalf("Failed to encrypt password: %v", err) } fmt.Println(encryptedPassword) } if *action == "dec" { realPassword, err := Decrypt(inputPassword, "") if err != nil { log.Fatalf("Failed to decrypt password: %v", err) } fmt.Println(realPassword) } } // use sha256 to get 32 bytes key func getAESKey(key string) []byte { selfSecretKey := os.Getenv("ENCRYPTION_KEY") if selfSecretKey != "" { key = selfSecretKey } else { key = EncryptionKey } hash := sha256.Sum256([]byte(key)) return hash[:] } func Encrypt(plaintext, secret string) (string, error) { key := getAESKey(secret) block, err := aes.NewCipher(key) if err != nil { return "", err } ciphertext := make([]byte, aes.BlockSize+len(plaintext)) iv := ciphertext[:aes.BlockSize] if _, err := io.ReadFull(rand.Reader, iv); err != nil { return "", err } stream := cipher.NewCFBEncrypter(block, iv) stream.XORKeyStream(ciphertext[aes.BlockSize:], []byte(plaintext)) return base64.StdEncoding.EncodeToString(ciphertext), nil } func Decrypt(encryptedText, secret string) (string, error) { key := getAESKey(secret) ciphertext, err := base64.StdEncoding.DecodeString(encryptedText) if err != nil { return "", err } if len(ciphertext) < aes.BlockSize { return "", errors.New("the ciphertext is too short") } iv := ciphertext[:aes.BlockSize] ciphertext = ciphertext[aes.BlockSize:] block, err := aes.NewCipher(key) if err != nil { return "", err } stream := cipher.NewCFBDecrypter(block, iv) stream.XORKeyStream(ciphertext, ciphertext) return string(ciphertext), nil }