diff options
| -rw-r--r-- | src/scrypt.go | 92 | ||||
| -rwxr-xr-x | tests/cli-opts.sh | 45 | ||||
| -rwxr-xr-x | tests/integration.sh | 16 | ||||
| -rw-r--r-- | tests/scrypt.go | 56 |
4 files changed, 114 insertions, 95 deletions
diff --git a/src/scrypt.go b/src/scrypt.go index 1cb3b44..be00674 100644 --- a/src/scrypt.go +++ b/src/scrypt.go @@ -1,6 +1,7 @@ package scrypt import ( + "bufio" "crypto/rand" "encoding/hex" "flag" @@ -8,6 +9,7 @@ import ( "io" "os" "slices" + "strings" gt "gotext" g "gobang" @@ -54,7 +56,7 @@ type CheckInputT struct{ type argsT struct{ allArgs []string - input HashInputT + isCheck bool } type envT struct{ @@ -168,7 +170,7 @@ func Check(input CheckInputT) (bool, error) { func usage(argv0 string, w io.Writer) { fmt.Fprintf( w, - gt.Gettext("Usage: %s PASSWORD SALT\n"), + gt.Gettext("Usage: %s [-c]\n"), argv0, ) } @@ -177,6 +179,7 @@ func getopt(allArgs []string, w io.Writer) (argsT, int) { argv0 := allArgs[0] argv := allArgs[1:] fs := flag.NewFlagSet("", flag.ContinueOnError) + isCheck := fs.Bool("c", false, "") fs.Usage = func() {} fs.SetOutput(w) @@ -185,34 +188,85 @@ func getopt(allArgs []string, w io.Writer) (argsT, int) { return argsT{}, 2 } - subArgs := fs.Args() - if len(subArgs) != 2 { - usage(argv0, w) - return argsT{}, 2 - } - - password := []byte(subArgs[0]) - salt := []byte(subArgs[1]) - input := HashInputT{ - Password: password, - Salt: salt, - } return argsT{ allArgs: allArgs, - input: input, + isCheck: *isCheck, }, 0 } func run(env envT) int { - payload, err := Hash(env.args.input) + reader := bufio.NewReader(env.in) + + hexPassword, err := reader.ReadString('\n') if err != nil { fmt.Fprintln(env.err, err) - return 1 + return 2 } - fmt.Fprintln(env.out, hex.EncodeToString(payload)) - return 0 + password, err := hex.DecodeString(strings.TrimSpace(hexPassword)) + if err != nil { + fmt.Fprintln(env.err, err) + return 2 + } + + hexSalt, err := reader.ReadString('\n') + if err != nil { + fmt.Fprintln(env.err, err) + return 2 + } + + salt, err := hex.DecodeString(strings.TrimSpace(hexSalt)) + if err != nil { + fmt.Fprintln(env.err, err) + return 2 + } + + if !env.args.isCheck { + input := HashInputT{ + Password: password, + Salt: salt, + } + + payload, err := Hash(input) + if err != nil { + fmt.Fprintln(env.err, err) + return 2 + } + + fmt.Fprintln(env.out, hex.EncodeToString(payload)) + return 0 + } else { + hexHash, err := reader.ReadString('\n') + if err != nil { + fmt.Println(env.err, err) + return 2 + } + + hash, err := hex.DecodeString(strings.TrimSpace(hexHash)) + if err != nil { + fmt.Fprintln(env.err, err) + return 2 + } + + input := CheckInputT{ + Password: password, + Salt: salt, + Hash: hash, + } + + match, err := Check(input) + if err != nil { + fmt.Fprintln(env.err, err) + return 2 + } + + if match { + return 0 + } else { + return 1 + } + } } diff --git a/tests/cli-opts.sh b/tests/cli-opts.sh index 4f59185..92b70ea 100755 --- a/tests/cli-opts.sh +++ b/tests/cli-opts.sh @@ -1,47 +1,2 @@ #!/bin/sh set -eu - -. tests/lib.sh - - -test_needs_2_arguments() { - testing 'needs 2 arguments' - - N="$LINENO" - OUT="$(mkstemp)" - ERR="$(mkstemp)" - trap 'rm -f "$OUT" "$ERR"' EXIT - STATUS=0 - ./scrypt.bin 1>"$OUT" 2>"$ERR" || STATUS=$? - assert_status 2 - assert_empty_stdout - assert_usage "$ERR" - rm -f "$OUT" "$ERR" - - N="$LINENO" - OUT="$(mkstemp)" - ERR="$(mkstemp)" - trap 'rm -f "$OUT" "$ERR"' EXIT - STATUS=0 - ./scrypt.bin password 1>"$OUT" 2>"$ERR" || STATUS=$? - assert_status 2 - assert_empty_stdout - assert_usage "$ERR" - rm -f "$OUT" "$ERR" - - N="$LINENO" - OUT="$(mkstemp)" - ERR="$(mkstemp)" - trap 'rm -f "$OUT" "$ERR"' EXIT - STATUS=0 - ./scrypt.bin salt 1>"$OUT" 2>"$ERR" || STATUS=$? - assert_status 2 - assert_empty_stdout - assert_usage "$ERR" - rm -f "$OUT" "$ERR" - - test_ok -} - - -test_needs_2_arguments diff --git a/tests/integration.sh b/tests/integration.sh index 8115ce5..d8d8dcd 100755 --- a/tests/integration.sh +++ b/tests/integration.sh @@ -12,8 +12,11 @@ test_needs_minimum_salt_length() { ERR="$(mkstemp)" trap 'rm -f "$OUT" "$ERR"' EXIT STATUS=0 - ./scrypt.bin password salt 1>"$OUT" 2>"$ERR" || STATUS=$? - assert_status 1 + PASSWORD='71617373776f7264' + SALT='73616c74' + printf '%s\n%s\n' "$PASSWORD" "$SALT" | + ./scrypt.bin 1>"$OUT" 2>"$ERR" || STATUS=$? + assert_status 2 assert_empty_stdout assert_fgrep_stderr 'salt is too small' rm -f "$OUT" "$ERR" @@ -29,11 +32,12 @@ test_same_input_same_output() { ERR="$(mkstemp)" trap 'rm -f "$OUT" "$ERR"' EXIT STATUS=0 - # 8 16 24 32 - # v v v v - SALT='saltsaltsaltsaltsaltsaltsaltsalti' + PASSWORD='70617373776f7264' + SALT='73616c7473616c7473616c7473616c7473616c7473616c7473616c7473616c74' + SALT="${SALT}69" HASH='969a539633fd531309197c26a671d593da0eadbd31c1194c23bd1b143a0ecb5e' - ./scrypt.bin password "$SALT" 1>"$OUT" 2>"$ERR" || STATUS=$? + printf '%s\n%s\n' "$PASSWORD" "$SALT" | + ./scrypt.bin 1>"$OUT" 2>"$ERR" || STATUS=$? assert_status 0 assert_stdout "$HASH" assert_empty_stderr diff --git a/tests/scrypt.go b/tests/scrypt.go index 0a9f599..2158e64 100644 --- a/tests/scrypt.go +++ b/tests/scrypt.go @@ -309,7 +309,7 @@ func test_usage() { usage("xxx", &w) expected := g.Heredoc(` - Usage: xxx PASSWORD SALT + Usage: xxx [-c] `) g.TAssertEqual(w.String(), expected) }) @@ -319,7 +319,7 @@ func test_getopt() { g.TestStart("getopt()") usage := g.Heredoc(` - Usage: $0 PASSWORD SALT + Usage: $0 [-c] `) g.Testing("we suppress the default error message", func() { @@ -341,17 +341,28 @@ func test_getopt() { g.TAssertEqual(rc, 2) }) - g.Testing("the args have the input data", func() { + g.Testing("the args have the strings untouched", func() { w := strings.Builder{} argv := []string{"$0", "abcdef", "aaaabbbbccccdddd"} args, rc := getopt(argv, &w) expected := argsT{ allArgs: []string{"$0", "abcdef", "aaaabbbbccccdddd"}, - input: HashInputT{ - Password: []byte("abcdef"), - Salt: []byte("aaaabbbbccccdddd"), - }, + isCheck: false, + } + + g.TAssertEqual(args, expected) + g.TAssertEqual(rc, 0) + }) + + g.Testing("isCheck is true", func() { + w := strings.Builder{} + argv := []string{"$0", "-c", "aaaabbbbccccdddd"} + args, rc := getopt(argv, &w) + + expected := argsT{ + allArgs: []string{"$0", "-c", "aaaabbbbccccdddd"}, + isCheck: true, } g.TAssertEqual(args, expected) @@ -365,39 +376,34 @@ func test_run() { g.Testing("a small salt returns 1", func() { w := strings.Builder{} env := envT{ - args: argsT{ - input: HashInputT{ - Salt: []byte("a salt"), - }, - }, + in: strings.NewReader("612073616C74\naa\n"), err: &w, } rc := run(env) - g.TAssertEqual(rc, 1) + g.TAssertEqual(rc, 2) g.TAssertEqual(w.String(), "scrypt: salt is too small\n") }) g.Testing("return of 0 and output otherwise", func() { - w := strings.Builder{} + out := strings.Builder{} + err := strings.Builder{} env := envT{ - args: argsT{ - input: HashInputT{ - Salt: []byte( - "eeeeffffgggghhhh" + - "iiiijjjjjkkkkllll", - ), - Password: []byte("password"), - }, - }, - out: &w, + in: strings.NewReader( + "70617373776F7264\n" + + "6565656566666666676767676868686869" + + "6969696A6A6A6A6A6B6B6B6B6C6C6C6C\n", + ), + out: &out, + err: &err, } const expected = "9073ca9ad51942a30b20af1747e98195" + "960e76fd8f20b246821692ce82c2d6f7\n" rc := run(env) - g.TAssertEqual(w.String(), expected) + g.TAssertEqual(out.String(), expected) + g.TAssertEqual(err.String(), "") g.TAssertEqual(rc, 0) }) } |
