diff --git a/hotp/hotp.go b/hotp/hotp.go index 62cdc87..ced7d8e 100644 --- a/hotp/hotp.go +++ b/hotp/hotp.go @@ -70,6 +70,12 @@ func GenerateCode(secret string, counter uint64) (string, error) { // GenerateCodeCustom uses a counter and secret value and options struct to // create a passcode. func GenerateCodeCustom(secret string, counter uint64, opts ValidateOpts) (passcode string, err error) { + // As noted in issue #10 this adds support for TOTP secrets that are + // missing their padding. + if n := len(secret) % 8; n != 0 { + secret = secret + strings.Repeat("=", 8-n) + } + secretBytes, err := base32.StdEncoding.DecodeString(secret) if err != nil { return "", otp.ErrValidateSecretInvalidBase32 diff --git a/hotp/hotp_test.go b/hotp/hotp_test.go index cadeeab..d41af51 100644 --- a/hotp/hotp_test.go +++ b/hotp/hotp_test.go @@ -109,6 +109,17 @@ func TestValidateInvalid(t *testing.T) { require.Equal(t, false, valid, "Valid should be false.") } +// This tests for issue #10 - secrets without padding +func TestValidatePadding(t *testing.T) { + valid, err := ValidateCustom("831097", 0, "JBSWY3DPEHPK3PX", + ValidateOpts{ + Digits: otp.DigitsSix, + Algorithm: otp.AlgorithmSHA1, + }) + require.NoError(t, err, "Expected no error.") + require.Equal(t, true, valid, "Valid should be true.") +} + func TestGenerate(t *testing.T) { k, err := Generate(GenerateOpts{ Issuer: "SnakeOil",