OTP.php 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. <?php
  2. /*
  3. * Copyright (c) 2011 Le Lag
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. namespace OTPHP {
  22. /**
  23. * One Time Password Generator
  24. *
  25. * The OTP class allow the generation of one-time
  26. * password that is described in rfc 4xxx.
  27. *
  28. * This is class is meant to be compatible with
  29. * Google Authenticator.
  30. *
  31. * This class was originally ported from the rotp
  32. * ruby library available at https://github.com/mdp/rotp
  33. */
  34. class OTP {
  35. /**
  36. * The base32 encoded secret key
  37. * @var string
  38. */
  39. public $secret;
  40. /**
  41. * The algorithm used for the hmac hash function
  42. * @var string
  43. */
  44. public $digest;
  45. /**
  46. * The number of digits in the one-time password
  47. * @var integer
  48. */
  49. public $digits;
  50. /**
  51. * Constructor for the OTP class
  52. * @param string $secret the secret key
  53. * @param array $opt options array can contain the
  54. * following keys :
  55. * @param integer digits : the number of digits in the one time password
  56. * Currently Google Authenticator only support 6. Defaults to 6.
  57. * @param string digest : the algorithm used for the hmac hash function
  58. * Google Authenticator only support sha1. Defaults to sha1
  59. *
  60. * @return new OTP class.
  61. */
  62. public function __construct($secret, $opt = Array()) {
  63. $this->digits = isset($opt['digits']) ? $opt['digits'] : 6;
  64. $this->digest = isset($opt['digest']) ? $opt['digest'] : 'sha1';
  65. $this->secret = $secret;
  66. }
  67. /**
  68. * Generate a one-time password
  69. *
  70. * @param integer $input : number used to seed the hmac hash function.
  71. * This number is usually a counter (HOTP) or calculated based on the current
  72. * timestamp (see TOTP class).
  73. * @return integer the one-time password
  74. */
  75. public function generateOTP($input) {
  76. $hash = hash_hmac($this->digest, $this->intToBytestring($input), $this->byteSecret());
  77. foreach(str_split($hash, 2) as $hex) { // stupid PHP has bin2hex but no hex2bin WTF
  78. $hmac[] = hexdec($hex);
  79. }
  80. $offset = $hmac[19] & 0xf;
  81. $code = ($hmac[$offset+0] & 0x7F) << 24 |
  82. ($hmac[$offset + 1] & 0xFF) << 16 |
  83. ($hmac[$offset + 2] & 0xFF) << 8 |
  84. ($hmac[$offset + 3] & 0xFF);
  85. return $code % pow(10, $this->digits);
  86. }
  87. /**
  88. * Returns the binary value of the base32 encoded secret
  89. * @access private
  90. * This method should be private but was left public for
  91. * phpunit tests to work.
  92. * @return binary secret key
  93. */
  94. public function byteSecret() {
  95. return Base32::decode($this->secret);
  96. }
  97. /**
  98. * Turns an integer in a OATH bytestring
  99. * @param integer $int
  100. * @access private
  101. * @return string bytestring
  102. */
  103. public function intToBytestring($int) {
  104. $result = Array();
  105. while($int != 0) {
  106. $result[] = chr($int & 0xFF);
  107. $int >>= 8;
  108. }
  109. return str_pad(join(array_reverse($result)), 8, "\000", STR_PAD_LEFT);
  110. }
  111. }
  112. }