From 2694554c333daf624eb2a8836a61c3de4e58f8c1 Mon Sep 17 00:00:00 2001 From: Yoav Shai Date: Fri, 9 Feb 2018 23:43:26 +0200 Subject: [PATCH 1/5] First commit --- main.go | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/main.go b/main.go index a8d173c..5aa88cc 100644 --- a/main.go +++ b/main.go @@ -90,11 +90,12 @@ var ( flag7 = flag.Bool("7", false, "generate 7-digit code") flag8 = flag.Bool("8", false, "generate 8-digit code") flagClip = flag.Bool("clip", false, "copy code to the clipboard") + flag10 = flag.Bool("10", false, "use a 10-second interval") ) func usage() { fmt.Fprintf(os.Stderr, "usage:\n") - fmt.Fprintf(os.Stderr, "\t2fa -add [-7] [-8] [-hotp] keyname\n") + fmt.Fprintf(os.Stderr, "\t2fa -add [-7] [-8] [-10] [-hotp] keyname\n") fmt.Fprintf(os.Stderr, "\t2fa -list\n") fmt.Fprintf(os.Stderr, "\t2fa [-clip] keyname\n") os.Exit(2) @@ -149,6 +150,7 @@ type Key struct { raw []byte digits int offset int // offset of counter + interval int // interval of generation } const counterLen = 20 @@ -176,18 +178,22 @@ func readKeychain(file string) *Keychain { if len(f) == 1 && len(f[0]) == 0 { continue } - if len(f) >= 3 && len(f[1]) == 1 && '6' <= f[1][0] && f[1][0] <= '8' { + if len(f) >= 4 && len(f[1]) == 1 && '6' <= f[1][0] && f[1][0] <= '8' && len(f[2]) == 2 && (f[2] == '30' || f[2] == '10') { var k Key name := string(f[0]) k.digits = int(f[1][0] - '0') - raw, err := decodeKey(string(f[2])) + k.interval, err := strconv.Atoi(string(f[2])) + if err != nil { + log.fatal(err) + } + raw, err := decodeKey(string(f[3])) if err == nil { k.raw = raw - if len(f) == 3 { + if len(f) == 4 { c.keys[name] = k continue } - if len(f) == 4 && len(f[3]) == counterLen { + if len(f) == 5 && len(f[4]) == counterLen { _, err := strconv.ParseUint(string(f[3]), 10, 64) if err == nil { // Valid counter. @@ -235,6 +241,11 @@ func (c *Keychain) add(name string) { size = 8 } + latency := 30 + if *flag10 { + latency = 10 + } + fmt.Fprintf(os.Stderr, "2fa key for %s: ", name) text, err := bufio.NewReader(os.Stdin).ReadString('\n') if err != nil { @@ -246,10 +257,11 @@ func (c *Keychain) add(name string) { log.Fatalf("invalid key: %v", err) } - line := fmt.Sprintf("%s %d %s", name, size, text) + line := fmt.Sprintf("%s %d %d %s", name, size, latency, text) if *flagHotp { line += " " + strings.Repeat("0", 20) } + line += "\n" f, err := os.OpenFile(c.file, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0600) @@ -291,7 +303,7 @@ func (c *Keychain) code(name string) string { } } else { // Time-based key. - code = totp(k.raw, time.Now(), k.digits) + code = totp(k.raw, time.Now(), k.digits, k.interval) } return fmt.Sprintf("%0*d", k.digits, code) } @@ -340,6 +352,6 @@ func hotp(key []byte, counter uint64, digits int) int { return int(v % d) } -func totp(key []byte, t time.Time, digits int) int { - return hotp(key, uint64(t.UnixNano())/30e9, digits) +func totp(key []byte, t time.Time, digits int, latency int) int { + return hotp(key, uint64(t.UnixNano())/(latency*10e8), digits) } From 02a1be26dc791920beb086ad8dae2e200e40271e Mon Sep 17 00:00:00 2001 From: Yoav Shai Date: Sat, 10 Feb 2018 00:20:54 +0200 Subject: [PATCH 2/5] Features are complete, codes don't generate properly. --- main.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 5aa88cc..6d9fe54 100644 --- a/main.go +++ b/main.go @@ -91,11 +91,12 @@ var ( flag8 = flag.Bool("8", false, "generate 8-digit code") flagClip = flag.Bool("clip", false, "copy code to the clipboard") flag10 = flag.Bool("10", false, "use a 10-second interval") + flag20 = flag.Bool("20", false, "use a 20-second interval") ) func usage() { fmt.Fprintf(os.Stderr, "usage:\n") - fmt.Fprintf(os.Stderr, "\t2fa -add [-7] [-8] [-10] [-hotp] keyname\n") + fmt.Fprintf(os.Stderr, "\t2fa -add [-7] [-8] [-10] [-20] [-hotp] keyname\n") fmt.Fprintf(os.Stderr, "\t2fa -list\n") fmt.Fprintf(os.Stderr, "\t2fa [-clip] keyname\n") os.Exit(2) @@ -124,6 +125,7 @@ func main() { return } if flag.NArg() != 1 { + fmt.Fprintf(os.Stderr, "errhere: %d\n", flag.NArg()) usage() } name := flag.Arg(0) @@ -178,13 +180,13 @@ func readKeychain(file string) *Keychain { if len(f) == 1 && len(f[0]) == 0 { continue } - if len(f) >= 4 && len(f[1]) == 1 && '6' <= f[1][0] && f[1][0] <= '8' && len(f[2]) == 2 && (f[2] == '30' || f[2] == '10') { + if len(f) >= 4 && len(f[1]) == 1 && '6' <= f[1][0] && f[1][0] <= '8' && len(f[2]) == 2 { var k Key name := string(f[0]) k.digits = int(f[1][0] - '0') - k.interval, err := strconv.Atoi(string(f[2])) + k.interval, err = strconv.Atoi(string(f[2])) if err != nil { - log.fatal(err) + log.Fatal(err) } raw, err := decodeKey(string(f[3])) if err == nil { @@ -244,6 +246,11 @@ func (c *Keychain) add(name string) { latency := 30 if *flag10 { latency = 10 + if *flag20 { + log.Fatalf("cannot use -10 and -20 together") + } + } else if *flag20 { + latency = 20 } fmt.Fprintf(os.Stderr, "2fa key for %s: ", name) @@ -353,5 +360,5 @@ func hotp(key []byte, counter uint64, digits int) int { } func totp(key []byte, t time.Time, digits int, latency int) int { - return hotp(key, uint64(t.UnixNano())/(latency*10e8), digits) + return hotp(key, uint64(t.UnixNano())/(uint64(latency)*10e8), digits) } From dbaf46b82728cf977e2cb40bc9706f04fb27056e Mon Sep 17 00:00:00 2001 From: Yoav Shai Date: Sat, 10 Feb 2018 01:09:37 +0200 Subject: [PATCH 3/5] Fixed small mistake, done --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 6d9fe54..f45b3f7 100644 --- a/main.go +++ b/main.go @@ -196,7 +196,7 @@ func readKeychain(file string) *Keychain { continue } if len(f) == 5 && len(f[4]) == counterLen { - _, err := strconv.ParseUint(string(f[3]), 10, 64) + _, err := strconv.ParseUint(string(f[4]), 10, 64) if err == nil { // Valid counter. k.offset = offset - counterLen From 36d969886b90e8a08fdca9e7e338f2132c4378f3 Mon Sep 17 00:00:00 2001 From: Yoav Shai Date: Sat, 10 Feb 2018 01:11:55 +0200 Subject: [PATCH 4/5] Remove debug print --- main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/main.go b/main.go index f45b3f7..f86e94a 100644 --- a/main.go +++ b/main.go @@ -125,7 +125,6 @@ func main() { return } if flag.NArg() != 1 { - fmt.Fprintf(os.Stderr, "errhere: %d\n", flag.NArg()) usage() } name := flag.Arg(0) From a1bd091124b196dd3de7ab24339e33fc05a02346 Mon Sep 17 00:00:00 2001 From: Yoav Shai Date: Sat, 10 Feb 2018 14:23:47 +0200 Subject: [PATCH 5/5] gofmt'ed --- main.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index f86e94a..453dff0 100644 --- a/main.go +++ b/main.go @@ -148,9 +148,9 @@ type Keychain struct { } type Key struct { - raw []byte - digits int - offset int // offset of counter + raw []byte + digits int + offset int // offset of counter interval int // interval of generation }