summaryrefslogtreecommitdiff
path: root/tests/test_generator.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_generator.py')
-rw-r--r--tests/test_generator.py278
1 files changed, 192 insertions, 86 deletions
diff --git a/tests/test_generator.py b/tests/test_generator.py
index 08947e5..68d3bfe 100644
--- a/tests/test_generator.py
+++ b/tests/test_generator.py
@@ -35,26 +35,26 @@ def test_caller_exceptions() -> None:
35 b'This is a test.', 'TeSt', otp2289.OTP_ALGO_MD5 35 b'This is a test.', 'TeSt', otp2289.OTP_ALGO_MD5
36 ) 36 )
37 with pytest.raises(otp2289.OTPGeneratorError) as exc_info: 37 with pytest.raises(otp2289.OTPGeneratorError) as exc_info:
38 gen.generate_otp_words('3') # ty: ignore[invalid-argument-type] 38 gen.generate_otp_response('3') # ty: ignore[invalid-argument-type]
39 assert exc_info.type is otp2289.OTPGeneratorError 39 assert exc_info.type is otp2289.OTPGeneratorError
40 assert exc_info.value.args[0] == 'Step value MUST be an int' 40 assert exc_info.value.args[0] == 'Step value MUST be an int'
41 with pytest.raises(otp2289.OTPGeneratorError) as exc_info: 41 with pytest.raises(otp2289.OTPGeneratorError) as exc_info:
42 gen.generate_otp_hexdigest(-1) 42 gen.generate_otp_response(-1)
43 assert exc_info.type is otp2289.OTPGeneratorError 43 assert exc_info.type is otp2289.OTPGeneratorError
44 assert exc_info.value.args[0] == 'Step value MUST be >= 0' 44 assert exc_info.value.args[0] == 'Step value MUST be >= 0'
45 with pytest.raises(otp2289.OTPChallengeError) as exc_info: 45 with pytest.raises(otp2289.OTPChallengeError) as exc_info:
46 gen.generate_otp_hexdigest_from_challenge( 46 gen.generate_otp_response_from_challenge(
47 b'md5 fbd TeSt' # ty: ignore[invalid-argument-type] 47 b'md5 fbd TeSt' # ty: ignore[invalid-argument-type]
48 ) 48 )
49 assert exc_info.type is otp2289.OTPChallengeError 49 assert exc_info.type is otp2289.OTPChallengeError
50 assert exc_info.value.args[0] == 'Challenge must be str' 50 assert exc_info.value.args[0] == 'Challenge must be str'
51 with pytest.raises(otp2289.OTPChallengeError) as exc_info: 51 with pytest.raises(otp2289.OTPChallengeError) as exc_info:
52 gen.generate_otp_hexdigest_from_challenge('md5 fbd TeSt') 52 gen.generate_otp_response_from_challenge('md5 fbd TeSt')
53 assert exc_info.type is otp2289.OTPChallengeError 53 assert exc_info.type is otp2289.OTPChallengeError
54 assert exc_info.value.args[0] == 'Invalid challenge' 54 assert exc_info.value.args[0] == 'Invalid challenge'
55 with pytest.raises(otp2289.generator.OTPChallengeError) as exc_info: 55 with pytest.raises(otp2289.OTPChallengeError) as exc_info:
56 gen.generate_otp_hexdigest_from_challenge('otp-md5 fbd TeSt') 56 gen.generate_otp_response_from_challenge('otp-md5 fbd TeSt')
57 assert exc_info.type is otp2289.generator.OTPChallengeError 57 assert exc_info.type is otp2289.OTPChallengeError
58 assert exc_info.value.args[0] == 'Invalid challenge' 58 assert exc_info.value.args[0] == 'Invalid challenge'
59 59
60 60
@@ -102,9 +102,9 @@ def test_constructor_exceptions() -> None:
102 assert exc_info.type is otp2289.OTPGeneratorError 102 assert exc_info.type is otp2289.OTPGeneratorError
103 assert exc_info.value.args[0] == 'hash_algo must be an int or a str' 103 assert exc_info.value.args[0] == 'hash_algo must be an int or a str'
104 # test the package structure as well 104 # test the package structure as well
105 with pytest.raises(otp2289.generator.OTPGeneratorError) as exc_info: 105 with pytest.raises(otp2289.OTPGeneratorError) as exc_info:
106 otp2289.generator.OTPGenerator(b'This is a test.', 'TeSt', 'foo') 106 otp2289.OTPGenerator(b'This is a test.', 'TeSt', 'foo')
107 assert exc_info.type is otp2289.generator.OTPGeneratorError 107 assert exc_info.type is otp2289.OTPGeneratorError
108 assert exc_info.value.args[0] == ( 108 assert exc_info.value.args[0] == (
109 'foo is not supported by this version of the hashlib module' 109 'foo is not supported by this version of the hashlib module'
110 ) 110 )
@@ -133,59 +133,148 @@ def test_md5() -> None:
133 gen = otp2289.OTPGenerator( 133 gen = otp2289.OTPGenerator(
134 b'This is a test.', 'TeSt', otp2289.OTP_ALGO_MD5 134 b'This is a test.', 'TeSt', otp2289.OTP_ALGO_MD5
135 ) 135 )
136 res_words = gen.generate_otp_words(0) 136 response = gen.generate_otp_response(0)
137 res_hex = gen.generate_otp_hexdigest(0) 137 assert isinstance(response, otp2289.OTPResponse)
138 assert isinstance(res_words, str) 138 assert isinstance(response.words, str)
139 assert isinstance(res_hex, str) 139 assert isinstance(response.hexdigest, str)
140 assert res_hex == '0x9e876134d90499dd' 140 assert response.hexdigest == '0x9e876134d90499dd'
141 assert res_words == 'INCH SEA ANNE LONG AHEM TOUR' 141 assert response.words == 'INCH SEA ANNE LONG AHEM TOUR'
142
142 # step 1 143 # step 1
143 assert gen.generate_otp_hexdigest(1) == '0x7965e05436f5029f' 144 response = gen.generate_otp_response(1)
144 assert gen.generate_otp_words(1) == 'EASE OIL FUM CURE AWRY AVIS' 145 assert response.hexdigest == '0x7965e05436f5029f'
145 assert gen.generate_otp_hexdigest_from_challenge('otp-md5 1 TeSt') == ( 146 assert response.words == 'EASE OIL FUM CURE AWRY AVIS'
146 '0x7965e05436f5029f' 147 assert (
148 gen.generate_otp_response_from_challenge('otp-md5 1 TeSt').hexdigest
149 == '0x7965e05436f5029f'
147 ) 150 )
148 assert gen.generate_otp_words_from_challenge('otp-md5 1 TeSt') == ( 151 assert (
149 'EASE OIL FUM CURE AWRY AVIS' 152 gen.generate_otp_response_from_challenge('otp-md5 1 TeSt').words
153 == 'EASE OIL FUM CURE AWRY AVIS'
150 ) 154 )
155
151 # step 99 156 # step 99
152 assert gen.generate_otp_hexdigest(99) == '0x50fe1962c4965880' 157 response = gen.generate_otp_response(99)
153 assert gen.generate_otp_words(99) == 'BAIL TUFT BITS GANG CHEF THY' 158 assert response.hexdigest == '0x50fe1962c4965880'
154 assert gen.generate_otp_hexdigest_from_challenge('otp-md5 99 TeSt') == ( 159 assert response.words == 'BAIL TUFT BITS GANG CHEF THY'
155 '0x50fe1962c4965880' 160 assert (
161 gen.generate_otp_response_from_challenge('otp-md5 99 TeSt').hexdigest
162 == '0x50fe1962c4965880'
156 ) 163 )
157 assert gen.generate_otp_words_from_challenge('otp-md5 99 TeSt') == ( 164 assert (
158 'BAIL TUFT BITS GANG CHEF THY' 165 gen.generate_otp_response_from_challenge('otp-md5 99 TeSt').words
166 == 'BAIL TUFT BITS GANG CHEF THY'
159 ) 167 )
168
160 # iterator test 169 # iterator test
161 hexdigests = list(gen.hexdigest_range(105)) # testing the range itself 170 hexdigests = list(gen.otp_response_range(105)) # testing the range itself
162 words = list(gen.words_range(99)) 171 words = list(gen.otp_response_range(99))
163 hexdigests.reverse() 172 hexdigests.reverse()
164 words.reverse() 173 words.reverse()
165 assert hexdigests[0] == '0x9e876134d90499dd' 174 assert hexdigests[0].hexdigest == '0x9e876134d90499dd'
166 assert hexdigests[1] == '0x7965e05436f5029f' 175 assert hexdigests[1].hexdigest == '0x7965e05436f5029f'
167 assert hexdigests[99] == '0x50fe1962c4965880' 176 assert hexdigests[99].hexdigest == '0x50fe1962c4965880'
168 assert words[0] == 'INCH SEA ANNE LONG AHEM TOUR' 177 assert words[0].words == 'INCH SEA ANNE LONG AHEM TOUR'
169 assert words[1] == 'EASE OIL FUM CURE AWRY AVIS' 178 assert words[1].words == 'EASE OIL FUM CURE AWRY AVIS'
170 assert words[99] == 'BAIL TUFT BITS GANG CHEF THY' 179 assert words[99].words == 'BAIL TUFT BITS GANG CHEF THY'
180
171 # pass='AbCdEfGhIjK', seed='alpha1' 181 # pass='AbCdEfGhIjK', seed='alpha1'
172 gen = otp2289.OTPGenerator(b'AbCdEfGhIjK', 'alpha1', otp2289.OTP_ALGO_MD5) 182 gen = otp2289.OTPGenerator(b'AbCdEfGhIjK', 'alpha1', otp2289.OTP_ALGO_MD5)
173 assert gen.generate_otp_hexdigest(0) == '0x87066dd9644bf206' 183 response = gen.generate_otp_response(0)
174 assert gen.generate_otp_words(0) == 'FULL PEW DOWN ONCE MORT ARC' 184 assert response.hexdigest == '0x87066dd9644bf206'
175 assert gen.generate_otp_hexdigest(1) == '0x7cd34c1040add14b' 185 assert response.words == 'FULL PEW DOWN ONCE MORT ARC'
176 assert gen.generate_otp_words(1) == 'FACT HOOF AT FIST SITE KENT' 186 response = gen.generate_otp_response(1)
177 assert gen.generate_otp_hexdigest(99) == '0x5aa37a81f212146c' 187 assert response.hexdigest == '0x7cd34c1040add14b'
178 assert gen.generate_otp_words(99) == 'BODE HOP JAKE STOW JUT RAP' 188 assert response.words == 'FACT HOOF AT FIST SITE KENT'
189 response = gen.generate_otp_response(99)
190 assert response.hexdigest == '0x5aa37a81f212146c'
191 assert response.words == 'BODE HOP JAKE STOW JUT RAP'
192
179 # pass="OTP's are good", seed='correct' 193 # pass="OTP's are good", seed='correct'
180 gen = otp2289.OTPGenerator( 194 gen = otp2289.OTPGenerator(
181 b"OTP's are good", 'correct', otp2289.OTP_ALGO_MD5 195 b"OTP's are good", 'correct', otp2289.OTP_ALGO_MD5
182 ) 196 )
183 assert gen.generate_otp_hexdigest(0) == '0xf205753943de4cf9' 197 response = gen.generate_otp_response(0)
184 assert gen.generate_otp_words(0) == 'ULAN NEW ARMY FUSE SUIT EYED' 198 assert response.hexdigest == '0xf205753943de4cf9'
185 assert gen.generate_otp_hexdigest(1) == '0xddcdac956f234937' 199 assert response.words == 'ULAN NEW ARMY FUSE SUIT EYED'
186 assert gen.generate_otp_words(1) == 'SKIM CULT LOB SLAM POE HOWL' 200 response = gen.generate_otp_response(1)
187 assert gen.generate_otp_hexdigest(99) == '0xb203e28fa525be47' 201 assert response.hexdigest == '0xddcdac956f234937'
188 assert gen.generate_otp_words(99) == 'LONG IVY JULY AJAR BOND LEE' 202 assert response.words == 'SKIM CULT LOB SLAM POE HOWL'
203 response = gen.generate_otp_response(99)
204 assert response.hexdigest == '0xb203e28fa525be47'
205 assert response.words == 'LONG IVY JULY AJAR BOND LEE'
206
207
208def test_otp_response() -> None:
209 """Tests OTPResponse"""
210 gen = otp2289.OTPGenerator(
211 b'This is a test.', 'TeSt', otp2289.OTP_ALGO_MD5
212 )
213 response = gen.generate_otp_response(0)
214 assert response.response_bytes == bytes(response)
215
216 # From 'RFC-2289 Appendix C - OTP Verification Examples'
217 # hexdigest: 9e876134d90499dd
218 # words: INCH SEA ANNE LONG AHEM TOUR
219 response_from_tokens = otp2289.OTPResponse.from_tokens(
220 'INCH SEA ANNE LONG AHEM TOUR'
221 )
222 response_from_hex1 = otp2289.OTPResponse.from_hex('9e876134d90499dd')
223 response_from_hex2 = otp2289.OTPResponse.from_hex('0x9e876134d90499dd')
224 assert (
225 response_from_tokens.response_bytes
226 == response_from_hex1.response_bytes
227 )
228 assert (
229 response_from_tokens.response_bytes
230 == response_from_hex2.response_bytes
231 )
232
233 # same tests, only using __eq__
234 assert response_from_tokens == response_from_hex1
235 assert response_from_tokens == response_from_hex2
236
237
238def test_otp_response_exceptions() -> None:
239 """Tests OTPResponse exceptions"""
240 with pytest.raises(otp2289.OTPResponseError) as exc_info:
241 otp2289.OTPResponse.from_hex(
242 b'9e876134d90499dd' # ty: ignore[invalid-argument-type]
243 )
244 assert exc_info.type is otp2289.OTPResponseError
245 assert exc_info.value.args[0] == 'OT-hex must be a str'
246 with pytest.raises(otp2289.OTPResponseError) as exc_info:
247 otp2289.OTPResponse.from_hex('9e876134d90499d')
248 assert exc_info.type is otp2289.OTPResponseError
249 assert exc_info.value.args[0] == (
250 'The length of the hex should be 16 (representing 64 bits digest)'
251 )
252 with pytest.raises(otp2289.OTPResponseError) as exc_info:
253 otp2289.OTPResponse.from_hex('9e876134d90499dg')
254 assert exc_info.type is otp2289.OTPResponseError
255 assert exc_info.value.args[0] == 'Invalid OT-hex'
256
257 # .from_tokens
258 with pytest.raises(otp2289.OTPResponseError) as exc_info:
259 otp2289.OTPResponse.from_tokens(
260 b'INCH SEA ANNE LONG AHEM TOUR' # ty: ignore[invalid-argument-type]
261 )
262 assert exc_info.type is otp2289.OTPResponseError
263 assert exc_info.value.args[0] == 'tokens must be a str'
264 with pytest.raises(otp2289.OTPResponseError) as exc_info:
265 otp2289.OTPResponse.from_tokens('INCH SEA ANNE LONG AHEM')
266 assert exc_info.type is otp2289.OTPResponseError
267 assert exc_info.value.args[0] == 'Tokens-string does not contain 6 tokens'
268 with pytest.raises(otp2289.OTPResponseError) as exc_info:
269 otp2289.OTPResponse.from_tokens('INCH SEA ANNE LONG AHEM SIMEON')
270 assert exc_info.type is otp2289.OTPResponseError
271 assert exc_info.value.args[0] == (
272 'One or more words not present in RFC1760'
273 )
274 with pytest.raises(otp2289.OTPResponseError) as exc_info:
275 otp2289.OTPResponse.from_tokens('INCH SEA ANNE LONG AHEM LEE')
276 assert exc_info.type is otp2289.OTPResponseError
277 assert exc_info.value.args[0] == 'Invalid bit checksum'
189 278
190 279
191def test_sha1() -> None: 280def test_sha1() -> None:
@@ -198,54 +287,71 @@ def test_sha1() -> None:
198 gen = otp2289.OTPGenerator( 287 gen = otp2289.OTPGenerator(
199 b'This is a test.', 'TeSt', otp2289.OTP_ALGO_SHA1 288 b'This is a test.', 'TeSt', otp2289.OTP_ALGO_SHA1
200 ) 289 )
201 res_hex = gen.generate_otp_hexdigest(step=0) 290 response = gen.generate_otp_response(step=0)
202 res_words = gen.generate_otp_words(step=0) 291 assert isinstance(response, otp2289.OTPResponse)
203 assert isinstance(res_words, str) 292 assert isinstance(response.words, str)
204 assert isinstance(res_hex, str) 293 assert isinstance(response.hexdigest, str)
205 assert res_hex == '0xbb9e6ae1979d8ff4' 294 assert response.hexdigest == '0xbb9e6ae1979d8ff4'
206 assert res_words == 'MILT VARY MAST OK SEES WENT' 295 assert response.words == 'MILT VARY MAST OK SEES WENT'
207 assert gen.generate_otp_hexdigest(1) == '0x63d936639734385b' 296 response = gen.generate_otp_response(1)
208 assert gen.generate_otp_words(1) == 'CART OTTO HIVE ODE VAT NUT' 297 assert response.hexdigest == '0x63d936639734385b'
209 assert gen.generate_otp_hexdigest_from_challenge('otp-sha1 1 TeSt') == ( 298 assert response.words == 'CART OTTO HIVE ODE VAT NUT'
210 '0x63d936639734385b' 299 assert (
300 gen.generate_otp_response_from_challenge('otp-sha1 1 TeSt').hexdigest
301 == '0x63d936639734385b'
211 ) 302 )
212 assert gen.generate_otp_words_from_challenge('otp-sha1 1 TeSt') == ( 303 assert (
213 'CART OTTO HIVE ODE VAT NUT' 304 gen.generate_otp_response_from_challenge('otp-sha1 1 TeSt').words
305 == 'CART OTTO HIVE ODE VAT NUT'
214 ) 306 )
215 assert gen.generate_otp_hexdigest(99) == '0x87fec7768b73ccf9' 307 response = gen.generate_otp_response(99)
216 assert gen.generate_otp_words(99) == 'GAFF WAIT SKID GIG SKY EYED' 308 assert response.hexdigest == '0x87fec7768b73ccf9'
217 assert gen.generate_otp_hexdigest_from_challenge('otp-sha1 99 TeSt') == ( 309 assert response.words == 'GAFF WAIT SKID GIG SKY EYED'
218 '0x87fec7768b73ccf9' 310 assert (
311 gen.generate_otp_response_from_challenge(
312 'otp-sha1 99 TeSt'
313 ).hexdigest
314 == '0x87fec7768b73ccf9'
219 ) 315 )
220 assert gen.generate_otp_words_from_challenge('otp-sha1 99 TeSt') == ( 316 assert (
221 'GAFF WAIT SKID GIG SKY EYED' 317 gen.generate_otp_response_from_challenge('otp-sha1 99 TeSt').words
318 == 'GAFF WAIT SKID GIG SKY EYED'
222 ) 319 )
320
223 # iterator test 321 # iterator test
224 hexdigests = list(gen.hexdigest_range(105)) 322 hexdigests = list(gen.otp_response_range(105))
225 words = list(gen.words_range(99)) 323 words = list(gen.otp_response_range(99))
226 hexdigests.reverse() 324 hexdigests.reverse()
227 words.reverse() 325 words.reverse()
228 assert hexdigests[0] == '0xbb9e6ae1979d8ff4' 326 assert hexdigests[0].hexdigest == '0xbb9e6ae1979d8ff4'
229 assert hexdigests[1] == '0x63d936639734385b' 327 assert hexdigests[1].hexdigest == '0x63d936639734385b'
230 assert hexdigests[99] == '0x87fec7768b73ccf9' 328 assert hexdigests[99].hexdigest == '0x87fec7768b73ccf9'
231 assert words[0] == 'MILT VARY MAST OK SEES WENT' 329 assert words[0].words == 'MILT VARY MAST OK SEES WENT'
232 assert words[1] == 'CART OTTO HIVE ODE VAT NUT' 330 assert words[1].words == 'CART OTTO HIVE ODE VAT NUT'
233 assert words[99] == 'GAFF WAIT SKID GIG SKY EYED' 331 assert words[99].words == 'GAFF WAIT SKID GIG SKY EYED'
332
234 # pass='AbCdEfGhIjK', seed='alpha1' 333 # pass='AbCdEfGhIjK', seed='alpha1'
235 gen = otp2289.OTPGenerator(b'AbCdEfGhIjK', 'alpha1', otp2289.OTP_ALGO_SHA1) 334 gen = otp2289.OTPGenerator(b'AbCdEfGhIjK', 'alpha1', otp2289.OTP_ALGO_SHA1)
236 assert gen.generate_otp_hexdigest(0) == '0xad85f658ebe383c9' 335 response = gen.generate_otp_response(0)
237 assert gen.generate_otp_words(0) == 'LEST OR HEEL SCOT ROB SUIT' 336 assert response.hexdigest == '0xad85f658ebe383c9'
238 assert gen.generate_otp_hexdigest(1) == '0xd07ce229b5cf119b' 337 assert response.words == 'LEST OR HEEL SCOT ROB SUIT'
239 assert gen.generate_otp_words(1) == 'RITE TAKE GELD COST TUNE RECK' 338 response = gen.generate_otp_response(1)
240 assert gen.generate_otp_hexdigest(99) == '0x27bc71035aaf3dc6' 339 assert response.hexdigest == '0xd07ce229b5cf119b'
241 assert gen.generate_otp_words(99) == 'MAY STAR TIN LYON VEDA STAN' 340 assert response.words == 'RITE TAKE GELD COST TUNE RECK'
341 response = gen.generate_otp_response(99)
342 assert response.hexdigest == '0x27bc71035aaf3dc6'
343 assert response.words == 'MAY STAR TIN LYON VEDA STAN'
344
242 # pass="OTP's are good", seed='correct' 345 # pass="OTP's are good", seed='correct'
243 gen = otp2289.OTPGenerator( 346 gen = otp2289.OTPGenerator(
244 b"OTP's are good", 'correct', otp2289.OTP_ALGO_SHA1 347 b"OTP's are good", 'correct', otp2289.OTP_ALGO_SHA1
245 ) 348 )
246 assert gen.generate_otp_hexdigest(0) == '0xd51f3e99bf8e6f0b' 349 response = gen.generate_otp_response(0)
247 assert gen.generate_otp_words(0) == 'RUST WELT KICK FELL TAIL FRAU' 350 assert response.hexdigest == '0xd51f3e99bf8e6f0b'
248 assert gen.generate_otp_hexdigest(1) == '0x82aeb52d943774e4' 351 assert response.words == 'RUST WELT KICK FELL TAIL FRAU'
249 assert gen.generate_otp_words(1) == 'FLIT DOSE ALSO MEW DRUM DEFY' 352 response = gen.generate_otp_response(1)
250 assert gen.generate_otp_hexdigest(99) == '0x4f296a74fe1567ec' 353 assert response.hexdigest == '0x82aeb52d943774e4'
251 assert gen.generate_otp_words(99) == 'AURA ALOE HURL WING BERG WAIT' 354 assert response.words == 'FLIT DOSE ALSO MEW DRUM DEFY'
355 response = gen.generate_otp_response(99)
356 assert response.hexdigest == '0x4f296a74fe1567ec'
357 assert response.words == 'AURA ALOE HURL WING BERG WAIT'