Skip to content

Commit b9fa8af

Browse files
authored
Improve Performance for HOTP OCRA (#196)
* Refactor OCRA Verify - [+] refactor(otpverifier): simplify OCRA token comparison logic * Reduce allocations per operation - [+] refactor(benchmark_test.go): update benchmark results for OCRAVerify with reduced allocations per operation - [+] refactor(hotp_ocra.go): optimize generateOCRA by preallocating data slice and using copy instead of append - [+] refactor(hotp_ocra.go): simplify HOTP string formatting using fmt.Sprintf with width and padding options
1 parent e22ea04 commit b9fa8af

File tree

2 files changed

+11
-17
lines changed

2 files changed

+11
-17
lines changed

internal/otpverifier/benchmark_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,12 +228,12 @@ func BenchmarkOCRAVerify(b *testing.B) {
228228
// goarch: amd64
229229
// pkg: github.com/H0llyW00dzZ/fiber2fa/internal/otpverifier
230230
// cpu: AMD Ryzen 9 3900X 12-Core Processor (Best CPU Cryptographic)
231-
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA1-6-24 504555 2243 ns/op 792 B/op 22 allocs/op
232-
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA256-8-24 595725 2027 ns/op 832 B/op 22 allocs/op
233-
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA512-8-24 425383 2819 ns/op 1185 B/op 22 allocs/op
234-
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA1-6#01-24 529720 2242 ns/op 792 B/op 22 allocs/op
231+
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA1-6-24 520404 2181 ns/op 784 B/op 20 allocs/op
232+
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA256-8-24 643852 1950 ns/op 824 B/op 20 allocs/op
233+
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA512-8-24 429360 2791 ns/op 1177 B/op 20 allocs/op
234+
// BenchmarkOCRAVerify/Hash=OCRA-1:HOTP-SHA1-6#01-24 533643 2212 ns/op 784 B/op 20 allocs/op
235235
//
236-
// Note: 22 allocs/op it's because of Pseudorandom and Hash Function you poggers.
236+
// Note: 20 allocs/op it's because of Pseudorandom and Hash Function you poggers.
237237
verifier.Verify(tc.token, challenge)
238238
}
239239
})

internal/otpverifier/hotp_ocra.go

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,10 @@ func (v *OCRAVerifier) generateOCRA(counter uint64, question string, hash func()
105105
// Prepare the input data
106106
// Note: The counterBytes and counter are not just any values. They can be bound to a cryptographically secure pseudorandom number,
107107
// along with questionBytes, similar to how [DecodeBase32WithPadding] is used to manipulate the result in the frontend hahaha.
108-
counterBytes := make([]byte, 8)
109-
binary.BigEndian.PutUint64(counterBytes, counter)
110-
questionBytes := []byte(question)
111-
112-
// Concatenate the input data
113-
data := append(counterBytes, questionBytes...)
108+
var data []byte
109+
data = make([]byte, 8+len(question))
110+
binary.BigEndian.PutUint64(data[:8], counter)
111+
copy(data[8:], question)
114112

115113
// Generate the HMAC hash
116114
hmacHash := hmac.New(hash, v.config.DecodeBase32WithPadding())
@@ -130,7 +128,7 @@ func (v *OCRAVerifier) generateOCRA(counter uint64, question string, hash func()
130128
hotp := truncatedHash % uint32(p10n)
131129

132130
// Format the HOTP value as a string with the specified number of digits
133-
return fmt.Sprintf(fmt.Sprintf("%%0%dd", v.config.Digits), hotp)
131+
return fmt.Sprintf("%0*d", v.config.Digits, hotp) // Result will padding it with leading zeros if necessary.
134132
}
135133

136134
// GenerateOTPURL creates the URL for the QR code based on the provided URI template.
@@ -147,9 +145,5 @@ func (v *OCRAVerifier) Verify(token string, challenge string) bool {
147145
// Note: Signature verification is not applicable here because the OCRA algorithm itself provides sufficient security.
148146
// It follows the specifications defined in RFC 6287 (https://datatracker.ietf.org/doc/html/rfc6287#section-7.1)
149147
// and uses this [crypto/subtle] package, which is a crucial component in cryptographic operations.
150-
if subtle.ConstantTimeCompare([]byte(token), []byte(expectedToken)) == 1 {
151-
return true
152-
}
153-
154-
return false
148+
return subtle.ConstantTimeCompare([]byte(token), []byte(expectedToken)) == 1
155149
}

0 commit comments

Comments
 (0)