Passed
Branch develop (e3abb6)
by Pieter van der
06:20
created
library/tiqr/OATH/OCRAParser.php 1 patch
Indentation   +229 added lines, -229 removed lines patch added patch discarded remove patch
@@ -4,241 +4,241 @@
 block discarded – undo
4 4
 
5 5
 class OATH_OCRAParser {
6 6
 
7
-	private $key = NULL;
8
-
9
-	private $OCRASuite = NULL;
10
-
11
-	private $OCRAVersion = NULL;
12
-
13
-	private $CryptoFunctionType = NULL;
14
-	private $CryptoFunctionHash = NULL;
15
-	private $CryptoFunctionHashLength = NULL;
16
-	private $CryptoFunctionTruncation = NULL;
17
-
18
-	private $C = FALSE;
19
-	private $Q = FALSE;
20
-	private $QType = 'N';
21
-	private $QLength = 8;
22
-
23
-	private $P = FALSE;
24
-	private $PType = 'SHA1';
25
-	private $PLength = 20;
26
-
27
-	private $S = FALSE;
28
-	private $SLength = 64;
29
-
30
-	private $T = FALSE;
31
-	private $TLength = 60; // 1M
32
-	private $TPeriods = array('H' => 3600, 'M' => 60, 'S' => 1);
33
-
34
-	private $supportedHashFunctions = array('SHA1' => 20, 'SHA256' => 32, 'SHA512' => 64);
35
-
36
-
37
-	public function __construct($ocraSuite) {
38
-		$this->parseOCRASuite($ocraSuite);
39
-	}
40
-
41
-	/**
42
-	 * Inspired by https://github.com/bdauvergne/python-oath
43
-	 */
44
-	private function parseOCRASuite($ocraSuite) {
45
-		if (!is_string($ocraSuite)) {
46
-			throw new Exception('OCRASuite not in string format: ' . var_export($ocraSuite, TRUE));
47
-		}
48
-
49
-		$ocraSuite = strtoupper($ocraSuite);
50
-		$this->OCRASuite = $ocraSuite;
51
-
52
-		$s = explode(':', $ocraSuite);
53
-		if (count($s) != 3) {
54
-			throw new Exception('Invalid OCRASuite format: ' . var_export($ocraSuite, TRUE));
55
-		}
56
-
57
-		$algo = explode('-', $s[0]);
58
-		if (count($algo) != 2) {
59
-			throw new Exception('Invalid OCRA version: ' . var_export($s[0], TRUE));
60
-		}
61
-
62
-		if ($algo[0] !== 'OCRA') {
63
-			throw new Exception('Unsupported OCRA algorithm: ' . var_export($algo[0], TRUE));
64
-		}
65
-
66
-		if ($algo[1] !== '1') {
67
-			throw new Exception('Unsupported OCRA version: ' . var_export($algo[1], TRUE));
68
-		}
69
-		$this->OCRAVersion = $algo[1];
70
-
71
-		$cf = explode('-', $s[1]);
72
-		if (count($cf) != 3) {
73
-			throw new Exception('Invalid OCRA suite crypto function: ' . var_export($s[1], TRUE));
74
-		}
75
-
76
-		if ($cf[0] !== 'HOTP') {
77
-			throw new Exception('Unsupported OCRA suite crypto function: ' . var_export($cf[0], TRUE));
78
-		}
79
-		$this->CryptoFunctionType = $cf[0];
80
-
81
-		if (!array_key_exists($cf[1], $this->supportedHashFunctions)) {
82
-			throw new Exception('Unsupported hash function in OCRA suite crypto function: ' . var_export($cf[1], TRUE));
83
-		}
84
-		$this->CryptoFunctionHash = $cf[1];
85
-		$this->CryptoFunctionHashLength = $this->supportedHashFunctions[$cf[1]];
86
-
87
-		if (!preg_match('/^\d+$/', $cf[2]) || (($cf[2] < 4 || $cf[2] > 10) && $cf[2] != 0)) {
88
-			throw new Exception('Invalid OCRA suite crypto function truncation length: ' . var_export($cf[2], TRUE));
89
-		}
90
-		$this->CryptoFunctionTruncation = intval($cf[2]);
91
-
92
-		$di = explode('-', $s[2]);
93
-		if (count($cf) == 0) {
94
-			throw new Exception('Invalid OCRA suite data input: ' . var_export($s[2], TRUE));
95
-		}
96
-
97
-		$data_input = array();
98
-		foreach($di as $elem) {
99
-			$letter = $elem[0];
100
-			if (array_key_exists($letter, $data_input)) {
101
-				throw new Exception('Duplicate field in OCRA suite data input: ' . var_export($elem, TRUE));
102
-			}
103
-			$data_input[$letter] = 1;
104
-
105
-			if ($letter === 'C' && strlen($elem) == 1) {
106
-				$this->C = TRUE;
107
-			} elseif ($letter === 'Q') {
108
-				if (strlen($elem) == 1) {
109
-					$this->Q = TRUE;
110
-				} elseif (preg_match('/^Q([AHN])(\d+)$/', $elem, $match)) {
111
-					$q_len = intval($match[2]);
112
-					if ($q_len < 4 || $q_len > 64) {
113
-						throw new Exception('Invalid OCRA suite data input question length: ' . var_export($q_len, TRUE));
114
-					}
115
-					$this->Q = TRUE;
116
-					$this->QType = $match[1];
117
-					$this->QLength = $q_len;
118
-				} else {
119
-					throw new Exception('Invalid OCRA suite data input question: ' . var_export($elem, TRUE));
120
-				}
121
-			} elseif ($letter === 'P') {
122
-				if (strlen($elem) == 1) {
123
-					$this->P = TRUE;
124
-				} else {
125
-					$p_algo = substr($elem, 1);
126
-					if (!array_key_exists($p_algo, $this->supportedHashFunctions)) {
127
-						throw new Exception('Unsupported OCRA suite PIN hash function: ' . var_export($elem, TRUE));
128
-					}
129
-					$this->P = TRUE;
130
-					$this->PType = $p_algo;
131
-					$this->PLength = $this->supportedHashFunctions[$p_algo];
132
-				}
133
-			} elseif ($letter === 'S') {
134
-				if (strlen($elem) == 1) {
135
-					$this->S = TRUE;
136
-				} elseif (preg_match('/^S(\d+)$/', $elem, $match)) {
137
-					$s_len = intval($match[1]);
138
-					if ($s_len <= 0 || $s_len > 512) {
139
-						throw new Exception('Invalid OCRA suite data input session information length: ' . var_export($s_len, TRUE));
140
-					}
141
-
142
-					$this->S = TRUE;
143
-					$this->SLength = $s_len;
144
-				} else {
145
-					throw new Exception('Invalid OCRA suite data input session information length: ' . var_export($elem, TRUE));
146
-				}
147
-			} elseif ($letter === 'T') {
148
-				if (strlen($elem) == 1) {
149
-					$this->T = TRUE;
150
-				} elseif (preg_match('/^T(\d+[HMS])+$/', $elem)) {
151
-					preg_match_all('/(\d+)([HMS])/', $elem, $match);
152
-
153
-					if (count($match[1]) !== count(array_unique($match[2]))) {
154
-						throw new Exception('Duplicate definitions in OCRA suite data input timestamp: ' . var_export($elem, TRUE));
155
-					}
156
-
157
-					$length = 0;
158
-					for ($i = 0; $i < count($match[1]); $i++) {
159
-						$length += intval($match[1][$i]) * $this->TPeriods[$match[2][$i]];
160
-					}
161
-					if ($length <= 0) {
162
-						throw new Exception('Invalid OCRA suite data input timestamp: ' . var_export($elem, TRUE));
163
-					}
164
-
165
-					$this->T = TRUE;
166
-					$this->TLength = $length;
167
-				} else {
168
-					throw new Exception('Invalid OCRA suite data input timestamp: ' . var_export($elem, TRUE));
169
-				}
170
-			} else {
171
-				throw new Exception('Unsupported OCRA suite data input field: ' . var_export($elem, TRUE));
172
-			}
173
-		}
174
-
175
-		if (!$this->Q) {
176
-			throw new Exception('OCRA suite data input question not defined: ' . var_export($s[2], TRUE));
177
-		}
178
-	}
179
-
180
-	public function generateChallenge() {
181
-		$q_length = $this->QLength;
182
-		$q_type = $this->QType;
7
+    private $key = NULL;
8
+
9
+    private $OCRASuite = NULL;
10
+
11
+    private $OCRAVersion = NULL;
12
+
13
+    private $CryptoFunctionType = NULL;
14
+    private $CryptoFunctionHash = NULL;
15
+    private $CryptoFunctionHashLength = NULL;
16
+    private $CryptoFunctionTruncation = NULL;
17
+
18
+    private $C = FALSE;
19
+    private $Q = FALSE;
20
+    private $QType = 'N';
21
+    private $QLength = 8;
22
+
23
+    private $P = FALSE;
24
+    private $PType = 'SHA1';
25
+    private $PLength = 20;
26
+
27
+    private $S = FALSE;
28
+    private $SLength = 64;
29
+
30
+    private $T = FALSE;
31
+    private $TLength = 60; // 1M
32
+    private $TPeriods = array('H' => 3600, 'M' => 60, 'S' => 1);
33
+
34
+    private $supportedHashFunctions = array('SHA1' => 20, 'SHA256' => 32, 'SHA512' => 64);
35
+
36
+
37
+    public function __construct($ocraSuite) {
38
+        $this->parseOCRASuite($ocraSuite);
39
+    }
40
+
41
+    /**
42
+     * Inspired by https://github.com/bdauvergne/python-oath
43
+     */
44
+    private function parseOCRASuite($ocraSuite) {
45
+        if (!is_string($ocraSuite)) {
46
+            throw new Exception('OCRASuite not in string format: ' . var_export($ocraSuite, TRUE));
47
+        }
48
+
49
+        $ocraSuite = strtoupper($ocraSuite);
50
+        $this->OCRASuite = $ocraSuite;
51
+
52
+        $s = explode(':', $ocraSuite);
53
+        if (count($s) != 3) {
54
+            throw new Exception('Invalid OCRASuite format: ' . var_export($ocraSuite, TRUE));
55
+        }
56
+
57
+        $algo = explode('-', $s[0]);
58
+        if (count($algo) != 2) {
59
+            throw new Exception('Invalid OCRA version: ' . var_export($s[0], TRUE));
60
+        }
61
+
62
+        if ($algo[0] !== 'OCRA') {
63
+            throw new Exception('Unsupported OCRA algorithm: ' . var_export($algo[0], TRUE));
64
+        }
65
+
66
+        if ($algo[1] !== '1') {
67
+            throw new Exception('Unsupported OCRA version: ' . var_export($algo[1], TRUE));
68
+        }
69
+        $this->OCRAVersion = $algo[1];
70
+
71
+        $cf = explode('-', $s[1]);
72
+        if (count($cf) != 3) {
73
+            throw new Exception('Invalid OCRA suite crypto function: ' . var_export($s[1], TRUE));
74
+        }
75
+
76
+        if ($cf[0] !== 'HOTP') {
77
+            throw new Exception('Unsupported OCRA suite crypto function: ' . var_export($cf[0], TRUE));
78
+        }
79
+        $this->CryptoFunctionType = $cf[0];
80
+
81
+        if (!array_key_exists($cf[1], $this->supportedHashFunctions)) {
82
+            throw new Exception('Unsupported hash function in OCRA suite crypto function: ' . var_export($cf[1], TRUE));
83
+        }
84
+        $this->CryptoFunctionHash = $cf[1];
85
+        $this->CryptoFunctionHashLength = $this->supportedHashFunctions[$cf[1]];
86
+
87
+        if (!preg_match('/^\d+$/', $cf[2]) || (($cf[2] < 4 || $cf[2] > 10) && $cf[2] != 0)) {
88
+            throw new Exception('Invalid OCRA suite crypto function truncation length: ' . var_export($cf[2], TRUE));
89
+        }
90
+        $this->CryptoFunctionTruncation = intval($cf[2]);
91
+
92
+        $di = explode('-', $s[2]);
93
+        if (count($cf) == 0) {
94
+            throw new Exception('Invalid OCRA suite data input: ' . var_export($s[2], TRUE));
95
+        }
96
+
97
+        $data_input = array();
98
+        foreach($di as $elem) {
99
+            $letter = $elem[0];
100
+            if (array_key_exists($letter, $data_input)) {
101
+                throw new Exception('Duplicate field in OCRA suite data input: ' . var_export($elem, TRUE));
102
+            }
103
+            $data_input[$letter] = 1;
104
+
105
+            if ($letter === 'C' && strlen($elem) == 1) {
106
+                $this->C = TRUE;
107
+            } elseif ($letter === 'Q') {
108
+                if (strlen($elem) == 1) {
109
+                    $this->Q = TRUE;
110
+                } elseif (preg_match('/^Q([AHN])(\d+)$/', $elem, $match)) {
111
+                    $q_len = intval($match[2]);
112
+                    if ($q_len < 4 || $q_len > 64) {
113
+                        throw new Exception('Invalid OCRA suite data input question length: ' . var_export($q_len, TRUE));
114
+                    }
115
+                    $this->Q = TRUE;
116
+                    $this->QType = $match[1];
117
+                    $this->QLength = $q_len;
118
+                } else {
119
+                    throw new Exception('Invalid OCRA suite data input question: ' . var_export($elem, TRUE));
120
+                }
121
+            } elseif ($letter === 'P') {
122
+                if (strlen($elem) == 1) {
123
+                    $this->P = TRUE;
124
+                } else {
125
+                    $p_algo = substr($elem, 1);
126
+                    if (!array_key_exists($p_algo, $this->supportedHashFunctions)) {
127
+                        throw new Exception('Unsupported OCRA suite PIN hash function: ' . var_export($elem, TRUE));
128
+                    }
129
+                    $this->P = TRUE;
130
+                    $this->PType = $p_algo;
131
+                    $this->PLength = $this->supportedHashFunctions[$p_algo];
132
+                }
133
+            } elseif ($letter === 'S') {
134
+                if (strlen($elem) == 1) {
135
+                    $this->S = TRUE;
136
+                } elseif (preg_match('/^S(\d+)$/', $elem, $match)) {
137
+                    $s_len = intval($match[1]);
138
+                    if ($s_len <= 0 || $s_len > 512) {
139
+                        throw new Exception('Invalid OCRA suite data input session information length: ' . var_export($s_len, TRUE));
140
+                    }
141
+
142
+                    $this->S = TRUE;
143
+                    $this->SLength = $s_len;
144
+                } else {
145
+                    throw new Exception('Invalid OCRA suite data input session information length: ' . var_export($elem, TRUE));
146
+                }
147
+            } elseif ($letter === 'T') {
148
+                if (strlen($elem) == 1) {
149
+                    $this->T = TRUE;
150
+                } elseif (preg_match('/^T(\d+[HMS])+$/', $elem)) {
151
+                    preg_match_all('/(\d+)([HMS])/', $elem, $match);
152
+
153
+                    if (count($match[1]) !== count(array_unique($match[2]))) {
154
+                        throw new Exception('Duplicate definitions in OCRA suite data input timestamp: ' . var_export($elem, TRUE));
155
+                    }
156
+
157
+                    $length = 0;
158
+                    for ($i = 0; $i < count($match[1]); $i++) {
159
+                        $length += intval($match[1][$i]) * $this->TPeriods[$match[2][$i]];
160
+                    }
161
+                    if ($length <= 0) {
162
+                        throw new Exception('Invalid OCRA suite data input timestamp: ' . var_export($elem, TRUE));
163
+                    }
164
+
165
+                    $this->T = TRUE;
166
+                    $this->TLength = $length;
167
+                } else {
168
+                    throw new Exception('Invalid OCRA suite data input timestamp: ' . var_export($elem, TRUE));
169
+                }
170
+            } else {
171
+                throw new Exception('Unsupported OCRA suite data input field: ' . var_export($elem, TRUE));
172
+            }
173
+        }
174
+
175
+        if (!$this->Q) {
176
+            throw new Exception('OCRA suite data input question not defined: ' . var_export($s[2], TRUE));
177
+        }
178
+    }
179
+
180
+    public function generateChallenge() {
181
+        $q_length = $this->QLength;
182
+        $q_type = $this->QType;
183 183
 
184 184
         $bytes = Tiqr_Random::randomBytes($q_length);
185 185
 
186
-		switch($q_type) {
187
-			case 'A':
188
-				$challenge = base64_encode($bytes);
189
-				$tr = implode("", unpack('H*', $bytes));
190
-				$challenge = rtrim(strtr($challenge, '+/', $tr), '=');
191
-				break;
192
-			case 'H':
193
-				$challenge = implode("", unpack('H*', $bytes));
194
-				break;
195
-			case 'N':
196
-				$challenge = implode("", unpack('N*', $bytes));
197
-				break;
198
-			default:
199
-				throw new Exception('Unsupported OCRASuite challenge type: ' . var_export($q_type, TRUE));
200
-				break;
201
-		}
202
-
203
-		$challenge = substr($challenge, 0, $q_length);
204
-
205
-		return $challenge;
206
-	}
207
-
208
-
209
-	public function generateSessionInformation() {
210
-		if (!$this->S) {
211
-			throw new Exception('Session information not defined in OCRASuite: ' . var_export($this->OCRASuite, TRUE));
212
-		}
213
-
214
-		$s_length = $this->SLength;
186
+        switch($q_type) {
187
+            case 'A':
188
+                $challenge = base64_encode($bytes);
189
+                $tr = implode("", unpack('H*', $bytes));
190
+                $challenge = rtrim(strtr($challenge, '+/', $tr), '=');
191
+                break;
192
+            case 'H':
193
+                $challenge = implode("", unpack('H*', $bytes));
194
+                break;
195
+            case 'N':
196
+                $challenge = implode("", unpack('N*', $bytes));
197
+                break;
198
+            default:
199
+                throw new Exception('Unsupported OCRASuite challenge type: ' . var_export($q_type, TRUE));
200
+                break;
201
+        }
202
+
203
+        $challenge = substr($challenge, 0, $q_length);
204
+
205
+        return $challenge;
206
+    }
207
+
208
+
209
+    public function generateSessionInformation() {
210
+        if (!$this->S) {
211
+            throw new Exception('Session information not defined in OCRASuite: ' . var_export($this->OCRASuite, TRUE));
212
+        }
213
+
214
+        $s_length = $this->SLength;
215 215
         $bytes = Tiqr_Random::randomBytes($s_length);
216 216
 
217
-		// The OCRA spec doesn't specify that the session data should be hexadecimal.
218
-		// However the reference implementation in the RFC does treat it as hex.
219
-		$session = bin2hex($bytes);
217
+        // The OCRA spec doesn't specify that the session data should be hexadecimal.
218
+        // However the reference implementation in the RFC does treat it as hex.
219
+        $session = bin2hex($bytes);
220 220
 		
221
-		$session = substr($session, 0, $s_length);
221
+        $session = substr($session, 0, $s_length);
222 222
 		
223
-		return $session;
224
-	}
225
-
226
-
227
-	/**
228
-	 * Constant time string comparison, see http://codahale.com/a-lesson-in-timing-attacks/
229
-	 */
230
-	public static function constEqual($s1, $s2) {
231
-		if (strlen($s1) != strlen($s2)) {
232
-			return FALSE;
233
-		}
234
-
235
-		$result = TRUE;
236
-		$length = strlen($s1);
237
-		for ($i = 0; $i < $length; $i++) {
238
-			$result &= ($s1[$i] == $s2[$i]);
239
-		}
240
-
241
-		return (boolean)$result;
242
-	}
223
+        return $session;
224
+    }
225
+
226
+
227
+    /**
228
+     * Constant time string comparison, see http://codahale.com/a-lesson-in-timing-attacks/
229
+     */
230
+    public static function constEqual($s1, $s2) {
231
+        if (strlen($s1) != strlen($s2)) {
232
+            return FALSE;
233
+        }
234
+
235
+        $result = TRUE;
236
+        $length = strlen($s1);
237
+        for ($i = 0; $i < $length; $i++) {
238
+            $result &= ($s1[$i] == $s2[$i]);
239
+        }
240
+
241
+        return (boolean)$result;
242
+    }
243 243
 
244 244
 }
Please login to merge, or discard this patch.