From 782be34197e32873a826041791992cffad6960a7 Mon Sep 17 00:00:00 2001 From: Thomas Schwery Date: Sun, 28 Oct 2018 12:11:41 +0100 Subject: [PATCH] Add issuer parsing and SteamGuard encoding --- oath.go | 26 +++++++++++++++++++++++--- totp.go | 6 ++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/oath.go b/oath.go index a6d9233..c6adb07 100644 --- a/oath.go +++ b/oath.go @@ -22,6 +22,7 @@ type OATH struct { hash func() hash.Hash algo crypto.Hash provider string + issuer string } // Size returns the output size (in characters) of the password. @@ -82,6 +83,10 @@ func (o OATH) URL(t Type, label string) string { v.Add("provider", o.provider) } + if o.issuer != "" { + v.Add("issuer", o.issuer) + } + u.RawQuery = v.Encode() return u.String() @@ -119,9 +124,24 @@ func (o OATH) OTP(counter uint64) string { h := hmac.New(o.hash, o.key) h.Write(ctr[:]) - dt := truncate(h.Sum(nil)) % mod - fmtStr := fmt.Sprintf("%%0%dd", o.size) - return fmt.Sprintf(fmtStr, dt) + + if o.issuer == "Steam" { + res := truncate(h.Sum(nil)) + + steamChars := "23456789BCDFGHJKMNPQRTVWXY" + steamCharsLen := int64(len(steamChars)) + hotp := make([]byte, 5, 5) + for i := 0; i < 5; i++ { + idx := res % steamCharsLen + hotp[i] = steamChars[int(idx)] + res = res / steamCharsLen + } + return string(hotp) + } else { + dt := truncate(h.Sum(nil)) % mod + fmtStr := fmt.Sprintf("%%0%dd", o.size) + return fmt.Sprintf(fmtStr, dt) + } } // truncate contains the DT function from the RFC; this is used to diff --git a/totp.go b/totp.go index 789de4a..e5214cc 100644 --- a/totp.go +++ b/totp.go @@ -150,12 +150,18 @@ func totpFromURL(u *url.URL) (*TOTP, string, error) { } } + var issuer = "" + if sissuer := v.Get("issuer"); sissuer != "" { + issuer = sissuer + } + key, err := base32.StdEncoding.DecodeString(Pad(secret)) if err != nil { // assume secret isn't base32 encoded key = []byte(secret) } otp := NewTOTP(key, 0, period, digits, algo) + otp.issuer = issuer return otp, label, nil }