Skip to content

Commit 4a29d78

Browse files
committed
Change to sha-512
1 parent e345059 commit 4a29d78

File tree

2 files changed

+14
-93
lines changed

2 files changed

+14
-93
lines changed

src/LaravelOTP.php

Lines changed: 11 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -33,110 +33,61 @@ final public function now(): string
3333
return $this->at();
3434
}
3535

36-
/**
37-
* @return string
38-
* return TOTP at previous timeframe
39-
*/
4036
final public function last(): string
4137
{
4238
return $this->at(-1);
4339
}
4440

45-
/**
46-
* @return string
47-
* return TOTP at next timeframe
48-
*/
4941
final public function next(): string
5042
{
5143
return $this->at(1);
5244
}
5345

54-
/**
55-
* @param int $offset
56-
* @return string
57-
* return TOTP at custom timeframe
58-
*/
5946
final public function at(int $offset = 0): string
6047
{
6148
return $this->generateTOTP($this->secret, $offset);
6249
}
6350

64-
/**
65-
* @param int $length
66-
* @return string
67-
* Generate Secret Key
68-
*/
6951
final public function generateSecretKey(): string
7052
{
7153
return substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'), 0, 32);
7254
}
7355

74-
/**
75-
* @return int
76-
* Return current time
77-
*/
7856
private function getCurrentTimestamp(): int
7957
{
80-
return floor(time() / 30); // Time steps of 30 seconds
58+
return floor(time() / 30);
8159
}
8260

83-
/**
84-
* @param int $counter
85-
* @return string
86-
* Return HOTP at specific counter
87-
*/
8861
final public function atCounter(int $counter): string
8962
{
9063
return $this->generateHOTP($this->secret, $counter);
9164
}
9265

93-
/**
94-
* @param string $secretKey
95-
* @param int $timeStepOffset
96-
* @return string
97-
* Generate TOTP at specific timeframe
98-
*/
9966
private function generateTOTP(string $secretKey, int $timeStepOffset = 0): string
10067
{
10168
$timestamp = $this->getCurrentTimestamp() + $timeStepOffset;
10269

103-
return $this->generateHOTP($secretKey, $timestamp); // TOTP is HOTP with a time-based counter
70+
return $this->generateHOTP($secretKey, $timestamp);
10471
}
10572

106-
/**
107-
* @param string $secretKey
108-
* @param int $counter
109-
* @return string
110-
* Generate HOTP at specific counter
111-
*/
11273
private function generateHOTP(string $secretKey, int $counter): string
11374
{
114-
// Decode the base32 secret key
11575
$key = $this->base32_decode($secretKey);
76+
$counter = pack('J', $counter);
11677

117-
// Pack the counter into an 8-byte binary string (big endian)
118-
$counter = pack('N*', 0) . pack('N*', $counter);
78+
$hash = hash_hmac('sha512', $counter, $key, true);
11979

120-
// Generate HMAC-SHA1 hash using the secret key and packed counter
121-
$hash = hash_hmac('sha1', $counter, $key, true);
122-
123-
// Extract dynamic binary code (truncated hash)
124-
$offset = ord($hash[19]) & 0xf;
80+
$offset = ord($hash[63]) & 0xf;
12581
$binaryCode = (
12682
((ord($hash[$offset]) & 0x7f) << 24) |
12783
((ord($hash[$offset + 1]) & 0xff) << 16) |
12884
((ord($hash[$offset + 2]) & 0xff) << 8) |
12985
(ord($hash[$offset + 3]) & 0xff)
13086
);
13187

132-
// Convert binary code into a 6-digit OTP
13388
return str_pad($binaryCode % 1000000, 6, '0', STR_PAD_LEFT);
13489
}
13590

136-
/**
137-
* @param string $input
138-
* @return string
139-
*/
14091
private function base32_decode(string $input): string
14192
{
14293
$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
@@ -147,7 +98,6 @@ private function base32_decode(string $input): string
14798
foreach (str_split($input) as $char) {
14899
$buffer = ($buffer << 5) | strpos($alphabet, $char);
149100
$bitsLeft += 5;
150-
151101
if ($bitsLeft >= 8) {
152102
$bitsLeft -= 8;
153103
$output .= chr(($buffer >> $bitsLeft) & 0xff);
@@ -157,63 +107,34 @@ private function base32_decode(string $input): string
157107
return $output;
158108
}
159109

160-
/**
161-
* @param string $otp
162-
* @param string|null $secret
163-
* @return bool
164-
* Verify TOTP
165-
*/
166110
final public function verifyTOTP(string $otp, string $secret = null): bool
167111
{
168112
if ($secret !== null) {
169113
$this->secret = $secret;
170114
}
171115

172-
$secretKey = $this->secret;
173-
174-
// Check the OTP for the current time step, the previous, and the next one
175116
for ($i = -1; $i <= 1; $i++) {
176-
$calculatedOtp = $this->generateTOTP($secretKey, $i);
177-
if ($calculatedOtp === $otp) {
178-
return true; // OTP is valid
117+
if ($this->generateTOTP($this->secret, $i) === $otp) {
118+
119+
return true;
179120
}
180121
}
181122

182-
return false; // OTP is invalid
123+
return false;
183124
}
184125

185-
/**
186-
* @param string $otp
187-
* @param int $counter
188-
* @param string|null $secret
189-
* @return bool
190-
* Verify HOTP at specific counter
191-
*/
192126
final public function verifyHOTP(string $otp, int $counter, string $secret = null): bool
193127
{
194128
if ($secret !== null) {
195129
$this->secret = $secret;
196130
}
197131

198-
$calculatedOtp = $this->generateHOTP($this->secret, $counter);
199-
return $calculatedOtp === $otp; // Return true if OTP matches, otherwise false
132+
return $this->generateHOTP($this->secret, $counter) === $otp;
200133
}
201134

202-
203-
/**
204-
* @param string $label
205-
* @param string $issuer
206-
* @param string|null $secretKey
207-
* @param int|null $counter
208-
* @return string
209-
* Generate URL to be used on QR Codes for Authenticator apps
210-
*/
211135
final public function generateUrl(string $label, string $issuer, string $secretKey = null, int $counter = null): string
212136
{
213-
$method = 'totp';
214-
if ($counter !== null) {
215-
$method = 'hotp';
216-
}
137+
$method = $counter !== null ? 'hotp' : 'totp';
217138
return "otpauth://" . $method . '/' . $label . "?secret=" . ($secretKey ?? $this->secret) . '&issuer=' . $issuer . ($counter ? '&counter=' . $counter : '');
218139
}
219140
}

src/LaravelOTPServiceProvider.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44

55
use Illuminate\Support\ServiceProvider;
66

7-
class LaravelOTPServiceProvider extends ServiceProvider
7+
final class LaravelOTPServiceProvider extends ServiceProvider
88
{
99
/**
1010
* Bootstrap the application services.
1111
*/
12-
public function boot()
12+
public function boot(): void
1313
{
1414

1515
if ($this->app->runningInConsole()) {
@@ -24,7 +24,7 @@ public function boot()
2424
/**
2525
* Register the application services.
2626
*/
27-
public function register()
27+
public function register(): void
2828
{
2929
// Register the main class to use with the facade
3030
$this->app->singleton('laravel-otp', function () {

0 commit comments

Comments
 (0)