Compare commits

...

3 Commits

Author SHA1 Message Date
akulij
b47de3e1b6 implement hex/raw input 2025-03-03 00:18:43 +00:00
akulij
9cde36c5c2 rename 'sum' variable that contains hashed password to more appropriate name 'secretKey' 2025-03-03 00:18:43 +00:00
akulij
181ac703ae add --input-type flag 2025-03-03 00:18:37 +00:00

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/hex"
"errors" "errors"
"flag" "flag"
"fmt" "fmt"
@ -10,6 +11,7 @@ import (
"os/signal" "os/signal"
"slices" "slices"
"strconv" "strconv"
"strings"
"syscall" "syscall"
"time" "time"
"unsafe" "unsafe"
@ -33,6 +35,7 @@ Options:
-o, --output OUTPUT Write the result to the file at path OUTPUT. -o, --output OUTPUT Write the result to the file at path OUTPUT.
--raw-output Print stripped keys (without additional text or comments) --raw-output Print stripped keys (without additional text or comments)
--entropy-level VALUE Manages required strenght of password (more info down below) --entropy-level VALUE Manages required strenght of password (more info down below)
--input-type TYPE Type of input from stdin. Can be 'password' (default), 'hash', 'raw'
Mostly similar to age-keygen Mostly similar to age-keygen
Required password strenght can be changes via --entropy-level flag. Possible values Required password strenght can be changes via --entropy-level flag. Possible values
@ -46,10 +49,19 @@ Each word or number is mapped following this list:
- stupid - no limit - stupid - no limit
` `
type InputType int
const (
InputPassword InputType = iota
InputHash
InputRaw
)
type Flags struct { type Flags struct {
RawOutput bool RawOutput bool
OutputFile string OutputFile string
EntropyLevel int EntropyLevel int
InputType InputType
} }
func main() { func main() {
@ -59,18 +71,27 @@ func main() {
errorf("error while parsing arguments: %s\n", err) errorf("error while parsing arguments: %s\n", err)
} }
passbytes, err := getPasswordBytes() var secretKey [curve25519.ScalarSize]byte
if err != nil { if flags.InputType == InputPassword {
errorf("Failed to get password, error: %s\n", err) secretKey, err = getInputPassword(flags.EntropyLevel)
} if err != nil {
valid := isEntropyValid(passbytes, flags.EntropyLevel) errorf("Failed to get password, error: %s\n", err)
if !valid { }
errorf("You should choose stroger password!!! (or change entropy level, read more with --help)\n") } else if flags.InputType == InputHash {
secretKey, err = getInputHash()
if err != nil {
errorf("Failed to read hash, error: %s\n", err)
}
} else if flags.InputType == InputRaw {
secretKey, err = getInputRaw()
if err != nil {
errorf("Failed to read raw data, error: %s\n", err)
}
} else {
errorf("No such input type implemented!!!")
} }
sum := sha256.Sum256(passbytes) k, err := newX25519IdentityFromScalar(secretKey[:])
k, err := newX25519IdentityFromScalar(sum[:])
if err != nil { if err != nil {
errorf("internal error: %v", err) errorf("internal error: %v", err)
} }
@ -100,6 +121,57 @@ func main() {
} }
} }
func getInputPassword(entropyLevel int) ([curve25519.ScalarSize]byte, error) {
passbytes, err := getPasswordBytes()
if err != nil {
return [curve25519.ScalarSize]byte{}, err
}
valid := isEntropyValid(passbytes, entropyLevel)
if !valid {
return [curve25519.ScalarSize]byte{}, errors.New("You should choose stroger password!!! (or change entropy level, read more with --help)\n")
}
return sha256.Sum256(passbytes), nil
}
func getInputHash() ([curve25519.ScalarSize]byte, error) {
hashStringBytes, err := getPasswordBytes()
if err != nil {
return [curve25519.ScalarSize]byte{}, err
}
hashString := strings.TrimSpace(string(hashStringBytes))
passbytes, err := hex.DecodeString(hashString)
if err != nil {
fmt.Printf("HEXSTR:%s|\n", hashString)
return [curve25519.ScalarSize]byte{}, errors.New(fmt.Sprintf("Unable to decode hash, error: %s\n", err))
}
if len(passbytes) != curve25519.ScalarSize {
return [curve25519.ScalarSize]byte{}, errors.New(fmt.Sprintf("Wrong input lenght of sha256 hash! (may be it is not a hash at all) Expected %d bytes, got: %d\n", curve25519.ScalarSize, len(passbytes)))
}
// making `possibly` stack allocated out of the one in heap
var key [curve25519.ScalarSize]byte
copy(key[:], passbytes)
return key, nil
}
func getInputRaw() ([curve25519.ScalarSize]byte, error) {
passbytes, err := getPasswordBytes()
if err != nil {
return [curve25519.ScalarSize]byte{}, err
}
if len(passbytes) != curve25519.ScalarSize {
return [curve25519.ScalarSize]byte{}, errors.New(fmt.Sprintf("Wrong amount of entered data! Expected %d bytes, got: %d\n", curve25519.ScalarSize, len(passbytes)))
}
// making `possibly` stack allocated out of the one in heap
var key [curve25519.ScalarSize]byte
copy(key[:], passbytes)
return key, nil
}
func setSystemSignalHandlers() { func setSystemSignalHandlers() {
go handleSigpipe() go handleSigpipe()
} }
@ -123,12 +195,14 @@ func parseFlags() (*Flags, error) {
rawOutput bool rawOutput bool
outputFile string outputFile string
entropyLevel string entropyLevel string
inputType string
) )
flag.BoolVar(&rawOutput, "raw-output", false, "Print stripped keys (without additional text or comments)") flag.BoolVar(&rawOutput, "raw-output", false, "Print stripped keys (without additional text or comments)")
flag.StringVar(&outputFile, "o", "", "Write the result to the file at path OUTPUT") flag.StringVar(&outputFile, "o", "", "Write the result to the file at path OUTPUT")
flag.StringVar(&outputFile, "output", "", "Write the result to the file at path OUTPUT") flag.StringVar(&outputFile, "output", "", "Write the result to the file at path OUTPUT")
flag.StringVar(&entropyLevel, "entropy-level", "medium", "Manages required strenght of password. Read more in --help") flag.StringVar(&entropyLevel, "entropy-level", "medium", "Manages required strenght of password. Read more in --help")
flag.StringVar(&inputType, "input-type", "password", "Type of input from stdin. Can be 'password' (default), 'hash', 'raw'")
flag.Parse() flag.Parse()
eLevel, err := parseEntropyLevel(entropyLevel) eLevel, err := parseEntropyLevel(entropyLevel)
@ -136,13 +210,34 @@ func parseFlags() (*Flags, error) {
return nil, err return nil, err
} }
iType, err := parseInputType(inputType)
if err != nil {
return nil, err
}
return &Flags{ return &Flags{
RawOutput: rawOutput, RawOutput: rawOutput,
OutputFile: outputFile, OutputFile: outputFile,
EntropyLevel: eLevel, EntropyLevel: eLevel,
InputType: iType,
}, nil }, nil
} }
func parseInputType(inputType string) (InputType, error) {
m := map[string]InputType{
"password": InputPassword,
"hash": InputHash,
"raw": InputRaw,
}
iType, ok := m[inputType]
if !ok {
return InputPassword, errors.New("wrong input type")
}
return iType, nil
}
func parseEntropyLevel(entropyLevel string) (int, error) { func parseEntropyLevel(entropyLevel string) (int, error) {
if i, err := strconv.Atoi(entropyLevel); err == nil { if i, err := strconv.Atoi(entropyLevel); err == nil {
if i == 0 { if i == 0 {