summaryrefslogtreecommitdiff
path: root/test/test_generator.py
diff options
context:
space:
mode:
authorSimeon Simeonov2023-01-08 23:39:45 +0100
committerSimeon Simeonov2023-01-08 23:39:45 +0100
commite9f45a50dd3f92a4082bec6dc33c4aa0f919138a (patch)
treedcfc89aa5aacaaf97072da9d0d0517c3b367176b /test/test_generator.py
parentb8fa40b48feb8709d27b1c50f1ea6be2ce081692 (diff)
Include the tests in the sdist packagev1.2.1
Diffstat (limited to 'test/test_generator.py')
-rw-r--r--test/test_generator.py280
1 files changed, 280 insertions, 0 deletions
diff --git a/test/test_generator.py b/test/test_generator.py
new file mode 100644
index 0000000..b4bb961
--- /dev/null
+++ b/test/test_generator.py
@@ -0,0 +1,280 @@
1# -*- coding: utf-8 -*-
2# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3#
4# Copyright (c) 2020-2023, Simeon Simeonov
5# All rights reserved.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions
9# are met:
10# 1. Redistributions of source code must retain the above copyright
11# notice, this list of conditions and the following disclaimer.
12# 2. Redistributions in binary form must reproduce the above copyright notice,
13# this list of conditions and the following disclaimer in the documentation
14# and/or other materials provided with the distribution.
15#
16# THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
17# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26"""Tests for otp2289.generator"""
27import pytest
28
29import otp2289
30
31
32def test_caller_exceptions():
33 """Tests the exceptions when calling an initialized object"""
34 gen = otp2289.OTPGenerator(
35 'This is a test.'.encode(),
36 'TeSt',
37 otp2289.OTP_ALGO_MD5,
38 )
39 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
40 gen.generate_otp_words('3')
41 assert exc_info.type is otp2289.OTPGeneratorException
42 assert exc_info.value.args[0] == 'Step value MUST be an int'
43 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
44 gen.generate_otp_hexdigest(-1)
45 assert exc_info.type is otp2289.OTPGeneratorException
46 assert exc_info.value.args[0] == 'Step value MUST be >= 0'
47 with pytest.raises(otp2289.OTPChallengeException) as exc_info:
48 gen.generate_otp_hexdigest_from_challenge(b'md5 fbd TeSt')
49 assert exc_info.type is otp2289.OTPChallengeException
50 assert exc_info.value.args[0] == 'Challenge must be str'
51 with pytest.raises(otp2289.OTPChallengeException) as exc_info:
52 gen.generate_otp_hexdigest_from_challenge('md5 fbd TeSt')
53 assert exc_info.type is otp2289.OTPChallengeException
54 assert exc_info.value.args[0] == 'Invalid challenge'
55 with pytest.raises(otp2289.generator.OTPChallengeException) as exc_info:
56 gen.generate_otp_hexdigest_from_challenge('otp-md5 fbd TeSt')
57 assert exc_info.type is otp2289.generator.OTPChallengeException
58 assert exc_info.value.args[0] == 'Invalid challenge'
59
60
61def test_constructor_exceptions():
62 """
63 Tests the exceptions when initializing a new object (in the constructor)
64 """
65 # test the otp2289.OTPGenerator __init__ and validators
66 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
67 otp2289.OTPGenerator(
68 'This is a test.'.encode(),
69 'TeStø'.encode(),
70 otp2289.OTP_ALGO_MD5,
71 )
72 assert exc_info.type is otp2289.OTPGeneratorException
73 assert exc_info.value.args[0] == 'Seed must be a string'
74 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
75 otp2289.OTPGenerator(
76 'This is a test.'.encode(),
77 'TeStøtEsTteSTteStTest',
78 otp2289.OTP_ALGO_SHA1,
79 )
80 assert exc_info.type is otp2289.OTPGeneratorException
81 assert exc_info.value.args[0] == (
82 'The seed MUST be of 1 to 16 characters in length'
83 )
84 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
85 otp2289.OTPGenerator(
86 'This is a test.'.encode(),
87 'TeStø',
88 otp2289.OTP_ALGO_SHA1,
89 )
90 assert exc_info.type is otp2289.OTPGeneratorException
91 assert exc_info.value.args[0] == (
92 'The seed MUST consist of purely alphanumeric characters'
93 )
94 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
95 otp2289.OTPGenerator(
96 'This is a test.'.encode(),
97 'TeSt',
98 9,
99 )
100 assert exc_info.type is otp2289.OTPGeneratorException
101 assert exc_info.value.args[0] == (
102 'hash_algo is not among the known algorithms'
103 )
104 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
105 otp2289.OTPGenerator(
106 'This is a test.'.encode(),
107 'TeSt',
108 b'md5',
109 )
110 assert exc_info.type is otp2289.OTPGeneratorException
111 assert exc_info.value.args[0] == 'hash_algo must be an int or a str'
112 # test the package structure as well
113 with pytest.raises(otp2289.generator.OTPGeneratorException) as exc_info:
114 otp2289.generator.OTPGenerator(
115 'This is a test.'.encode(),
116 'TeSt',
117 'foo',
118 )
119 assert exc_info.type is otp2289.generator.OTPGeneratorException
120 assert exc_info.value.args[0] == (
121 'foo is not supported by this version of the hashlib module'
122 )
123 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
124 otp2289.OTPGenerator('1234567', 'TeSt', otp2289.OTP_ALGO_MD5)
125 assert exc_info.type is otp2289.OTPGeneratorException
126 assert exc_info.value.args[0] == 'Password must be a byte-string'
127 with pytest.raises(otp2289.OTPGeneratorException) as exc_info:
128 otp2289.OTPGenerator(
129 '1234567'.encode(),
130 'TeSt',
131 otp2289.OTP_ALGO_MD5,
132 )
133 assert exc_info.type is otp2289.OTPGeneratorException
134 assert exc_info.value.args[0] == 'Password must be longer than 10 bytes'
135
136
137def test_md5():
138 """
139 Tests the MD5 functionality of the OTPGenerator as described in the RFC
140
141 Those are the tests from 'RFC-2289 Appendix C - OTP Verification Examples'
142 """
143 # We could run this in a loop, but I guess "Readability counts."
144 # pass='This is a test.', seed='TeSt'
145 gen = otp2289.OTPGenerator(
146 'This is a test.'.encode(),
147 'TeSt',
148 otp2289.OTP_ALGO_MD5,
149 )
150 res_words = gen.generate_otp_words(0)
151 res_hex = gen.generate_otp_hexdigest(0)
152 assert isinstance(res_words, str)
153 assert isinstance(res_hex, str)
154 assert res_hex == '0x9e876134d90499dd'
155 assert res_words == 'INCH SEA ANNE LONG AHEM TOUR'
156 # step 1
157 assert gen.generate_otp_hexdigest(1) == '0x7965e05436f5029f'
158 assert gen.generate_otp_words(1) == 'EASE OIL FUM CURE AWRY AVIS'
159 assert gen.generate_otp_hexdigest_from_challenge('otp-md5 1 TeSt') == (
160 '0x7965e05436f5029f'
161 )
162 assert gen.generate_otp_words_from_challenge('otp-md5 1 TeSt') == (
163 'EASE OIL FUM CURE AWRY AVIS'
164 )
165 # step 99
166 assert gen.generate_otp_hexdigest(99) == '0x50fe1962c4965880'
167 assert gen.generate_otp_words(99) == 'BAIL TUFT BITS GANG CHEF THY'
168 assert gen.generate_otp_hexdigest_from_challenge('otp-md5 99 TeSt') == (
169 '0x50fe1962c4965880'
170 )
171 assert gen.generate_otp_words_from_challenge('otp-md5 99 TeSt') == (
172 'BAIL TUFT BITS GANG CHEF THY'
173 )
174 # iterator test
175 hexdigests = list(gen.hexdigest_range(105)) # testing the range itself
176 words = list(gen.words_range(99))
177 hexdigests.reverse()
178 words.reverse()
179 assert hexdigests[0] == '0x9e876134d90499dd'
180 assert hexdigests[1] == '0x7965e05436f5029f'
181 assert hexdigests[99] == '0x50fe1962c4965880'
182 assert words[0] == 'INCH SEA ANNE LONG AHEM TOUR'
183 assert words[1] == 'EASE OIL FUM CURE AWRY AVIS'
184 assert words[99] == 'BAIL TUFT BITS GANG CHEF THY'
185 # pass='AbCdEfGhIjK', seed='alpha1'
186 gen = otp2289.OTPGenerator(
187 'AbCdEfGhIjK'.encode(),
188 'alpha1',
189 otp2289.OTP_ALGO_MD5,
190 )
191 assert gen.generate_otp_hexdigest(0) == '0x87066dd9644bf206'
192 assert gen.generate_otp_words(0) == 'FULL PEW DOWN ONCE MORT ARC'
193 assert gen.generate_otp_hexdigest(1) == '0x7cd34c1040add14b'
194 assert gen.generate_otp_words(1) == 'FACT HOOF AT FIST SITE KENT'
195 assert gen.generate_otp_hexdigest(99) == '0x5aa37a81f212146c'
196 assert gen.generate_otp_words(99) == 'BODE HOP JAKE STOW JUT RAP'
197 # pass="OTP's are good", seed='correct'
198 gen = otp2289.OTPGenerator(
199 "OTP's are good".encode(),
200 'correct',
201 otp2289.OTP_ALGO_MD5,
202 )
203 assert gen.generate_otp_hexdigest(0) == '0xf205753943de4cf9'
204 assert gen.generate_otp_words(0) == 'ULAN NEW ARMY FUSE SUIT EYED'
205 assert gen.generate_otp_hexdigest(1) == '0xddcdac956f234937'
206 assert gen.generate_otp_words(1) == 'SKIM CULT LOB SLAM POE HOWL'
207 assert gen.generate_otp_hexdigest(99) == '0xb203e28fa525be47'
208 assert gen.generate_otp_words(99) == 'LONG IVY JULY AJAR BOND LEE'
209
210
211def test_sha1():
212 """
213 Tests the SHA-1 functionality of the OTPGenerator as described in the RFC
214
215 Those are the tests from 'RFC-2289 Appendix C - OTP Verification Examples'
216 """
217 # pass='This is a test.', seed='TeSt'
218 gen = otp2289.OTPGenerator(
219 'This is a test.'.encode(),
220 'TeSt',
221 otp2289.OTP_ALGO_SHA1,
222 )
223 # step=0
224 res_hex = gen.generate_otp_hexdigest(0)
225 res_words = gen.generate_otp_words(0)
226 assert isinstance(res_words, str)
227 assert isinstance(res_hex, str)
228 assert res_hex == '0xbb9e6ae1979d8ff4'
229 assert res_words == 'MILT VARY MAST OK SEES WENT'
230 assert gen.generate_otp_hexdigest(1) == '0x63d936639734385b'
231 assert gen.generate_otp_words(1) == 'CART OTTO HIVE ODE VAT NUT'
232 assert gen.generate_otp_hexdigest_from_challenge('otp-sha1 1 TeSt') == (
233 '0x63d936639734385b'
234 )
235 assert gen.generate_otp_words_from_challenge('otp-sha1 1 TeSt') == (
236 'CART OTTO HIVE ODE VAT NUT'
237 )
238 assert gen.generate_otp_hexdigest(99) == '0x87fec7768b73ccf9'
239 assert gen.generate_otp_words(99) == 'GAFF WAIT SKID GIG SKY EYED'
240 assert gen.generate_otp_hexdigest_from_challenge('otp-sha1 99 TeSt') == (
241 '0x87fec7768b73ccf9'
242 )
243 assert gen.generate_otp_words_from_challenge('otp-sha1 99 TeSt') == (
244 'GAFF WAIT SKID GIG SKY EYED'
245 )
246 # iterator test
247 hexdigests = list(gen.hexdigest_range(105))
248 words = list(gen.words_range(99))
249 hexdigests.reverse()
250 words.reverse()
251 assert hexdigests[0] == '0xbb9e6ae1979d8ff4'
252 assert hexdigests[1] == '0x63d936639734385b'
253 assert hexdigests[99] == '0x87fec7768b73ccf9'
254 assert words[0] == 'MILT VARY MAST OK SEES WENT'
255 assert words[1] == 'CART OTTO HIVE ODE VAT NUT'
256 assert words[99] == 'GAFF WAIT SKID GIG SKY EYED'
257 # pass='AbCdEfGhIjK', seed='alpha1'
258 gen = otp2289.OTPGenerator(
259 'AbCdEfGhIjK'.encode(),
260 'alpha1',
261 otp2289.OTP_ALGO_SHA1,
262 )
263 assert gen.generate_otp_hexdigest(0) == '0xad85f658ebe383c9'
264 assert gen.generate_otp_words(0) == 'LEST OR HEEL SCOT ROB SUIT'
265 assert gen.generate_otp_hexdigest(1) == '0xd07ce229b5cf119b'
266 assert gen.generate_otp_words(1) == 'RITE TAKE GELD COST TUNE RECK'
267 assert gen.generate_otp_hexdigest(99) == '0x27bc71035aaf3dc6'
268 assert gen.generate_otp_words(99) == 'MAY STAR TIN LYON VEDA STAN'
269 # pass="OTP's are good", seed='correct'
270 gen = otp2289.OTPGenerator(
271 "OTP's are good".encode(),
272 'correct',
273 otp2289.OTP_ALGO_SHA1,
274 )
275 assert gen.generate_otp_hexdigest(0) == '0xd51f3e99bf8e6f0b'
276 assert gen.generate_otp_words(0) == 'RUST WELT KICK FELL TAIL FRAU'
277 assert gen.generate_otp_hexdigest(1) == '0x82aeb52d943774e4'
278 assert gen.generate_otp_words(1) == 'FLIT DOSE ALSO MEW DRUM DEFY'
279 assert gen.generate_otp_hexdigest(99) == '0x4f296a74fe1567ec'
280 assert gen.generate_otp_words(99) == 'AURA ALOE HURL WING BERG WAIT'