Skip to content

Instantly share code, notes, and snippets.

@aditya-r-m
Last active May 18, 2025 05:44
Show Gist options
  • Select an option

  • Save aditya-r-m/9e41cec4cd4629f6e7335164a2d8ae71 to your computer and use it in GitHub Desktop.

Select an option

Save aditya-r-m/9e41cec4cd4629f6e7335164a2d8ae71 to your computer and use it in GitHub Desktop.
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"crypto/sha256"
"fmt"
"io"
"os"
"regexp"
"slices"
"strings"
)
func main() {
fmt.Print("\n\033[1;34mPasskey : \033[0m")
var keyString string
fmt.Scan(&keyString)
fmt.Println()
h := sha256.New()
h.Write([]byte(keyString))
key := h.Sum(nil)
file := "./crypt.log";
plainText := ""
cipherText, err := os.ReadFile(file)
if err == nil {
plainText, err = DecryptMessage(key, cipherText)
if err != nil { panic(err) }
}
for {
fmt.Print("\033[1;34mCommand : \033[0m")
var command string
fmt.Scan(&command)
switch command {
case "get":
var arg string
fmt.Scan(&arg)
fmt.Println(strings.Join(regexp.MustCompile(`(?m)^` + arg + `(.*)?\n`).FindAllString(plainText, -1), ""))
case "set":
var argk string
fmt.Scan(&argk)
var argv string
fmt.Scan(&argv)
re := regexp.MustCompile(`(?m)^` + argk + ` (.*)?\n`)
if re.MatchString(plainText) {
plainText = re.ReplaceAllString(plainText, argk + " " + argv + "\n")
} else {
plainText += argk + " " + argv + "\n"
}
lines := strings.Split(plainText, "\n")
lines = lines[:len(lines) - 1]
slices.Sort(lines)
plainText = strings.Join(lines, "\n") + "\n"
fmt.Println()
case "del":
var arg string
fmt.Scan(&arg)
re := regexp.MustCompile(`(?m)^` + arg + ` (.*)?\n`)
plainText = re.ReplaceAllString(plainText, "")
fmt.Println()
case "show":
fmt.Println(plainText)
case "list":
re := regexp.MustCompile(` (.*)?\n`)
fmt.Println(re.ReplaceAllString(plainText, "\n"))
case "save":
cipherText, err := EncryptMessage(key, plainText)
if err != nil { panic(err) }
err = os.WriteFile(file, cipherText, 0644)
if err != nil { panic(err) }
fmt.Println()
case "quit":
fmt.Println()
return
default:
fmt.Println("Invalid Command\n")
}
}
}
func EncryptMessage(key []byte, message string) ([]byte, error) {
byteMsg := []byte(message)
block, err := aes.NewCipher(key)
if err != nil { panic(err) }
cipherText := make([]byte, aes.BlockSize+len(byteMsg))
iv := cipherText[:aes.BlockSize]
_, err = io.ReadFull(rand.Reader, iv)
if err != nil { panic(err) }
// https://pkg.go.dev/crypto/cipher#NewCFBEncrypter
stream := cipher.NewCFBEncrypter(block, iv)
stream.XORKeyStream(cipherText[aes.BlockSize:], byteMsg)
return cipherText, nil
}
func DecryptMessage(key []byte, cipherText []byte) (string, error) {
block, err := aes.NewCipher(key)
if err != nil { panic(err) }
if len(cipherText) < aes.BlockSize {
return "", fmt.Errorf("invalid ciphertext block size")
}
iv := cipherText[:aes.BlockSize]
cipherText = cipherText[aes.BlockSize:]
// https://pkg.go.dev/crypto/cipher#NewCFBDecrypter
stream := cipher.NewCFBDecrypter(block, iv)
stream.XORKeyStream(cipherText, cipherText)
return string(cipherText), nil
}

The attached Go script is a minimal secret management utility to securely note personal data such as usernames & passwords.

The CLI application can be started with a simple go run crypt.go. It provides read-write interface to work with space-separated key value lines using commands get <key-prefix>, set <key> <value>, del <key>, show, list, save, quit.

The application requires a central key on startup, & loads any previously saved data. The plain text & central key stay in process memory, and only AES-256 encrypted cipher text is written to storage. The cipher text can be replicated across devices or uploaded to personal cloud drive.

The code can also be altered slightly to capture encrypted timed logs instead of key-value pairs.

NOTE

  • Ensure that the terminal is not storing any scroll-buffer output on disk.
  • Ensure that iv is randomized appropriately if storing multiple similar plaintext versions.
  • For encrypting simple blobs, gpg is the standard alternative that can be considered.
    • gpg --no-symkey-cache --symmetric --batch --passphrase $KEY $FILE
    • gpg --no-symkey-cache --decrypt --use-embedded-filename --batch --passphrase $KEY $FILE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment