Passed
Push — develop ( 22eefe...e65dcd )
by Pieter van der
06:04
created

Tiqr_OCRAWrapper_v1::_challengeConfig()   A

Complexity

Conditions 5
Paths 10

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 5.3906

Importance

Changes 1
Bugs 1 Features 0
Metric Value
eloc 11
c 1
b 1
f 0
dl 0
loc 21
ccs 9
cts 12
cp 0.75
rs 9.6111
cc 5
nc 10
nop 1
crap 5.3906
1
<?php
2
3
/**
4
 * This file is part of the tiqr project.
5
 * 
6
 * The tiqr project aims to provide an open implementation for 
7
 * authentication using mobile devices. It was initiated by 
8
 * SURFnet and developed by Egeniq.
9
 *
10
 * More information: http://www.tiqr.org
11
 *
12
 * @author Ivo Jansch <[email protected]>
13
 * 
14
 * @package tiqr
15
 *
16
 * @license New BSD License - See LICENSE file for details.
17
 *
18
 * @copyright (C) 2010-2011 SURFnet BV
19
 */
20
21
22
/**
23
 * @internal includes
24
 */
25
require_once("OCRA_v1.php");
26
require_once("Tiqr/Random.php");
27
28
/**
29
 * A wrapper for the OCRA algorithm implementing just the features we support.
30
 * Legacy bridge mapping current OCRA.php interface to the v1 legacy OCRA
31
 * implementation, for older clients.
32
 * @author ivo
33
 */
