From 75a3deddea80cc770f3bbd1deb63ce69f0b836d2 Mon Sep 17 00:00:00 2001 From: Erin Millard Date: Tue, 17 Sep 2013 23:26:41 +1000 Subject: [PATCH] Implemented an mOTP generator. --- .../Otis/Motp/Generator/MotpGenerator.php | 66 +++++++++++++++++++ .../Motp/Generator/MotpGeneratorInterface.php | 31 +++++++++ .../Totp/Generator/TotpGeneratorInterface.php | 2 +- .../Otis/Motp/Generator/MotpGeneratorTest.php | 56 ++++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/Eloquent/Otis/Motp/Generator/MotpGenerator.php create mode 100644 src/Eloquent/Otis/Motp/Generator/MotpGeneratorInterface.php create mode 100644 test/suite/Eloquent/Otis/Motp/Generator/MotpGeneratorTest.php diff --git a/src/Eloquent/Otis/Motp/Generator/MotpGenerator.php b/src/Eloquent/Otis/Motp/Generator/MotpGenerator.php new file mode 100644 index 0000000..a9a3a03 --- /dev/null +++ b/src/Eloquent/Otis/Motp/Generator/MotpGenerator.php @@ -0,0 +1,66 @@ +isolator = Isolator::get($isolator); + } + + /** + * Generate an mOTP value. + * + * @link http://motp.sourceforge.net/#1.1 + * + * @param string $secret The shared secret. + * @param string $pin The PIN. + * @param integer|null $time The Unix timestamp to generate the password for. + * + * @return string The generated mOTP value. + */ + public function generate($secret, $pin, $time = null) + { + if (null === $time) { + $time = $this->isolator()->time(); + } + + return substr( + md5(strval(intval($time / 10)) . bin2hex($secret) . $pin), + 0, + 6 + ); + } + + /** + * Get the isolator. + * + * @return Isolator The isolator. + */ + protected function isolator() + { + return $this->isolator; + } + + private $isolator; +} diff --git a/src/Eloquent/Otis/Motp/Generator/MotpGeneratorInterface.php b/src/Eloquent/Otis/Motp/Generator/MotpGeneratorInterface.php new file mode 100644 index 0000000..54710cf --- /dev/null +++ b/src/Eloquent/Otis/Motp/Generator/MotpGeneratorInterface.php @@ -0,0 +1,31 @@ +isolator = Phake::mock(Isolator::className()); + $this->generator = new MotpGenerator($this->isolator); + } + + public function generateData() + { + // secret pin time expected + return array( + 'Known good value 1' => array('12345678', '1234', 0, 'd64c7d'), + 'Known good value 2' => array('12345678', '1234', 9, 'd64c7d'), + 'Known good value 3' => array('12345678', '1234', 1234, '6bfed1'), + 'Known good value 4' => array('12345678', '1234', 1240, 'ee20ed'), + 'Known good value 5' => array(pack('H*', 'fd85e62d9beb4542'), '1234', 1379424174, '65e5e8'), + ); + } + + /** + * @dataProvider generateData + */ + public function testGenerate($secret, $pin, $time, $motp) + { + $result = $this->generator->generate($secret, $pin, $time); + + $this->assertSame($motp, $result); + } + + public function testGenerateCurrentTime() + { + Phake::when($this->isolator)->time()->thenReturn(1234); + + $this->assertSame('6bfed1', $this->generator->generate('12345678', '1234', null)); + } +}