Compare commits

...

8 Commits

Author SHA1 Message Date
akulij
c9cb1bb2d8 README: mark task to add sigpipe handle as done 2025-02-27 22:19:28 +00:00
akulij
5184859c54 handle sigpipe for user friendliness 2025-02-27 22:18:18 +00:00
akulij
bd018136d6 delete sigint handler since it doesn't do anything 2025-02-27 22:13:45 +00:00
akulij
d924708a1c fix: signal handler setter doesn't need to be ran asynchronously 2025-02-27 22:12:13 +00:00
akulij
5f13d1d409 change password input method
in previous method if press ctrl-c during password enter terminal echo
kept off. It was possible to fix it to set `stty echo` in sigint
handler, but this solution is more elegant
2025-02-27 22:07:41 +00:00
akulij
d5192456ce handle sigint 2025-02-27 22:07:30 +00:00
akulij
3161afeb3b README: add task to accept another input as hash 2025-02-27 21:36:40 +00:00
akulij
a873717f17 move flags parsing out of main function 2025-02-27 21:27:36 +00:00
2 changed files with 90 additions and 45 deletions

View File

@ -11,4 +11,5 @@ Exact amount of required characters can be calculated by formula: $\lceil 256 /
## TODO ## TODO
[X] piped/terminal output as raw/verbose [X] piped/terminal output as raw/verbose
[ ] handle broken pipe signal since program will so much depend on pipes [X] handle broken pipe signal since program will so much depend on pipes
[ ] option to read hex number that will be used instead of hash of password (usefull if user already has sha 256 hash of smth or want to use something else as input instead)

View File

@ -7,8 +7,10 @@ import (
"io" "io"
"log" "log"
"os" "os"
"os/signal"
"slices" "slices"
"strconv" "strconv"
"syscall"
"time" "time"
"unsafe" "unsafe"
@ -44,7 +46,76 @@ Each word or number is mapped following this list:
- stupid - no limit - stupid - no limit
` `
type Flags struct {
RawOutput bool
OutputFile string
EntropyLevel int
}
func main() { func main() {
setSystemSignalHandlers()
flags, err := parseFlags()
if err != nil {
errorf("error while parsing arguments: %s\n", err)
}
passbytes, err := getPasswordBytes()
if err != nil {
errorf("Failed to get password, error: %s\n", err)
}
valid := isEntropyValid(passbytes, flags.EntropyLevel)
if !valid {
errorf("You should choose stroger password!!! (or change entropy level, read more with --help)\n")
}
sum := sha256.Sum256(passbytes)
k, err := newX25519IdentityFromScalar(sum[:])
if err != nil {
errorf("internal error: %v", err)
}
// if user is not seeing private keyfile, which also contains public key,
// also duplicate public key it to stderr,
// but if user sees public key via stdout, no need for duplication
if flags.OutputFile != "" {
if !flags.RawOutput {
fmt.Printf("Public key: %s\n", k.Recipient())
} else {
fmt.Printf("%s", k.Recipient())
}
}
output := os.Stdout
if flags.OutputFile != "" {
output, err = os.Create(flags.OutputFile)
if err != nil {
errorf("failed to create output file, error: %s", err)
}
}
err = writeSecretKey(output, k, !flags.RawOutput)
if err != nil {
fmt.Printf("Failed to write secret key to file, error: %s\n", err)
}
}
func setSystemSignalHandlers() {
go handleSigpipe()
}
func handleSigpipe() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGPIPE)
<-c
errorf("Recieved SIGPIPE. Check if your programs that give input or recieve input do not stops before this one")
os.Exit(1)
}
func parseFlags() (*Flags, error) {
log.SetFlags(0) log.SetFlags(0)
flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s", usage) } flag.Usage = func() { fmt.Fprintf(os.Stderr, "%s", usage) }
@ -62,48 +133,14 @@ func main() {
eLevel, err := parseEntropyLevel(entropyLevel) eLevel, err := parseEntropyLevel(entropyLevel)
if err != nil { if err != nil {
errorf("error while parsing --entropy-level argument: %s\n", err) return nil, err
} }
passbytes, err := getPasswordBytes() return &Flags{
if err != nil { RawOutput: rawOutput,
errorf("Failed to get password, error: %s\n", err) OutputFile: outputFile,
} EntropyLevel: eLevel,
valid := isEntropyValid(passbytes, eLevel) }, nil
if !valid {
errorf("You should choose stroger password!!! (or change entropy level, read more with --help)\n")
}
sum := sha256.Sum256(passbytes)
k, err := newX25519IdentityFromScalar(sum[:])
if err != nil {
errorf("internal error: %v", err)
}
// if user is not seeing private keyfile, which also contains public key,
// also duplicate public key it to stderr,
// but if user sees public key via stdout, no need for duplication
if outputFile != "" {
if !rawOutput {
fmt.Printf("Public key: %s\n", k.Recipient())
} else {
fmt.Printf("%s", k.Recipient())
}
}
output := os.Stdout
if outputFile != "" {
output, err = os.Create(outputFile)
if err != nil {
errorf("failed to create output file, error: %s", err)
}
}
err = writeSecretKey(output, k, !rawOutput)
if err != nil {
fmt.Printf("Failed to write secret key to file, error: %s\n", err)
}
} }
func parseEntropyLevel(entropyLevel string) (int, error) { func parseEntropyLevel(entropyLevel string) (int, error) {
@ -134,10 +171,17 @@ func isEntropyValid(passbytes []byte, entropyLevel int) bool {
func getPasswordBytes() ([]byte, error) { func getPasswordBytes() ([]byte, error) {
if term.IsTerminal(int(os.Stdin.Fd())) { if term.IsTerminal(int(os.Stdin.Fd())) {
fmt.Fprintf(os.Stderr, "Enter password: ") oldState, err := term.MakeRaw(0)
passbytes, err := term.ReadPassword(int(os.Stdin.Fd())) defer term.Restore(0, oldState)
fmt.Println()
return passbytes, err screen := struct {
io.Reader
io.Writer
}{os.Stdin, os.Stdout}
t := term.NewTerminal(screen, "")
pass, err := t.ReadPassword("Enter pass: ")
return []byte(pass), err
} else { } else {
return io.ReadAll(os.Stdin) return io.ReadAll(os.Stdin)
} }