34
class Tiqr_OCRAWrapper_v1 
35
{
36
    protected $_ocraSuite = NULL;
37
    
38
    /**
39
     * The length of generated session keys
40
     */
41
    const SESSIONKEY_SIZE = 16;
42
    
43
44 6
    public function __construct($ocraSuite) 
45
    {
46 6
        $this->_ocraSuite = $ocraSuite;
47 6
    }
48
    
49
    /**
50
     * Generate a challenge string based on an ocraSuite
51
     * @return String An OCRA challenge that matches the specification of
52
     *         the ocraSuite.
53
     */
54 2
    public function generateChallenge() 
55
    {
56 2
        return $this->_getChallenge($this->_ocraSuite);
57
    }
58
    
59
60
    /**
61
     * Generate a session key based on an ocraSuite
62
     * @return String Hexadecimal session key
63
     */
64 2
    public function generateSessionKey() 
65
    {
66 2
        return Tiqr_Random::randomHexString(self::SESSIONKEY_SIZE);
67
    }
68
    
69
    /**
70
     * Calculate an OCRA repsonse to a given OCRA challenge, according to
71
     * the algorithm specified by an OCRA Suite.
72
     * @param String $secret a hex representation of the user's secret
73
     * @param String $challenge a hex or (alfa)numeric challenge question
74
     * @param String $sessionKey a hex sessionKey identifying the current session
75
     * @return String An OCRA response, the length of which is determined by the
76
     *             OCRA suite.
77
     */
78 2
    public function calculateResponse($secret, $challenge, $sessionKey) 
79
    {
80 2
        return $this->_calculateResponse($this->_ocraSuite, $secret, $challenge, $sessionKey);
81
    }
82
    
83
    /**
84
     * Calculate and verify an OCRA response.
85
     * @param String $response Expected OCRA response
86
     * @param String $secret a hex representation of the user's secret
87
     * @param String $challenge a hex or (alfa)numeric challenge question
88
     * @param String $sessionKey the sessionKey identifying the current session
89
     * @return Boolean True if response matches, false otherwise
90
     */
91 1
    public function verifyResponse($response, $secret, $challenge, $sessionKey)
92
    {
93 1
         $expected = $this->calculateResponse($secret, $challenge, $sessionKey);
94
95 1
         return ($expected == $response);
96
    }
97
98
    /**
99
     * derive the challenge configuration from an ocraSuite String
100
     * @param String $ocraSuite
101
     * @return Array an array with a format and length key. 
102
     *               - format determines what challenges should look like 
103
     *                 (H for Hex, A for alphanumeric, N for numeric)
104
     *               - length is the length of challenges
105
     */
106 2
    protected function _challengeConfig($ocraSuite)
107
    {
108
        // find the :QN10, -QN10, QH10 etc. bit
109 2
        $pos = stripos($ocraSuite, ":q");
110 2
        if ($pos===false) $pos = stripos($ocraSuite, "-q");
111 2
        if ($pos===false) {
112
            // No challenge config specified. Since we only support challenge based OCRA, we fallback to default 10 digit hexadecimal.
113
            return array("format"=>"H", "length"=>10);
114
        }
115 2
        $format = substr($ocraSuite, $pos+2, 1);
116 2
        if (!in_array($format, array("N", "A", "H"))) {
117
            $format = "H";
118
        }
119
        
120 2
        $length = (int)substr($ocraSuite, $pos+3, 2);
121
                
122 2
        if ($length<=0) {
123
            $length = 10;
124
        }
125
        
126 2
        return array("format"=>$format, "length"=>$length);
127
    }
128
    
129
    /**
130
     * Format a random set of bytes according to the ocrasuite's 
131
     * challenge configuration
132
     * @param String $challenge bytes containing a random challenge
133
     * @param String $format the format to return (H, A or N)
134
     * @param int $length The length of the desired challenge
135
     */
136 2
    protected function _formatChallenge($challenge, $format, $length)
137
    {
138
        // Convert random bytes to correct format.
139 2
        switch ($format) {
140 2
            case "H": 
141 2
                $result = bin2hex($challenge);
142 2
                break;
143
            case "A": 
144
                $result = bin2hex($challenge); // hex is alfanumeric, too
145
                break;
146
            case "N": 
147
                $result = '0';
148
                while (strlen($challenge)) {
149
                    $ord = ord(substr($challenge, 0, 1));
150
                    $result = bcadd(bcmul($result, 256), $ord);
151
                    $challenge = substr($challenge, 1);
152
                }
153
                break;
154
            default:
155
                $result = bin2hex($challenge);
156
        }        
157
        
158 2
        return substr($result, 0, $length); // simple truncate
159
    }
160
    
161
    /**
162
     * Generate a challenge string based on an ocraSuite
163
     * @param String $ocraSuite The ocrasuite that determines what the 
164
     *                          challenge will look like.
165
     * @return String An OCRA challenge that matches the specification of 
166
     *         the ocraSuite.
167
     */
168 2
    protected function _getChallenge($ocraSuite) 
169
    {
170 2
        $strong = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $strong is dead and can be removed.
Loading history...
171
        
172 2
        $conf = $this->_challengeConfig($ocraSuite);
173
        
174 2
        $length = $conf["length"];   
175
        
176 2
        $rnd = Tiqr_Random::randomBytes($length);
177
     
178 2
        return $this->_formatChallenge($rnd, $conf["format"], $length);
179
    }
180
    
181
    /**
182
     * Calculate an OCRA repsonse to a given OCRA challenge, according to
183
     * the algorithm specified by an OCRA Suite.
184
     * @param String $ocraSuite
185
     * @param String $secret a hex representation of the user's secret
186
     * @param String $challenge a hex or (alfa)numeric challenge question
187
     * @param String $sessionKey the sessionKey identifying the current session
188
     * @return int An OCRA response, the length of which is determined by the 
189
     *             OCRA suite.
190
     */
191 2
    protected function _calculateResponse($ocraSuite, $secret, $challenge, $sessionKey)
192
    {       
193 2
        if (strpos(strtolower($ocraSuite), "qn")!==false) {
194
            
195
            // challenge is decimal, but generateOcra always wants it in hex.
196
            $challenge = dechex($challenge);
0 ignored issues
show
Bug introduced by
$challenge of type string is incompatible with the type integer expected by parameter $num of dechex(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

196
            $challenge = dechex(/** @scrutinizer ignore-type */ $challenge);
Loading history...
197
            
198
        }
199
        // for some reason we're seeing the secret in lowercase.
200 2
        return OCRA_v1::generateOCRA($ocraSuite, strtoupper($secret), "", $challenge, "", $sessionKey, "");
0 ignored issues
show
Bug introduced by
$ocraSuite of type string is incompatible with the type the expected by parameter $ocraSuite of OCRA_v1::generateOCRA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

200
        return OCRA_v1::generateOCRA(/** @scrutinizer ignore-type */ $ocraSuite, strtoupper($secret), "", $challenge, "", $sessionKey, "");
Loading history...
Bug introduced by
$challenge of type string is incompatible with the type the expected by parameter $question of OCRA_v1::generateOCRA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

200
        return OCRA_v1::generateOCRA($ocraSuite, strtoupper($secret), "", /** @scrutinizer ignore-type */ $challenge, "", $sessionKey, "");
Loading history...
Bug introduced by
'' of type string is incompatible with the type the expected by parameter $counter of OCRA_v1::generateOCRA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

200
        return OCRA_v1::generateOCRA($ocraSuite, strtoupper($secret), /** @scrutinizer ignore-type */ "", $challenge, "", $sessionKey, "");
Loading history...
Bug Best Practice introduced by
The expression return OCRA_v1::generate...e, '', $sessionKey, '') returns the type A which is incompatible with the documented return type integer.
Loading history...
Bug introduced by
strtoupper($secret) of type string is incompatible with the type the expected by parameter $key of OCRA_v1::generateOCRA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

200
        return OCRA_v1::generateOCRA($ocraSuite, /** @scrutinizer ignore-type */ strtoupper($secret), "", $challenge, "", $sessionKey, "");
Loading history...
Bug introduced by
'' of type string is incompatible with the type a expected by parameter $password of OCRA_v1::generateOCRA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

200
        return OCRA_v1::generateOCRA($ocraSuite, strtoupper($secret), "", $challenge, /** @scrutinizer ignore-type */ "", $sessionKey, "");
Loading history...
Bug introduced by
'' of type string is incompatible with the type a expected by parameter $timeStamp of OCRA_v1::generateOCRA(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

200
        return OCRA_v1::generateOCRA($ocraSuite, strtoupper($secret), "", $challenge, "", $sessionKey, /** @scrutinizer ignore-type */ "");
Loading history...
201
202
    }
203
}