-
Notifications
You must be signed in to change notification settings - Fork 199
Description
I'm trying to migrate from sonata-project/google-authenticator since it's been abandoned for a while. I have thousands of 2fa codes set up that are based on an md5 hash + 2fa salt environment value. These are then converted to base32 and used for creating the QR code as well as validating the 6 digit pin.
The issue I'm running into is verifyKey is throwing an InvalidCharactersException even though the string is valid. I wrote a test script and verified the string is valid through several different means. I'll include as much information as I can, including the test script I wrote, that proves this issue.
- Library Version:
pragmarx/google2fa v8.0.3(added as"pragmarx/google2fa": "^8.0"in mycomposer.jsonfile - PHP Version:
8.3.1 - The Problem String:
MEYGGZRYGQYGMZRRMNRDCYJVGYZDQY3CGU4TEYJSGQ2TKM3EGMZUYOCMKE2EESSLIJBVQQSNHAYVEUZYGNJVKQKPK5AVKOBZJJJEKM2RJFCDQNRXHFMQ==== - Minimal reproducable code:
<?php
require_once __DIR__ . '/vendor/autoload.php';
use PragmaRX\Google2FA\Google2FA;
$secret = 'MEYGGZRYGQYGMZRRMNRDCYJVGYZDQY3CGU4TEYJSGQ2TKM3EGMZUYOCMKE2EESSLIJBVQQSNHAYVEUZYGNJVKQKPK5AVKOBZJJJEKM2RJFCDQNRXHFMQ====';
$alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; // As used by PragmaRX\Google2FA\Support\Constants::ALPHABET
$code = '123456';
echo "<h3>Direct Preg Match Test (Simulating Library Logic)</h3>\n";
$secretWithoutPadding = preg_replace('/=+$/', '', $secret);
$pattern = '/^[' . $alphabet . ']+$/'; // This pattern is derived from the library's Base32::checkForValidCharacters method
$isMatch = preg_match($pattern, $secretWithoutPadding);
echo "preg_match result: "; var_dump($isMatch); echo "\n";
if ($isMatch === 1) {
echo "Direct preg_match: SUCCESSFUL MATCH.\n";
} else {
echo "Direct preg_match: FAILED TO MATCH (preg_last_error: " . preg_last_error() . " - " . preg_last_error_msg() . ").\n";
}
echo "\n";
echo "<h3>Google2FA Library Test</h3>\n";
$google2fa = new Google2FA();
try {
echo "Attempting \$google2fa->verifyKey(\$secret, \$code)...\n";
$valid = $google2fa->verifyKey($secret, $code);
echo "verifyKey result: "; var_dump($valid); echo "\n";
} catch (\Exception $e) {
echo "Exception caught from verifyKey:\n";
echo "Message: " . $e->getMessage() . "\n";
echo "File: " . $e->getFile() . " :: Line " . $e->getLine() . "\n";
// Optionally include first few lines of trace if concise
echo "Trace:\n" . $e->getTraceAsString() . "\n";
}
?>
- Actual output of script:
<h3>Direct Preg Match Test</h3>
preg_match result: int(1)
Direct preg_match: SUCCESSFUL MATCH.
<h3>Google2FA Library Test</h3>
Attempting $google2fa->verifyKey($secret, $code)...
Exception caught from verifyKey:
Message: Invalid characters in the base32 string.
File: /home/vagrant/code/ccbv5/vendor/pragmarx/google2fa/src/Support/Base32.php :: Line 205
Trace:
#0 /home/vagrant/code/ccbv5/vendor/pragmarx/google2fa/src/Support/Base32.php(164): PragmaRX\Google2FA\Google2FA->checkForValidCharacters()
#1 /home/vagrant/code/ccbv5/vendor/pragmarx/google2fa/src/Support/Base32.php(75): PragmaRX\Google2FA\Google2FA->validateSecret()
#2 /home/vagrant/code/ccbv5/vendor/pragmarx/google2fa/src/Google2FA.php(284): PragmaRX\Google2FA\Google2FA->base32Decode()
#3 /home/vagrant/code/ccbv5/vendor/pragmarx/google2fa/src/Google2FA.php(82): PragmaRX\Google2FA\Google2FA->oathTotp()
#4 /home/vagrant/code/ccbv5/vendor/pragmarx/google2fa/src/Google2FA.php(472): PragmaRX\Google2FA\Google2FA->findValidOTP()
#5 /home/vagrant/code/ccbv5/app/Http/Controllers/TestController.php(138): PragmaRX\Google2FA\Google2FA->verifyKey()
...
The expected output would be: verifyKey should process the secret without throwing an InvalidCharactersException, and then return false (because 123456 is a dummy code).
I've run this code both inside and outside of my Laravel framework and receive the same error message, so it doesn't seem to be some kind of conflict with a constant being overwritten.
If I generate a secret directly with $google2fa->generateSecretKey() and then run $google2fa->verifyKey() with that secret, it works exactly as expected. It's just an issue with valid base32 codes that were generated using the old code. Obviously I can't switch to this project if I'm unable to have the old codes work.
Any ideas what may be causing this or any additional information you need from me?