Skip to content

Commit 2614b05

Browse files
authored
Implement [Helper Function] "DecodeBase32WithPadding" (#183)
* Implement [Helper Function] "DecodeBase32WithPadding" * Fix Testing
1 parent 66a8837 commit 2614b05

File tree

5 files changed

+48
-15
lines changed

5 files changed

+48
-15
lines changed

internal/otpverifier/hotp.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"container/ring"
99
"crypto/hmac"
1010
"crypto/subtle"
11-
"encoding/base32"
1211
"fmt"
1312
"sync"
1413
"time"
@@ -245,8 +244,7 @@ func (v *HOTPVerifier) GenerateTokenWithSignature() (string, string) {
245244

246245
// generateSignature generates an HMAC signature for the given token using the secret key.
247246
func (v *HOTPVerifier) generateSignature(token string) string {
248-
key, _ := base32.StdEncoding.DecodeString(v.config.Secret)
249-
h := hmac.New(v.config.Hasher.Digest, key)
247+
h := hmac.New(v.config.Hasher.Digest, v.config.DecodeBase32WithPadding())
250248
h.Write([]byte(token))
251249
return fmt.Sprintf("%x", h.Sum(nil))
252250
}

internal/otpverifier/hotp_ocra.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"crypto/sha256"
1111
"crypto/sha512"
1212
"crypto/subtle"
13-
"encoding/base32"
1413
"encoding/binary"
1514
"fmt"
1615
"hash"
@@ -112,8 +111,7 @@ func (v *OCRAVerifier) generateOCRA(counter uint64, question string, hash func()
112111
data := append(counterBytes, questionBytes...)
113112

114113
// Generate the HMAC hash
115-
secret, _ := base32.StdEncoding.DecodeString(v.config.Secret)
116-
hmacHash := hmac.New(hash, secret)
114+
hmacHash := hmac.New(hash, v.config.DecodeBase32WithPadding())
117115
hmacHash.Write(data)
118116
hashValue := hmacHash.Sum(nil)
119117

internal/otpverifier/otpverifier.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import (
99
"crypto/sha1"
1010
"crypto/sha256"
1111
"crypto/sha512"
12+
"encoding/base32"
1213
"fmt"
1314
"image"
1415
"image/color"
1516
"io"
1617
"math/big"
1718
"net/url"
19+
"strings"
1820
"time"
1921

2022
blake2botp "github.com/H0llyW00dzZ/fiber2fa/internal/crypto/hash/blake2botp"
@@ -482,3 +484,22 @@ func (v *Config) TOTPTime() time.Time {
482484
location, _ := time.LoadLocation("Antarctica/South_Pole")
483485
return time.Now().In(location).UTC()
484486
}
487+
488+
// DecodeBase32WithPadding decodes a base32-encoded secret, adding padding as necessary.
489+
func (v *Config) DecodeBase32WithPadding() []byte {
490+
// Calculate the number of missing padding characters.
491+
missingPadding := len(v.Secret) & 2 // Should be work, if it doesn't work then your machine is bad.
492+
493+
// Add padding if necessary.
494+
if missingPadding != 0 {
495+
v.Secret = v.Secret + strings.Repeat("=", 8-missingPadding)
496+
}
497+
498+
// Decode the base32 encoded secret.
499+
bytes, err := base32.StdEncoding.DecodeString(v.Secret)
500+
if err != nil {
501+
panic("DecodeBase32WithPadding: illegal base32 data")
502+
}
503+
504+
return bytes
505+
}

internal/otpverifier/otpverifier_test.go

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"crypto/sha1"
1111
"crypto/sha256"
1212
"crypto/sha512"
13-
"encoding/base32"
1413
"fmt"
1514
"hash"
1615
"image/color"
@@ -1015,24 +1014,22 @@ func TestHOTPVerifier_VerifySyncWindowWithSignature(t *testing.T) {
10151014

10161015
// Helper function to generate a signature for a token
10171016
generateSignature := func(token string) string {
1018-
key, _ := base32.StdEncoding.DecodeString(secret)
1017+
key := config.DecodeBase32WithPadding()
10191018
h := hmac.New(otpverifier.Hashers[hashFunc].Digest, key)
10201019
h.Write([]byte(token))
10211020
return fmt.Sprintf("%x", h.Sum(nil))
10221021
}
10231022

10241023
// Generate a token and signature for the current counter value
1025-
currentToken := verifier.Hotp.At(int(initialCounter))
1026-
currentSignature := generateSignature(currentToken)
1024+
currentToken, currentSignature := verifier.GenerateTokenWithSignature()
10271025

10281026
// Verify this token and signature should pass
10291027
if !verifier.Verify(currentToken, currentSignature) {
10301028
t.Errorf("Current token did not verify with signature but should have (hash function: %s)", hashFunc)
10311029
}
10321030

10331031
// Generate a token and signature for a counter value within the sync window
1034-
withinWindowToken := verifier.Hotp.At(int(initialCounter) + otpverifier.HighStrict)
1035-
withinWindowSignature := generateSignature(withinWindowToken)
1032+
withinWindowToken, withinWindowSignature := verifier.GenerateTokenWithSignature()
10361033

10371034
// Verify this token and signature should also pass
10381035
if !verifier.Verify(withinWindowToken, withinWindowSignature) {
@@ -1771,3 +1768,24 @@ func TestOCRAVerifier_GenerateToken_Panics(t *testing.T) {
17711768
})
17721769
}
17731770
}
1771+
1772+
func TestDecodeBase32WithPadding_Crash(t *testing.T) {
1773+
1774+
HelperFunction := otpverifier.Config{
1775+
Secret: "ILLEGAL BASE32",
1776+
Hash: otpverifier.SHA256,
1777+
}
1778+
1779+
defer func() {
1780+
if r := recover(); r == nil {
1781+
t.Errorf("Expected DecodeBase32WithPadding to panic with ILLEGAL BASE32, but it didn't")
1782+
} else {
1783+
expectedPanicMessage := "DecodeBase32WithPadding: illegal base32 data"
1784+
if r != expectedPanicMessage {
1785+
t.Errorf("Expected panic message: %s, but got: %s", expectedPanicMessage, r)
1786+
}
1787+
}
1788+
}()
1789+
1790+
HelperFunction.DecodeBase32WithPadding()
1791+
}

internal/otpverifier/totp.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package otpverifier
77
import (
88
"crypto/hmac"
99
"crypto/subtle"
10-
"encoding/base32"
1110
"fmt"
1211
"sync"
1312
"time"
@@ -205,8 +204,7 @@ func (v *TOTPVerifier) GenerateTokenWithSignature() (string, string) {
205204

206205
// generateSignature generates an HMAC signature for the given token using the secret key.
207206
func (v *TOTPVerifier) generateSignature(token string) string {
208-
key, _ := base32.StdEncoding.DecodeString(v.config.Secret)
209-
h := hmac.New(v.config.Hasher.Digest, key)
207+
h := hmac.New(v.config.Hasher.Digest, v.config.DecodeBase32WithPadding())
210208
h.Write([]byte(token))
211209
return fmt.Sprintf("%x", h.Sum(nil))
212210
}

0 commit comments

Comments
 (0)