Provides support for TOTP (time based) and HOTP (HMAC, counter based) one time password, following RFC 6238. Useful for two factor authentication (2FA), and is compatible with most popular solutions like Google Authenticator.
Recommended client for Android and iOS is FreeOTP: https://freeotp.github.io/
- Generate a secret
- Base32 decode / encode (RFC 3548)
- Protected against timing attacks
- TOTP support
- HOTP support
- Supports time drift
- Supports multiple digests: SHA1 (default), SHA256 or SHA512
- Supports any number of digits
- Can be used to generate new codes as well as compare them (client or server scenario)
Usage example: generating a new code
Usage example: comparing a code sent by client
$success = \KD2\Security_OTP::TOTP($secret, $_POST['code']); if ($success) echo 'TOTP auth was successful'; else echo 'TOTP auth failed';
Usage example: comparing a code using NTP time
This is quite useful if your code is used on servers you don't manage, and where server time is sometimes out of sync and causes trouble with TOTP.
$time = \KD2\Security_OTP::getTimeFromNTP('nz.pool.ntp.org'); $success = \KD2\Security_OTP::TOTP($secret, $_POST['code'], $time); if ($success) echo 'TOTP auth was successful'; else echo 'TOTP auth failed';
Usage example: creating a random secret and displaying it with a QR code
$secret = \KD2\Security_OTP::getRandomSecret(); $secret_display = implode(' ', str_split($secret, 4)); $otp_url = \KD2\Security_OTP::getOTPAuthURL('My website', $secret); $qrcode = (new \KD2\QRCode($otp_url))->toSVG(); $qrcode_encoded = 'data:image/svg+xml;base64,' . base64_encode($qrcode); echo '<p>Your secret is:</p>'; echo '<pre>' . htmlspecialchars($secret_display) . '</pre>'; echo '<p>Scan this QRCode in FreeOTP to add it:</p>'; echo '<img src="' . htmlspecialchars($qrcode_encoded) . '" />';
Security_OTP::HOTP($secret, $count, $code = null, $digits = 6, $digest = 'sha1')
Creates or checks a HOTP code
Note that you should store $count yourself, as well as store codes that have already been used successfully, and reject any used code to protect against replay attacks.
@param string $secret Secret key (Base32 encoded) @param integer $count Counter or timestamp for TOTP @param integer $code Code to check against, if null is passed, then a code will be generated @param integer $digits Number of digits in the generated code (default is 6) @param string $digest Digest algo to use (sha1, sha256 or sha512) default is sha1
Security_OTP::TOTP($secret, $code = null, $timestamp = time(), $digits = 6, $digest = 'sha1', $interval = 30, $drift = 1)
Time based One-time password (RFC 6238)
Note that you should store codes that have already been used successfully, and reject any previously used code to protect against replay attacks.
@param string $secret Secret key @param integer $code One-time code to check against, if NULL a new code will be returned @param integer $timestamp UNIX timestamp (in seconds) or NULL to use the system time @param integer $digits Number of digits in the generated code (default is 6) @param string $digest Digest algo to use (sha1, sha256 or sha512) default is sha1 @param integer $interval Time interval to round the timestamp (default is 30 seconds) @param integer $drift Number of intervals in the past and future to try This is useful for clients who use an invalid time to generate the OTP.
Security_OTP::getRandomSecret($length = 16)
Returns a random base32 secret for HOTP/TOTP
@param integer $length Length of the secret key (default is 16 characters)
Security_OTP::getOTPAuthURL($label, $secret, $type = 'totp')
Returns a valid otpauth:// URL from a secret (Useful to generate QRcodes)
@param string $label Service label, eg 'Blog:email@example.com' @param string $secret secret key @param string $type 'totp' or 'hotp'
Security_OTP::getTimeFromNTP($host = 'pool.ntp.org', $timeout = 10)
Returns current time as an UNIX timestamp from a NTP server (atomic time).
@param string $host Server host (default is pool.ntp.org) @param integer $timeout Timeout in seconds (default is 10 seconds) @return integer Number of seconds since January 1st 1970