diff options
| -rw-r--r-- | .ruff.toml | 98 | ||||
| -rw-r--r-- | README.md | 5 | ||||
| -rw-r--r-- | src/otp2289/__init__.py | 26 | ||||
| -rw-r--r-- | src/otp2289/__main__.py | 46 | ||||
| -rw-r--r-- | src/otp2289/generator.py | 2408 | ||||
| -rw-r--r-- | src/otp2289/server.py | 88 | ||||
| -rw-r--r-- | test/test_generator.py | 55 | ||||
| -rw-r--r-- | test/test_main.py | 3 | ||||
| -rw-r--r-- | test/test_server.py | 15 |
9 files changed, 2296 insertions, 448 deletions
diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..c5617c1 --- /dev/null +++ b/.ruff.toml | |||
| @@ -0,0 +1,98 @@ | |||
| 1 | cache-dir = "~/.cache/ruff" | ||
| 2 | indent-width = 4 | ||
| 3 | line-length = 79 | ||
| 4 | target-version = "py312" | ||
| 5 | |||
| 6 | [lint] | ||
| 7 | select = ["ALL", "D101", "D102", "D103", "D104"] | ||
| 8 | ignore = [ | ||
| 9 | "ANN", | ||
| 10 | "BLE001", | ||
| 11 | "COM812", | ||
| 12 | "D", | ||
| 13 | "EM101", # Exception must not use a string literal, assign to variable first | ||
| 14 | "EM102", # Exception must not use an f-string literal, assign to variable first | ||
| 15 | "ERA001", | ||
| 16 | "FBT001", | ||
| 17 | "FBT002", | ||
| 18 | "INP001", | ||
| 19 | "ISC001", | ||
| 20 | "N802", | ||
| 21 | "N806", | ||
| 22 | "PLR2004", | ||
| 23 | "PTH111", | ||
| 24 | "RUF012", | ||
| 25 | "RUF013", | ||
| 26 | "S101", | ||
| 27 | "S324", | ||
| 28 | "T201", | ||
| 29 | "TRY003", | ||
| 30 | "TRY300", | ||
| 31 | "UP020" | ||
| 32 | ] | ||
| 33 | |||
| 34 | # D101 - Missing docstring in public class | ||
| 35 | # D102 - Missing docstring in public method | ||
| 36 | # D200 - One-line docstring should fit on one line | ||
| 37 | # D203 - 1 blank line required before class docstring | ||
| 38 | # D205 - 1 blank line required between summary line and description | ||
| 39 | # D403 - First word of the first line should be capitalized: `str` -> `Str` | ||
| 40 | # FBT001 - Boolean-typed positional argument in function definition | ||
| 41 | # FBT002 - Boolean default positional argument in function definition | ||
| 42 | # INP001 - File `beinc_weechat.py` is part of an implicit namespace package. Add an `__init__.py` | ||
| 43 | # N802 - Function name `do_GET` should be lowercase | ||
| 44 | # N806 - Variable `POST_data` in function should be lowercase | ||
| 45 | # PLR2004 - Magic value used in comparison, consider replacing `200` with a constant variable | ||
| 46 | # PTH111 - `os.path.expanduser()` should be replaced by `Path.expanduser()` | ||
| 47 | # PTH113 - `os.path.isfile()` should be replaced by `Path.is_file()` | ||
| 48 | # PTH123 - `open()` should be replaced by `Path.open()` | ||
| 49 | # RUF012 - Mutable class attributes should be annotated with `typing.ClassVar` | ||
| 50 | # RUF013 - PEP 484 prohibits implicit `Optional` | ||
| 51 | # S101 - Use of `assert` detected | ||
| 52 | # S324 - Probable use of insecure hash functions in `hashlib`: `md5` | ||
| 53 | # T201 - `print` found | ||
| 54 | # TRY003 - Avoid specifying long messages outside the exception class | ||
| 55 | # TRY300 - Consider moving this statement to an `else` block | ||
| 56 | # UP020 - Use builtin `open` | ||
| 57 | |||
| 58 | # Allow fix for all enabled rules (when `--fix`) is provided. | ||
| 59 | fixable = ["ALL"] | ||
| 60 | unfixable = [] | ||
| 61 | |||
| 62 | # custom settings | ||
| 63 | [lint.per-file-ignores] | ||
| 64 | "src/otp2289/__main__.py" = ["PTH113", "PTH123"] # "Readability counts" | ||
| 65 | |||
| 66 | |||
| 67 | [format] | ||
| 68 | # Like Black, use double quotes for strings. | ||
| 69 | quote-style = "single" | ||
| 70 | |||
| 71 | # Like Black, indent with spaces, rather than tabs. | ||
| 72 | indent-style = "space" | ||
| 73 | |||
| 74 | # Like Black, respect magic trailing commas. | ||
| 75 | skip-magic-trailing-comma = true | ||
| 76 | |||
| 77 | # Like Black, automatically detect the appropriate line ending. | ||
| 78 | line-ending = "auto" | ||
| 79 | |||
| 80 | # Enable auto-formatting of code examples in docstrings. Markdown, | ||
| 81 | # reStructuredText code/literal blocks and doctests are all supported. | ||
| 82 | # | ||
| 83 | # This is currently disabled by default, but it is planned for this | ||
| 84 | # to be opt-out in the future. | ||
| 85 | docstring-code-format = false | ||
| 86 | |||
| 87 | # Set the line length limit used when formatting code snippets in | ||
| 88 | # docstrings. | ||
| 89 | # | ||
| 90 | # This only has an effect when the `docstring-code-format` setting is | ||
| 91 | # enabled. | ||
| 92 | docstring-code-line-length = "dynamic" | ||
| 93 | |||
| 94 | [lint.flake8-quotes] | ||
| 95 | inline-quotes = "single" | ||
| 96 | |||
| 97 | [lint.isort] | ||
| 98 | split-on-trailing-comma = false | ||
| @@ -33,7 +33,7 @@ I hope that somebody will find it useful. | |||
| 33 | pkg install security/py-pyotp2289 | 33 | pkg install security/py-pyotp2289 |
| 34 | ``` | 34 | ``` |
| 35 | 35 | ||
| 36 | – or: | 36 | or: |
| 37 | 37 | ||
| 38 | ```bash | 38 | ```bash |
| 39 | cd /usr/ports/security/py-pyotp2289 | 39 | cd /usr/ports/security/py-pyotp2289 |
| @@ -46,9 +46,6 @@ I hope that somebody will find it useful. | |||
| 46 | # add sgs' custom repository using app-eselect/eselect-repository | 46 | # add sgs' custom repository using app-eselect/eselect-repository |
| 47 | eselect repository add sgs | 47 | eselect repository add sgs |
| 48 | 48 | ||
| 49 | # ... or using app-portage/layman (obsolete) | ||
| 50 | layman -a sgs | ||
| 51 | |||
| 52 | emerge dev-python/pyotp2289 | 49 | emerge dev-python/pyotp2289 |
| 53 | ``` | 50 | ``` |
| 54 | 51 | ||
diff --git a/src/otp2289/__init__.py b/src/otp2289/__init__.py index 5e51498..c9e3c74 100644 --- a/src/otp2289/__init__.py +++ b/src/otp2289/__init__.py | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD | 1 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
| 3 | # | 2 | # |
| 4 | # Copyright (c) 2020-2023 Simeon Simeonov | 3 | # Copyright (c) 2020-2025 Simeon Simeonov |
| 5 | # All rights reserved. | 4 | # All rights reserved. |
| 6 | # | 5 | # |
| 7 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
| @@ -24,23 +23,24 @@ | |||
| 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 23 | # (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. | 24 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | """A pure Python implementation of RFC-2289""" | 25 | """A pure Python implementation of RFC-2289""" |
| 26 | |||
| 27 | from .generator import ( | 27 | from .generator import ( |
| 28 | OTP_ALGO_MD5, | 28 | OTP_ALGO_MD5, |
| 29 | OTP_ALGO_SHA1, | 29 | OTP_ALGO_SHA1, |
| 30 | OTPChallengeException, | 30 | OTPChallengeError, |
| 31 | OTPGenerator, | 31 | OTPGenerator, |
| 32 | OTPGeneratorException, | 32 | OTPGeneratorError, |
| 33 | ) | 33 | ) |
| 34 | from .server import ( | 34 | from .server import ( |
| 35 | OTPInvalidResponse, | 35 | OTPInvalidResponseError, |
| 36 | OTPState, | 36 | OTPState, |
| 37 | OTPStateException, | 37 | OTPStateError, |
| 38 | OTPStore, | 38 | OTPStore, |
| 39 | OTPStoreException, | 39 | OTPStoreError, |
| 40 | ) | 40 | ) |
| 41 | 41 | ||
| 42 | __author__ = 'Simeon Simeonov' | 42 | __author__ = 'Simeon Simeonov' |
| 43 | __version__ = '1.2.1' | 43 | __version__ = '1.2.2' |
| 44 | __license__ = 'BSD 2-Clause' | 44 | __license__ = 'BSD 2-Clause' |
| 45 | 45 | ||
| 46 | 46 | ||
| @@ -57,12 +57,12 @@ VERSION = tuple(map(int_or_str, __version__.split('.'))) | |||
| 57 | __all__ = [ | 57 | __all__ = [ |
| 58 | 'OTP_ALGO_MD5', | 58 | 'OTP_ALGO_MD5', |
| 59 | 'OTP_ALGO_SHA1', | 59 | 'OTP_ALGO_SHA1', |
| 60 | 'OTPChallengeException', | 60 | 'OTPChallengeError', |
| 61 | 'OTPGenerator', | 61 | 'OTPGenerator', |
| 62 | 'OTPGeneratorException', | 62 | 'OTPGeneratorError', |
| 63 | 'OTPInvalidResponse', | 63 | 'OTPInvalidResponseError', |
| 64 | 'OTPState', | 64 | 'OTPState', |
| 65 | 'OTPStateException', | 65 | 'OTPStateError', |
| 66 | 'OTPStore', | 66 | 'OTPStore', |
| 67 | 'OTPStoreException', | 67 | 'OTPStoreError', |
| 68 | ] | 68 | ] |
diff --git a/src/otp2289/__main__.py b/src/otp2289/__main__.py index d267b1b..9f1aab8 100644 --- a/src/otp2289/__main__.py +++ b/src/otp2289/__main__.py | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD | 1 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
| 3 | # | 2 | # |
| 4 | # Copyright (c) 2020-2023 Simeon Simeonov | 3 | # Copyright (c) 2020-2025 Simeon Simeonov |
| 5 | # All rights reserved. | 4 | # All rights reserved. |
| 6 | # | 5 | # |
| 7 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
| @@ -32,10 +31,10 @@ python -m otp2289 --initiate-new-sequence -s TesT | |||
| 32 | python -m otp2289 --generate-otp-response -c "otp-md5 499 TesT " -f token | 31 | python -m otp2289 --generate-otp-response -c "otp-md5 499 TesT " -f token |
| 33 | python -m otp2289 --generate-otp-response -s TesT -i 499 -f token | 32 | python -m otp2289 --generate-otp-response -s TesT -i 499 -f token |
| 34 | """ | 33 | """ |
| 34 | |||
| 35 | import argparse | 35 | import argparse |
| 36 | import errno | 36 | import errno |
| 37 | import getpass | 37 | import getpass |
| 38 | import io | ||
| 39 | import os | 38 | import os |
| 40 | import secrets | 39 | import secrets |
| 41 | import string | 40 | import string |
| @@ -56,17 +55,15 @@ def generate_otp_response(args: argparse.Namespace) -> str: | |||
| 56 | :param args: The arguments assigned from argparse | 55 | :param args: The arguments assigned from argparse |
| 57 | :type args: argparse.Namespace | 56 | :type args: argparse.Namespace |
| 58 | 57 | ||
| 59 | :raises otp2289.OTPChallengeException: If the challenge is invalid | 58 | :raises otp2289.OTPChallengeError: If the challenge is invalid |
| 60 | 59 | ||
| 61 | :raises otp2289.OTPGeneratorException: If generator parameters are wrong | 60 | :raises otp2289.OTPGeneratorError: If generator parameters are wrong |
| 62 | 61 | ||
| 63 | :return: The response string | 62 | :return: The response string |
| 64 | :rtype: str | 63 | :rtype: str |
| 65 | """ | 64 | """ |
| 66 | generator = otp2289.generator.OTPGenerator( | 65 | generator = otp2289.generator.OTPGenerator( |
| 67 | args.password.encode(), | 66 | args.password.encode(), args.seed, args.hash_algo |
| 68 | args.seed, | ||
| 69 | args.hash_algo, | ||
| 70 | ) | 67 | ) |
| 71 | if args.challenge_string: | 68 | if args.challenge_string: |
| 72 | if args.output_format == 'token': | 69 | if args.output_format == 'token': |
| @@ -95,27 +92,26 @@ def generate_otp_range(args: argparse.Namespace) -> str: | |||
| 95 | :param args: The arguments assigned from argparse | 92 | :param args: The arguments assigned from argparse |
| 96 | :type args: argparse.Namespace | 93 | :type args: argparse.Namespace |
| 97 | 94 | ||
| 98 | :raises otp2289.OTPChallengeException: If the challenge is invalid | 95 | :raises otp2289.OTPChallengeError: If the challenge is invalid |
| 99 | 96 | ||
| 100 | :raises otp2289.OTPGeneratorException: If generator parameters are wrong | 97 | :raises otp2289.OTPGeneratorError: If generator parameters are wrong |
| 101 | 98 | ||
| 102 | :return: The responses string | 99 | :return: The responses string |
| 103 | :rtype: str | 100 | :rtype: str |
| 104 | """ | 101 | """ |
| 105 | generator = otp2289.generator.OTPGenerator( | 102 | generator = otp2289.generator.OTPGenerator( |
| 106 | args.password.encode(), | 103 | args.password.encode(), args.seed, args.hash_algo |
| 107 | args.seed, | ||
| 108 | args.hash_algo, | ||
| 109 | ) | 104 | ) |
| 110 | if args.output_format == 'token': | 105 | if args.output_format == 'token': |
| 111 | method = generator.generate_otp_words | 106 | method = generator.generate_otp_words |
| 112 | else: | 107 | else: |
| 113 | method = generator.generate_otp_hexdigest | 108 | method = generator.generate_otp_hexdigest |
| 109 | |||
| 114 | # handle most cases explicitly | 110 | # handle most cases explicitly |
| 115 | if args.range == 1: | 111 | if args.range == 1: |
| 116 | return f'{args.step}: ' + method(args.step) | 112 | return f'{args.step}: ' + method(args.step) |
| 117 | if args.range > args.step + 1: | 113 | args.range = min(args.range, args.step + 1) |
| 118 | args.range = args.step + 1 | 114 | |
| 119 | # any need for quiet? | 115 | # any need for quiet? |
| 120 | header = '' | 116 | header = '' |
| 121 | if not args.quiet: | 117 | if not args.quiet: |
| @@ -126,11 +122,7 @@ def generate_otp_range(args: argparse.Namespace) -> str: | |||
| 126 | return header + os.linesep.join( | 122 | return header + os.linesep.join( |
| 127 | [ | 123 | [ |
| 128 | f'{step}: ' + method(step) | 124 | f'{step}: ' + method(step) |
| 129 | for step in range( | 125 | for step in range(args.step, args.step - args.range, -1) |
| 130 | args.step, | ||
| 131 | args.step - args.range, | ||
| 132 | -1, | ||
| 133 | ) | ||
| 134 | ] | 126 | ] |
| 135 | ) | 127 | ) |
| 136 | 128 | ||
| @@ -171,7 +163,7 @@ def get_password(args: argparse.Namespace) -> str: | |||
| 171 | return password | 163 | return password |
| 172 | 164 | ||
| 173 | if os.path.isfile(args.password): | 165 | if os.path.isfile(args.password): |
| 174 | with io.open(args.password, 'r', encoding='utf-8') as fp: | 166 | with open(args.password, encoding='utf-8') as fp: |
| 175 | return fp.readline().strip() | 167 | return fp.readline().strip() |
| 176 | 168 | ||
| 177 | return args.password | 169 | return args.password |
| @@ -196,9 +188,9 @@ def initiate_new_sequence(args: argparse.Namespace) -> str: | |||
| 196 | :param args: The arguments assigned from argparse | 188 | :param args: The arguments assigned from argparse |
| 197 | :type args: argparse.Namespace | 189 | :type args: argparse.Namespace |
| 198 | 190 | ||
| 199 | :raises otp2289.OTPChallengeException: If the challenge is invalid | 191 | :raises otp2289.OTPChallengeError: If the challenge is invalid |
| 200 | 192 | ||
| 201 | :raises otp2289.OTPGeneratorException: If generator parameters are wrong | 193 | :raises otp2289.OTPGeneratorError: If generator parameters are wrong |
| 202 | 194 | ||
| 203 | :return: The response string | 195 | :return: The response string |
| 204 | :rtype: str | 196 | :rtype: str |
| @@ -212,9 +204,7 @@ def initiate_new_sequence(args: argparse.Namespace) -> str: | |||
| 212 | f'Hash: {args.hash_algo}{os.linesep}' | 204 | f'Hash: {args.hash_algo}{os.linesep}' |
| 213 | ) | 205 | ) |
| 214 | generator = otp2289.generator.OTPGenerator( | 206 | generator = otp2289.generator.OTPGenerator( |
| 215 | args.password.encode(), | 207 | args.password.encode(), args.seed, args.hash_algo |
| 216 | args.seed, | ||
| 217 | args.hash_algo, | ||
| 218 | ) | 208 | ) |
| 219 | if args.challenge_string: | 209 | if args.challenge_string: |
| 220 | return header + generator.generate_otp_hexdigest_from_challenge( | 210 | return header + generator.generate_otp_hexdigest_from_challenge( |
| @@ -372,9 +362,9 @@ def main(args=None): | |||
| 372 | if args.generate_otp_response: | 362 | if args.generate_otp_response: |
| 373 | print(generate_otp_response(args)) | 363 | print(generate_otp_response(args)) |
| 374 | sys.exit(0) | 364 | sys.exit(0) |
| 375 | except otp2289.generator.OTPGeneratorException as exp: | 365 | except otp2289.generator.OTPGeneratorError as exp: |
| 376 | eprint(f'GeneratorException: {exp}') | 366 | eprint(f'GeneratorException: {exp}') |
| 377 | except otp2289.generator.OTPChallengeException as exp: | 367 | except otp2289.generator.OTPChallengeError as exp: |
| 378 | eprint(f'ChallengeException: {exp}') | 368 | eprint(f'ChallengeException: {exp}') |
| 379 | except Exception as exp: | 369 | except Exception as exp: |
| 380 | eprint(f'Unknown error: {exp}') | 370 | eprint(f'Unknown error: {exp}') |
diff --git a/src/otp2289/generator.py b/src/otp2289/generator.py index 73ca18b..c03d289 100644 --- a/src/otp2289/generator.py +++ b/src/otp2289/generator.py | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD | 1 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
| 3 | # | 2 | # |
| 4 | # Copyright (c) 2020-2023 Simeon Simeonov | 3 | # Copyright (c) 2020-2025 Simeon Simeonov |
| 5 | # All rights reserved. | 4 | # All rights reserved. |
| 6 | # | 5 | # |
| 7 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
| @@ -24,6 +23,7 @@ | |||
| 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 23 | # (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. | 24 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | """A pure Python implementation of the RFC-2289 OTP generator""" | 25 | """A pure Python implementation of the RFC-2289 OTP generator""" |
| 26 | |||
| 27 | import binascii | 27 | import binascii |
| 28 | import hashlib | 28 | import hashlib |
| 29 | import string | 29 | import string |
| @@ -33,283 +33,2072 @@ OTP_ALGO_SHA1 = 2 | |||
| 33 | 33 | ||
| 34 | # the tokens are defined in https://tools.ietf.org/html/rfc2289 # | 34 | # the tokens are defined in https://tools.ietf.org/html/rfc2289 # |
| 35 | RFC1760_TOKENS = [ | 35 | RFC1760_TOKENS = [ |
| 36 | 'A', 'ABE', 'ACE', 'ACT', 'AD', 'ADA', 'ADD', | 36 | 'A', |
| 37 | 'AGO', 'AID', 'AIM', 'AIR', 'ALL', 'ALP', 'AM', 'AMY', | 37 | 'ABE', |
| 38 | 'AN', 'ANA', 'AND', 'ANN', 'ANT', 'ANY', 'APE', 'APS', | 38 | 'ACE', |
| 39 | 'APT', 'ARC', 'ARE', 'ARK', 'ARM', 'ART', 'AS', 'ASH', | 39 | 'ACT', |
| 40 | 'ASK', 'AT', 'ATE', 'AUG', 'AUK', 'AVE', 'AWE', 'AWK', | 40 | 'AD', |
| 41 | 'AWL', 'AWN', 'AX', 'AYE', 'BAD', 'BAG', 'BAH', 'BAM', | 41 | 'ADA', |
| 42 | 'BAN', 'BAR', 'BAT', 'BAY', 'BE', 'BED', 'BEE', 'BEG', | 42 | 'ADD', |
| 43 | 'BEN', 'BET', 'BEY', 'BIB', 'BID', 'BIG', 'BIN', 'BIT', | 43 | 'AGO', |
| 44 | 'BOB', 'BOG', 'BON', 'BOO', 'BOP', 'BOW', 'BOY', 'BUB', | 44 | 'AID', |
| 45 | 'BUD', 'BUG', 'BUM', 'BUN', 'BUS', 'BUT', 'BUY', 'BY', | 45 | 'AIM', |
| 46 | 'BYE', 'CAB', 'CAL', 'CAM', 'CAN', 'CAP', 'CAR', 'CAT', | 46 | 'AIR', |
| 47 | 'CAW', 'COD', 'COG', 'COL', 'CON', 'COO', 'COP', 'COT', | 47 | 'ALL', |
| 48 | 'COW', 'COY', 'CRY', 'CUB', 'CUE', 'CUP', 'CUR', 'CUT', | 48 | 'ALP', |
| 49 | 'DAB', 'DAD', 'DAM', 'DAN', 'DAR', 'DAY', 'DEE', 'DEL', | 49 | 'AM', |
| 50 | 'DEN', 'DES', 'DEW', 'DID', 'DIE', 'DIG', 'DIN', 'DIP', | 50 | 'AMY', |
| 51 | 'DO', 'DOE', 'DOG', 'DON', 'DOT', 'DOW', 'DRY', 'DUB', | 51 | 'AN', |
| 52 | 'DUD', 'DUE', 'DUG', 'DUN', 'EAR', 'EAT', 'ED', 'EEL', | 52 | 'ANA', |
| 53 | 'EGG', 'EGO', 'ELI', 'ELK', 'ELM', 'ELY', 'EM', 'END', | 53 | 'AND', |
| 54 | 'EST', 'ETC', 'EVA', 'EVE', 'EWE', 'EYE', 'FAD', 'FAN', | 54 | 'ANN', |
| 55 | 'FAR', 'FAT', 'FAY', 'FED', 'FEE', 'FEW', 'FIB', 'FIG', | 55 | 'ANT', |
| 56 | 'FIN', 'FIR', 'FIT', 'FLO', 'FLY', 'FOE', 'FOG', 'FOR', | 56 | 'ANY', |
| 57 | 'FRY', 'FUM', 'FUN', 'FUR', 'GAB', 'GAD', 'GAG', 'GAL', | 57 | 'APE', |
| 58 | 'GAM', 'GAP', 'GAS', 'GAY', 'GEE', 'GEL', 'GEM', 'GET', | 58 | 'APS', |
| 59 | 'GIG', 'GIL', 'GIN', 'GO', 'GOT', 'GUM', 'GUN', 'GUS', | 59 | 'APT', |
| 60 | 'GUT', 'GUY', 'GYM', 'GYP', 'HA', 'HAD', 'HAL', 'HAM', | 60 | 'ARC', |
| 61 | 'HAN', 'HAP', 'HAS', 'HAT', 'HAW', 'HAY', 'HE', 'HEM', | 61 | 'ARE', |
| 62 | 'HEN', 'HER', 'HEW', 'HEY', 'HI', 'HID', 'HIM', 'HIP', | 62 | 'ARK', |
| 63 | 'HIS', 'HIT', 'HO', 'HOB', 'HOC', 'HOE', 'HOG', 'HOP', | 63 | 'ARM', |
| 64 | 'HOT', 'HOW', 'HUB', 'HUE', 'HUG', 'HUH', 'HUM', 'HUT', | 64 | 'ART', |
| 65 | 'I', 'ICY', 'IDA', 'IF', 'IKE', 'ILL', 'INK', 'INN', | 65 | 'AS', |
| 66 | 'IO', 'ION', 'IQ', 'IRA', 'IRE', 'IRK', 'IS', 'IT', | 66 | 'ASH', |
| 67 | 'ITS', 'IVY', 'JAB', 'JAG', 'JAM', 'JAN', 'JAR', 'JAW', | 67 | 'ASK', |
| 68 | 'JAY', 'JET', 'JIG', 'JIM', 'JO', 'JOB', 'JOE', 'JOG', | 68 | 'AT', |
| 69 | 'JOT', 'JOY', 'JUG', 'JUT', 'KAY', 'KEG', 'KEN', 'KEY', | 69 | 'ATE', |
| 70 | 'KID', 'KIM', 'KIN', 'KIT', 'LA', 'LAB', 'LAC', 'LAD', | 70 | 'AUG', |
| 71 | 'LAG', 'LAM', 'LAP', 'LAW', 'LAY', 'LEA', 'LED', 'LEE', | 71 | 'AUK', |
| 72 | 'LEG', 'LEN', 'LEO', 'LET', 'LEW', 'LID', 'LIE', 'LIN', | 72 | 'AVE', |
| 73 | 'LIP', 'LIT', 'LO', 'LOB', 'LOG', 'LOP', 'LOS', 'LOT', | 73 | 'AWE', |
| 74 | 'LOU', 'LOW', 'LOY', 'LUG', 'LYE', 'MA', 'MAC', 'MAD', | 74 | 'AWK', |
| 75 | 'MAE', 'MAN', 'MAO', 'MAP', 'MAT', 'MAW', 'MAY', 'ME', | 75 | 'AWL', |
| 76 | 'MEG', 'MEL', 'MEN', 'MET', 'MEW', 'MID', 'MIN', 'MIT', | 76 | 'AWN', |
| 77 | 'MOB', 'MOD', 'MOE', 'MOO', 'MOP', 'MOS', 'MOT', 'MOW', | 77 | 'AX', |
| 78 | 'MUD', 'MUG', 'MUM', 'MY', 'NAB', 'NAG', 'NAN', 'NAP', | 78 | 'AYE', |
| 79 | 'NAT', 'NAY', 'NE', 'NED', 'NEE', 'NET', 'NEW', 'NIB', | 79 | 'BAD', |
| 80 | 'NIL', 'NIP', 'NIT', 'NO', 'NOB', 'NOD', 'NON', 'NOR', | 80 | 'BAG', |
| 81 | 'NOT', 'NOV', 'NOW', 'NU', 'NUN', 'NUT', 'O', 'OAF', | 81 | 'BAH', |
| 82 | 'OAK', 'OAR', 'OAT', 'ODD', 'ODE', 'OF', 'OFF', 'OFT', | 82 | 'BAM', |
| 83 | 'OH', 'OIL', 'OK', 'OLD', 'ON', 'ONE', 'OR', 'ORB', | 83 | 'BAN', |
| 84 | 'ORE', 'ORR', 'OS', 'OTT', 'OUR', 'OUT', 'OVA', 'OW', | 84 | 'BAR', |
| 85 | 'OWE', 'OWL', 'OWN', 'OX', 'PA', 'PAD', 'PAL', 'PAM', | 85 | 'BAT', |
| 86 | 'PAN', 'PAP', 'PAR', 'PAT', 'PAW', 'PAY', 'PEA', 'PEG', | 86 | 'BAY', |
| 87 | 'PEN', 'PEP', 'PER', 'PET', 'PEW', 'PHI', 'PI', 'PIE', | 87 | 'BE', |
| 88 | 'PIN', 'PIT', 'PLY', 'PO', 'POD', 'POE', 'POP', 'POT', | 88 | 'BED', |
| 89 | 'POW', 'PRO', 'PRY', 'PUB', 'PUG', 'PUN', 'PUP', 'PUT', | 89 | 'BEE', |
| 90 | 'QUO', 'RAG', 'RAM', 'RAN', 'RAP', 'RAT', 'RAW', 'RAY', | 90 | 'BEG', |
| 91 | 'REB', 'RED', 'REP', 'RET', 'RIB', 'RID', 'RIG', 'RIM', | 91 | 'BEN', |
| 92 | 'RIO', 'RIP', 'ROB', 'ROD', 'ROE', 'RON', 'ROT', 'ROW', | 92 | 'BET', |
| 93 | 'ROY', 'RUB', 'RUE', 'RUG', 'RUM', 'RUN', 'RYE', 'SAC', | 93 | 'BEY', |
| 94 | 'SAD', 'SAG', 'SAL', 'SAM', 'SAN', 'SAP', 'SAT', 'SAW', | 94 | 'BIB', |
| 95 | 'SAY', 'SEA', 'SEC', 'SEE', 'SEN', 'SET', 'SEW', 'SHE', | 95 | 'BID', |
| 96 | 'SHY', 'SIN', 'SIP', 'SIR', 'SIS', 'SIT', 'SKI', 'SKY', | 96 | 'BIG', |
| 97 | 'SLY', 'SO', 'SOB', 'SOD', 'SON', 'SOP', 'SOW', 'SOY', | 97 | 'BIN', |
| 98 | 'SPA', 'SPY', 'SUB', 'SUD', 'SUE', 'SUM', 'SUN', 'SUP', | 98 | 'BIT', |
| 99 | 'TAB', 'TAD', 'TAG', 'TAN', 'TAP', 'TAR', 'TEA', 'TED', | 99 | 'BOB', |
| 100 | 'TEE', 'TEN', 'THE', 'THY', 'TIC', 'TIE', 'TIM', 'TIN', | 100 | 'BOG', |
| 101 | 'TIP', 'TO', 'TOE', 'TOG', 'TOM', 'TON', 'TOO', 'TOP', | 101 | 'BON', |
| 102 | 'TOW', 'TOY', 'TRY', 'TUB', 'TUG', 'TUM', 'TUN', 'TWO', | 102 | 'BOO', |
| 103 | 'UN', 'UP', 'US', 'USE', 'VAN', 'VAT', 'VET', 'VIE', | 103 | 'BOP', |
| 104 | 'WAD', 'WAG', 'WAR', 'WAS', 'WAY', 'WE', 'WEB', 'WED', | 104 | 'BOW', |
| 105 | 'WEE', 'WET', 'WHO', 'WHY', 'WIN', 'WIT', 'WOK', 'WON', | 105 | 'BOY', |
| 106 | 'WOO', 'WOW', 'WRY', 'WU', 'YAM', 'YAP', 'YAW', 'YE', | 106 | 'BUB', |
| 107 | 'YEA', 'YES', 'YET', 'YOU', 'ABED', 'ABEL', 'ABET', 'ABLE', | 107 | 'BUD', |
| 108 | 'ABUT', 'ACHE', 'ACID', 'ACME', 'ACRE', 'ACTA', 'ACTS', 'ADAM', | 108 | 'BUG', |
| 109 | 'ADDS', 'ADEN', 'AFAR', 'AFRO', 'AGEE', 'AHEM', 'AHOY', 'AIDA', | 109 | 'BUM', |
| 110 | 'AIDE', 'AIDS', 'AIRY', 'AJAR', 'AKIN', 'ALAN', 'ALEC', 'ALGA', | 110 | 'BUN', |
| 111 | 'ALIA', 'ALLY', 'ALMA', 'ALOE', 'ALSO', 'ALTO', 'ALUM', 'ALVA', | 111 | 'BUS', |
| 112 | 'AMEN', 'AMES', 'AMID', 'AMMO', 'AMOK', 'AMOS', 'AMRA', 'ANDY', | 112 | 'BUT', |
| 113 | 'ANEW', 'ANNA', 'ANNE', 'ANTE', 'ANTI', 'AQUA', 'ARAB', 'ARCH', | 113 | 'BUY', |
| 114 | 'AREA', 'ARGO', 'ARID', 'ARMY', 'ARTS', 'ARTY', 'ASIA', 'ASKS', | 114 | 'BY', |
| 115 | 'ATOM', 'AUNT', 'AURA', 'AUTO', 'AVER', 'AVID', 'AVIS', 'AVON', | 115 | 'BYE', |
| 116 | 'AVOW', 'AWAY', 'AWRY', 'BABE', 'BABY', 'BACH', 'BACK', 'BADE', | 116 | 'CAB', |
| 117 | 'BAIL', 'BAIT', 'BAKE', 'BALD', 'BALE', 'BALI', 'BALK', 'BALL', | 117 | 'CAL', |
| 118 | 'BALM', 'BAND', 'BANE', 'BANG', 'BANK', 'BARB', 'BARD', 'BARE', | 118 | 'CAM', |
| 119 | 'BARK', 'BARN', 'BARR', 'BASE', 'BASH', 'BASK', 'BASS', 'BATE', | 119 | 'CAN', |
| 120 | 'BATH', 'BAWD', 'BAWL', 'BEAD', 'BEAK', 'BEAM', 'BEAN', 'BEAR', | 120 | 'CAP', |
| 121 | 'BEAT', 'BEAU', 'BECK', 'BEEF', 'BEEN', 'BEER', 'BEET', 'BELA', | 121 | 'CAR', |
| 122 | 'BELL', 'BELT', 'BEND', 'BENT', 'BERG', 'BERN', 'BERT', 'BESS', | 122 | 'CAT', |
| 123 | 'BEST', 'BETA', 'BETH', 'BHOY', 'BIAS', 'BIDE', 'BIEN', 'BILE', | 123 | 'CAW', |
| 124 | 'BILK', 'BILL', 'BIND', 'BING', 'BIRD', 'BITE', 'BITS', 'BLAB', | 124 | 'COD', |
| 125 | 'BLAT', 'BLED', 'BLEW', 'BLOB', 'BLOC', 'BLOT', 'BLOW', 'BLUE', | 125 | 'COG', |
| 126 | 'BLUM', 'BLUR', 'BOAR', 'BOAT', 'BOCA', 'BOCK', 'BODE', 'BODY', | 126 | 'COL', |
| 127 | 'BOGY', 'BOHR', 'BOIL', 'BOLD', 'BOLO', 'BOLT', 'BOMB', 'BONA', | 127 | 'CON', |
| 128 | 'BOND', 'BONE', 'BONG', 'BONN', 'BONY', 'BOOK', 'BOOM', 'BOON', | 128 | 'COO', |
| 129 | 'BOOT', 'BORE', 'BORG', 'BORN', 'BOSE', 'BOSS', 'BOTH', 'BOUT', | 129 | 'COP', |
| 130 | 'BOWL', 'BOYD', 'BRAD', 'BRAE', 'BRAG', 'BRAN', 'BRAY', 'BRED', | 130 | 'COT', |
| 131 | 'BREW', 'BRIG', 'BRIM', 'BROW', 'BUCK', 'BUDD', 'BUFF', 'BULB', | 131 | 'COW', |
| 132 | 'BULK', 'BULL', 'BUNK', 'BUNT', 'BUOY', 'BURG', 'BURL', 'BURN', | 132 | 'COY', |
| 133 | 'BURR', 'BURT', 'BURY', 'BUSH', 'BUSS', 'BUST', 'BUSY', 'BYTE', | 133 | 'CRY', |
| 134 | 'CADY', 'CAFE', 'CAGE', 'CAIN', 'CAKE', 'CALF', 'CALL', 'CALM', | 134 | 'CUB', |
| 135 | 'CAME', 'CANE', 'CANT', 'CARD', 'CARE', 'CARL', 'CARR', 'CART', | 135 | 'CUE', |
| 136 | 'CASE', 'CASH', 'CASK', 'CAST', 'CAVE', 'CEIL', 'CELL', 'CENT', | 136 | 'CUP', |
| 137 | 'CERN', 'CHAD', 'CHAR', 'CHAT', 'CHAW', 'CHEF', 'CHEN', 'CHEW', | 137 | 'CUR', |
| 138 | 'CHIC', 'CHIN', 'CHOU', 'CHOW', 'CHUB', 'CHUG', 'CHUM', 'CITE', | 138 | 'CUT', |
| 139 | 'CITY', 'CLAD', 'CLAM', 'CLAN', 'CLAW', 'CLAY', 'CLOD', 'CLOG', | 139 | 'DAB', |
| 140 | 'CLOT', 'CLUB', 'CLUE', 'COAL', 'COAT', 'COCA', 'COCK', 'COCO', | 140 | 'DAD', |
| 141 | 'CODA', 'CODE', 'CODY', 'COED', 'COIL', 'COIN', 'COKE', 'COLA', | 141 | 'DAM', |
| 142 | 'COLD', 'COLT', 'COMA', 'COMB', 'COME', 'COOK', 'COOL', 'COON', | 142 | 'DAN', |
| 143 | 'COOT', 'CORD', 'CORE', 'CORK', 'CORN', 'COST', 'COVE', 'COWL', | 143 | 'DAR', |
| 144 | 'CRAB', 'CRAG', 'CRAM', 'CRAY', 'CREW', 'CRIB', 'CROW', 'CRUD', | 144 | 'DAY', |
| 145 | 'CUBA', 'CUBE', 'CUFF', 'CULL', 'CULT', 'CUNY', 'CURB', 'CURD', | 145 | 'DEE', |
| 146 | 'CURE', 'CURL', 'CURT', 'CUTS', 'DADE', 'DALE', 'DAME', 'DANA', | 146 | 'DEL', |
| 147 | 'DANE', 'DANG', 'DANK', 'DARE', 'DARK', 'DARN', 'DART', 'DASH', | 147 | 'DEN', |
| 148 | 'DATA', 'DATE', 'DAVE', 'DAVY', 'DAWN', 'DAYS', 'DEAD', 'DEAF', | 148 | 'DES', |
| 149 | 'DEAL', 'DEAN', 'DEAR', 'DEBT', 'DECK', 'DEED', 'DEEM', 'DEER', | 149 | 'DEW', |
| 150 | 'DEFT', 'DEFY', 'DELL', 'DENT', 'DENY', 'DESK', 'DIAL', 'DICE', | 150 | 'DID', |
| 151 | 'DIED', 'DIET', 'DIME', 'DINE', 'DING', 'DINT', 'DIRE', 'DIRT', | 151 | 'DIE', |
| 152 | 'DISC', 'DISH', 'DISK', 'DIVE', 'DOCK', 'DOES', 'DOLE', 'DOLL', | 152 | 'DIG', |
| 153 | 'DOLT', 'DOME', 'DONE', 'DOOM', 'DOOR', 'DORA', 'DOSE', 'DOTE', | 153 | 'DIN', |
| 154 | 'DOUG', 'DOUR', 'DOVE', 'DOWN', 'DRAB', 'DRAG', 'DRAM', 'DRAW', | 154 | 'DIP', |
| 155 | 'DREW', 'DRUB', 'DRUG', 'DRUM', 'DUAL', 'DUCK', 'DUCT', 'DUEL', | 155 | 'DO', |
| 156 | 'DUET', 'DUKE', 'DULL', 'DUMB', 'DUNE', 'DUNK', 'DUSK', 'DUST', | 156 | 'DOE', |
| 157 | 'DUTY', 'EACH', 'EARL', 'EARN', 'EASE', 'EAST', 'EASY', 'EBEN', | 157 | 'DOG', |
| 158 | 'ECHO', 'EDDY', 'EDEN', 'EDGE', 'EDGY', 'EDIT', 'EDNA', 'EGAN', | 158 | 'DON', |
| 159 | 'ELAN', 'ELBA', 'ELLA', 'ELSE', 'EMIL', 'EMIT', 'EMMA', 'ENDS', | 159 | 'DOT', |
| 160 | 'ERIC', 'EROS', 'EVEN', 'EVER', 'EVIL', 'EYED', 'FACE', 'FACT', | 160 | 'DOW', |
| 161 | 'FADE', 'FAIL', 'FAIN', 'FAIR', 'FAKE', 'FALL', 'FAME', 'FANG', | 161 | 'DRY', |
| 162 | 'FARM', 'FAST', 'FATE', 'FAWN', 'FEAR', 'FEAT', 'FEED', 'FEEL', | 162 | 'DUB', |
| 163 | 'FEET', 'FELL', 'FELT', 'FEND', 'FERN', 'FEST', 'FEUD', 'FIEF', | 163 | 'DUD', |
| 164 | 'FIGS', 'FILE', 'FILL', 'FILM', 'FIND', 'FINE', 'FINK', 'FIRE', | 164 | 'DUE', |
| 165 | 'FIRM', 'FISH', 'FISK', 'FIST', 'FITS', 'FIVE', 'FLAG', 'FLAK', | 165 | 'DUG', |
| 166 | 'FLAM', 'FLAT', 'FLAW', 'FLEA', 'FLED', 'FLEW', 'FLIT', 'FLOC', | 166 | 'DUN', |
| 167 | 'FLOG', 'FLOW', 'FLUB', 'FLUE', 'FOAL', 'FOAM', 'FOGY', 'FOIL', | 167 | 'EAR', |
| 168 | 'FOLD', 'FOLK', 'FOND', 'FONT', 'FOOD', 'FOOL', 'FOOT', 'FORD', | 168 | 'EAT', |
| 169 | 'FORE', 'FORK', 'FORM', 'FORT', 'FOSS', 'FOUL', 'FOUR', 'FOWL', | 169 | 'ED', |
| 170 | 'FRAU', 'FRAY', 'FRED', 'FREE', 'FRET', 'FREY', 'FROG', 'FROM', | 170 | 'EEL', |
| 171 | 'FUEL', 'FULL', 'FUME', 'FUND', 'FUNK', 'FURY', 'FUSE', 'FUSS', | 171 | 'EGG', |
| 172 | 'GAFF', 'GAGE', 'GAIL', 'GAIN', 'GAIT', 'GALA', 'GALE', 'GALL', | 172 | 'EGO', |
| 173 | 'GALT', 'GAME', 'GANG', 'GARB', 'GARY', 'GASH', 'GATE', 'GAUL', | 173 | 'ELI', |
| 174 | 'GAUR', 'GAVE', 'GAWK', 'GEAR', 'GELD', 'GENE', 'GENT', 'GERM', | 174 | 'ELK', |
| 175 | 'GETS', 'GIBE', 'GIFT', 'GILD', 'GILL', 'GILT', 'GINA', 'GIRD', | 175 | 'ELM', |
| 176 | 'GIRL', 'GIST', 'GIVE', 'GLAD', 'GLEE', 'GLEN', 'GLIB', 'GLOB', | 176 | 'ELY', |
| 177 | 'GLOM', 'GLOW', 'GLUE', 'GLUM', 'GLUT', 'GOAD', 'GOAL', 'GOAT', | 177 | 'EM', |
| 178 | 'GOER', 'GOES', 'GOLD', 'GOLF', 'GONE', 'GONG', 'GOOD', 'GOOF', | 178 | 'END', |
| 179 | 'GORE', 'GORY', 'GOSH', 'GOUT', 'GOWN', 'GRAB', 'GRAD', 'GRAY', | 179 | 'EST', |
| 180 | 'GREG', 'GREW', 'GREY', 'GRID', 'GRIM', 'GRIN', 'GRIT', 'GROW', | 180 | 'ETC', |
| 181 | 'GRUB', 'GULF', 'GULL', 'GUNK', 'GURU', 'GUSH', 'GUST', 'GWEN', | 181 | 'EVA', |
| 182 | 'GWYN', 'HAAG', 'HAAS', 'HACK', 'HAIL', 'HAIR', 'HALE', 'HALF', | 182 | 'EVE', |
| 183 | 'HALL', 'HALO', 'HALT', 'HAND', 'HANG', 'HANK', 'HANS', 'HARD', | 183 | 'EWE', |
| 184 | 'HARK', 'HARM', 'HART', 'HASH', 'HAST', 'HATE', 'HATH', 'HAUL', | 184 | 'EYE', |
| 185 | 'HAVE', 'HAWK', 'HAYS', 'HEAD', 'HEAL', 'HEAR', 'HEAT', 'HEBE', | 185 | 'FAD', |
| 186 | 'HECK', 'HEED', 'HEEL', 'HEFT', 'HELD', 'HELL', 'HELM', 'HERB', | 186 | 'FAN', |
| 187 | 'HERD', 'HERE', 'HERO', 'HERS', 'HESS', 'HEWN', 'HICK', 'HIDE', | 187 | 'FAR', |
| 188 | 'HIGH', 'HIKE', 'HILL', 'HILT', 'HIND', 'HINT', 'HIRE', 'HISS', | 188 | 'FAT', |
| 189 | 'HIVE', 'HOBO', 'HOCK', 'HOFF', 'HOLD', 'HOLE', 'HOLM', 'HOLT', | 189 | 'FAY', |
| 190 | 'HOME', 'HONE', 'HONK', 'HOOD', 'HOOF', 'HOOK', 'HOOT', 'HORN', | 190 | 'FED', |
| 191 | 'HOSE', 'HOST', 'HOUR', 'HOVE', 'HOWE', 'HOWL', 'HOYT', 'HUCK', | 191 | 'FEE', |
| 192 | 'HUED', 'HUFF', 'HUGE', 'HUGH', 'HUGO', 'HULK', 'HULL', 'HUNK', | 192 | 'FEW', |
| 193 | 'HUNT', 'HURD', 'HURL', 'HURT', 'HUSH', 'HYDE', 'HYMN', 'IBIS', | 193 | 'FIB', |
| 194 | 'ICON', 'IDEA', 'IDLE', 'IFFY', 'INCA', 'INCH', 'INTO', 'IONS', | 194 | 'FIG', |
| 195 | 'IOTA', 'IOWA', 'IRIS', 'IRMA', 'IRON', 'ISLE', 'ITCH', 'ITEM', | 195 | 'FIN', |
| 196 | 'IVAN', 'JACK', 'JADE', 'JAIL', 'JAKE', 'JANE', 'JAVA', 'JEAN', | 196 | 'FIR', |
| 197 | 'JEFF', 'JERK', 'JESS', 'JEST', 'JIBE', 'JILL', 'JILT', 'JIVE', | 197 | 'FIT', |
| 198 | 'JOAN', 'JOBS', 'JOCK', 'JOEL', 'JOEY', 'JOHN', 'JOIN', 'JOKE', | 198 | 'FLO', |
| 199 | 'JOLT', 'JOVE', 'JUDD', 'JUDE', 'JUDO', 'JUDY', 'JUJU', 'JUKE', | 199 | 'FLY', |
| 200 | 'JULY', 'JUNE', 'JUNK', 'JUNO', 'JURY', 'JUST', 'JUTE', 'KAHN', | 200 | 'FOE', |
| 201 | 'KALE', 'KANE', 'KANT', 'KARL', 'KATE', 'KEEL', 'KEEN', 'KENO', | 201 | 'FOG', |
| 202 | 'KENT', 'KERN', 'KERR', 'KEYS', 'KICK', 'KILL', 'KIND', 'KING', | 202 | 'FOR', |
| 203 | 'KIRK', 'KISS', 'KITE', 'KLAN', 'KNEE', 'KNEW', 'KNIT', 'KNOB', | 203 | 'FRY', |
| 204 | 'KNOT', 'KNOW', 'KOCH', 'KONG', 'KUDO', 'KURD', 'KURT', 'KYLE', | 204 | 'FUM', |
| 205 | 'LACE', 'LACK', 'LACY', 'LADY', 'LAID', 'LAIN', 'LAIR', 'LAKE', | 205 | 'FUN', |
| 206 | 'LAMB', 'LAME', 'LAND', 'LANE', 'LANG', 'LARD', 'LARK', 'LASS', | 206 | 'FUR', |
| 207 | 'LAST', 'LATE', 'LAUD', 'LAVA', 'LAWN', 'LAWS', 'LAYS', 'LEAD', | 207 | 'GAB', |
| 208 | 'LEAF', 'LEAK', 'LEAN', 'LEAR', 'LEEK', 'LEER', 'LEFT', 'LEND', | 208 | 'GAD', |
| 209 | 'LENS', 'LENT', 'LEON', 'LESK', 'LESS', 'LEST', 'LETS', 'LIAR', | 209 | 'GAG', |
| 210 | 'LICE', 'LICK', 'LIED', 'LIEN', 'LIES', 'LIEU', 'LIFE', 'LIFT', | 210 | 'GAL', |
| 211 | 'LIKE', 'LILA', 'LILT', 'LILY', 'LIMA', 'LIMB', 'LIME', 'LIND', | 211 | 'GAM', |
| 212 | 'LINE', 'LINK', 'LINT', 'LION', 'LISA', 'LIST', 'LIVE', 'LOAD', | 212 | 'GAP', |
| 213 | 'LOAF', 'LOAM', 'LOAN', 'LOCK', 'LOFT', 'LOGE', 'LOIS', 'LOLA', | 213 | 'GAS', |
| 214 | 'LONE', 'LONG', 'LOOK', 'LOON', 'LOOT', 'LORD', 'LORE', 'LOSE', | 214 | 'GAY', |
| 215 | 'LOSS', 'LOST', 'LOUD', 'LOVE', 'LOWE', 'LUCK', 'LUCY', 'LUGE', | 215 | 'GEE', |
| 216 | 'LUKE', 'LULU', 'LUND', 'LUNG', 'LURA', 'LURE', 'LURK', 'LUSH', | 216 | 'GEL', |
| 217 | 'LUST', 'LYLE', 'LYNN', 'LYON', 'LYRA', 'MACE', 'MADE', 'MAGI', | 217 | 'GEM', |
| 218 | 'MAID', 'MAIL', 'MAIN', 'MAKE', 'MALE', 'MALI', 'MALL', 'MALT', | 218 | 'GET', |
| 219 | 'MANA', 'MANN', 'MANY', 'MARC', 'MARE', 'MARK', 'MARS', 'MART', | 219 | 'GIG', |
| 220 | 'MARY', 'MASH', 'MASK', 'MASS', 'MAST', 'MATE', 'MATH', 'MAUL', | 220 | 'GIL', |
| 221 | 'MAYO', 'MEAD', 'MEAL', 'MEAN', 'MEAT', 'MEEK', 'MEET', 'MELD', | 221 | 'GIN', |
| 222 | 'MELT', 'MEMO', 'MEND', 'MENU', 'MERT', 'MESH', 'MESS', 'MICE', | 222 | 'GO', |
| 223 | 'MIKE', 'MILD', 'MILE', 'MILK', 'MILL', 'MILT', 'MIMI', 'MIND', | 223 | 'GOT', |
| 224 | 'MINE', 'MINI', 'MINK', 'MINT', 'MIRE', 'MISS', 'MIST', 'MITE', | 224 | 'GUM', |
| 225 | 'MITT', 'MOAN', 'MOAT', 'MOCK', 'MODE', 'MOLD', 'MOLE', 'MOLL', | 225 | 'GUN', |
| 226 | 'MOLT', 'MONA', 'MONK', 'MONT', 'MOOD', 'MOON', 'MOOR', 'MOOT', | 226 | 'GUS', |
| 227 | 'MORE', 'MORN', 'MORT', 'MOSS', 'MOST', 'MOTH', 'MOVE', 'MUCH', | 227 | 'GUT', |
| 228 | 'MUCK', 'MUDD', 'MUFF', 'MULE', 'MULL', 'MURK', 'MUSH', 'MUST', | 228 | 'GUY', |
| 229 | 'MUTE', 'MUTT', 'MYRA', 'MYTH', 'NAGY', 'NAIL', 'NAIR', 'NAME', | 229 | 'GYM', |
| 230 | 'NARY', 'NASH', 'NAVE', 'NAVY', 'NEAL', 'NEAR', 'NEAT', 'NECK', | 230 | 'GYP', |
| 231 | 'NEED', 'NEIL', 'NELL', 'NEON', 'NERO', 'NESS', 'NEST', 'NEWS', | 231 | 'HA', |
| 232 | 'NEWT', 'NIBS', 'NICE', 'NICK', 'NILE', 'NINA', 'NINE', 'NOAH', | 232 | 'HAD', |
| 233 | 'NODE', 'NOEL', 'NOLL', 'NONE', 'NOOK', 'NOON', 'NORM', 'NOSE', | 233 | 'HAL', |
| 234 | 'NOTE', 'NOUN', 'NOVA', 'NUDE', 'NULL', 'NUMB', 'OATH', 'OBEY', | 234 | 'HAM', |
| 235 | 'OBOE', 'ODIN', 'OHIO', 'OILY', 'OINT', 'OKAY', 'OLAF', 'OLDY', | 235 | 'HAN', |
| 236 | 'OLGA', 'OLIN', 'OMAN', 'OMEN', 'OMIT', 'ONCE', 'ONES', 'ONLY', | 236 | 'HAP', |
| 237 | 'ONTO', 'ONUS', 'ORAL', 'ORGY', 'OSLO', 'OTIS', 'OTTO', 'OUCH', | 237 | 'HAS', |
| 238 | 'OUST', 'OUTS', 'OVAL', 'OVEN', 'OVER', 'OWLY', 'OWNS', 'QUAD', | 238 | 'HAT', |
| 239 | 'QUIT', 'QUOD', 'RACE', 'RACK', 'RACY', 'RAFT', 'RAGE', 'RAID', | 239 | 'HAW', |
| 240 | 'RAIL', 'RAIN', 'RAKE', 'RANK', 'RANT', 'RARE', 'RASH', 'RATE', | 240 | 'HAY', |
| 241 | 'RAVE', 'RAYS', 'READ', 'REAL', 'REAM', 'REAR', 'RECK', 'REED', | 241 | 'HE', |
| 242 | 'REEF', 'REEK', 'REEL', 'REID', 'REIN', 'RENA', 'REND', 'RENT', | 242 | 'HEM', |
| 243 | 'REST', 'RICE', 'RICH', 'RICK', 'RIDE', 'RIFT', 'RILL', 'RIME', | 243 | 'HEN', |
| 244 | 'RING', 'RINK', 'RISE', 'RISK', 'RITE', 'ROAD', 'ROAM', 'ROAR', | 244 | 'HER', |
| 245 | 'ROBE', 'ROCK', 'RODE', 'ROIL', 'ROLL', 'ROME', 'ROOD', 'ROOF', | 245 | 'HEW', |
| 246 | 'ROOK', 'ROOM', 'ROOT', 'ROSA', 'ROSE', 'ROSS', 'ROSY', 'ROTH', | 246 | 'HEY', |
| 247 | 'ROUT', 'ROVE', 'ROWE', 'ROWS', 'RUBE', 'RUBY', 'RUDE', 'RUDY', | 247 | 'HI', |
| 248 | 'RUIN', 'RULE', 'RUNG', 'RUNS', 'RUNT', 'RUSE', 'RUSH', 'RUSK', | 248 | 'HID', |
| 249 | 'RUSS', 'RUST', 'RUTH', 'SACK', 'SAFE', 'SAGE', 'SAID', 'SAIL', | 249 | 'HIM', |
| 250 | 'SALE', 'SALK', 'SALT', 'SAME', 'SAND', 'SANE', 'SANG', 'SANK', | 250 | 'HIP', |
| 251 | 'SARA', 'SAUL', 'SAVE', 'SAYS', 'SCAN', 'SCAR', 'SCAT', 'SCOT', | 251 | 'HIS', |
| 252 | 'SEAL', 'SEAM', 'SEAR', 'SEAT', 'SEED', 'SEEK', 'SEEM', 'SEEN', | 252 | 'HIT', |
| 253 | 'SEES', 'SELF', 'SELL', 'SEND', 'SENT', 'SETS', 'SEWN', 'SHAG', | 253 | 'HO', |
| 254 | 'SHAM', 'SHAW', 'SHAY', 'SHED', 'SHIM', 'SHIN', 'SHOD', 'SHOE', | 254 | 'HOB', |
| 255 | 'SHOT', 'SHOW', 'SHUN', 'SHUT', 'SICK', 'SIDE', 'SIFT', 'SIGH', | 255 | 'HOC', |
| 256 | 'SIGN', 'SILK', 'SILL', 'SILO', 'SILT', 'SINE', 'SING', 'SINK', | 256 | 'HOE', |
| 257 | 'SIRE', 'SITE', 'SITS', 'SITU', 'SKAT', 'SKEW', 'SKID', 'SKIM', | 257 | 'HOG', |
| 258 | 'SKIN', 'SKIT', 'SLAB', 'SLAM', 'SLAT', 'SLAY', 'SLED', 'SLEW', | 258 | 'HOP', |
| 259 | 'SLID', 'SLIM', 'SLIT', 'SLOB', 'SLOG', 'SLOT', 'SLOW', 'SLUG', | 259 | 'HOT', |
| 260 | 'SLUM', 'SLUR', 'SMOG', 'SMUG', 'SNAG', 'SNOB', 'SNOW', 'SNUB', | 260 | 'HOW', |
| 261 | 'SNUG', 'SOAK', 'SOAR', 'SOCK', 'SODA', 'SOFA', 'SOFT', 'SOIL', | 261 | 'HUB', |
| 262 | 'SOLD', 'SOME', 'SONG', 'SOON', 'SOOT', 'SORE', 'SORT', 'SOUL', | 262 | 'HUE', |
| 263 | 'SOUR', 'SOWN', 'STAB', 'STAG', 'STAN', 'STAR', 'STAY', 'STEM', | 263 | 'HUG', |
| 264 | 'STEW', 'STIR', 'STOW', 'STUB', 'STUN', 'SUCH', 'SUDS', 'SUIT', | 264 | 'HUH', |
| 265 | 'SULK', 'SUMS', 'SUNG', 'SUNK', 'SURE', 'SURF', 'SWAB', 'SWAG', | 265 | 'HUM', |
| 266 | 'SWAM', 'SWAN', 'SWAT', 'SWAY', 'SWIM', 'SWUM', 'TACK', 'TACT', | 266 | 'HUT', |
| 267 | 'TAIL', 'TAKE', 'TALE', 'TALK', 'TALL', 'TANK', 'TASK', 'TATE', | 267 | 'I', |
| 268 | 'TAUT', 'TEAL', 'TEAM', 'TEAR', 'TECH', 'TEEM', 'TEEN', 'TEET', | 268 | 'ICY', |
| 269 | 'TELL', 'TEND', 'TENT', 'TERM', 'TERN', 'TESS', 'TEST', 'THAN', | 269 | 'IDA', |
| 270 | 'THAT', 'THEE', 'THEM', 'THEN', 'THEY', 'THIN', 'THIS', 'THUD', | 270 | 'IF', |
| 271 | 'THUG', 'TICK', 'TIDE', 'TIDY', 'TIED', 'TIER', 'TILE', 'TILL', | 271 | 'IKE', |
| 272 | 'TILT', 'TIME', 'TINA', 'TINE', 'TINT', 'TINY', 'TIRE', 'TOAD', | 272 | 'ILL', |
| 273 | 'TOGO', 'TOIL', 'TOLD', 'TOLL', 'TONE', 'TONG', 'TONY', 'TOOK', | 273 | 'INK', |
| 274 | 'TOOL', 'TOOT', 'TORE', 'TORN', 'TOTE', 'TOUR', 'TOUT', 'TOWN', | 274 | 'INN', |
| 275 | 'TRAG', 'TRAM', 'TRAY', 'TREE', 'TREK', 'TRIG', 'TRIM', 'TRIO', | 275 | 'IO', |
| 276 | 'TROD', 'TROT', 'TROY', 'TRUE', 'TUBA', 'TUBE', 'TUCK', 'TUFT', | 276 | 'ION', |
| 277 | 'TUNA', 'TUNE', 'TUNG', 'TURF', 'TURN', 'TUSK', 'TWIG', 'TWIN', | 277 | 'IQ', |
| 278 | 'TWIT', 'ULAN', 'UNIT', 'URGE', 'USED', 'USER', 'USES', 'UTAH', | 278 | 'IRA', |
| 279 | 'VAIL', 'VAIN', 'VALE', 'VARY', 'VASE', 'VAST', 'VEAL', 'VEDA', | 279 | 'IRE', |
| 280 | 'VEIL', 'VEIN', 'VEND', 'VENT', 'VERB', 'VERY', 'VETO', 'VICE', | 280 | 'IRK', |
| 281 | 'VIEW', 'VINE', 'VISE', 'VOID', 'VOLT', 'VOTE', 'WACK', 'WADE', | 281 | 'IS', |
| 282 | 'WAGE', 'WAIL', 'WAIT', 'WAKE', 'WALE', 'WALK', 'WALL', 'WALT', | 282 | 'IT', |
| 283 | 'WAND', 'WANE', 'WANG', 'WANT', 'WARD', 'WARM', 'WARN', 'WART', | 283 | 'ITS', |
| 284 | 'WASH', 'WAST', 'WATS', 'WATT', 'WAVE', 'WAVY', 'WAYS', 'WEAK', | 284 | 'IVY', |
| 285 | 'WEAL', 'WEAN', 'WEAR', 'WEED', 'WEEK', 'WEIR', 'WELD', 'WELL', | 285 | 'JAB', |
| 286 | 'WELT', 'WENT', 'WERE', 'WERT', 'WEST', 'WHAM', 'WHAT', 'WHEE', | 286 | 'JAG', |
| 287 | 'WHEN', 'WHET', 'WHOA', 'WHOM', 'WICK', 'WIFE', 'WILD', 'WILL', | 287 | 'JAM', |
| 288 | 'WIND', 'WINE', 'WING', 'WINK', 'WINO', 'WIRE', 'WISE', 'WISH', | 288 | 'JAN', |
| 289 | 'WITH', 'WOLF', 'WONT', 'WOOD', 'WOOL', 'WORD', 'WORE', 'WORK', | 289 | 'JAR', |
| 290 | 'WORM', 'WORN', 'WOVE', 'WRIT', 'WYNN', 'YALE', 'YANG', 'YANK', | 290 | 'JAW', |
| 291 | 'YARD', 'YARN', 'YAWL', 'YAWN', 'YEAH', 'YEAR', 'YELL', 'YOGA', | 291 | 'JAY', |
| 292 | 'YOKE'] | 292 | 'JET', |
| 293 | 'JIG', | ||
| 294 | 'JIM', | ||
| 295 | 'JO', | ||
| 296 | 'JOB', | ||
| 297 | 'JOE', | ||
| 298 | 'JOG', | ||
| 299 | 'JOT', | ||
| 300 | 'JOY', | ||
| 301 | 'JUG', | ||
| 302 | 'JUT', | ||
| 303 | 'KAY', | ||
| 304 | 'KEG', | ||
| 305 | 'KEN', | ||
| 306 | 'KEY', | ||
| 307 | 'KID', | ||
| 308 | 'KIM', | ||
| 309 | 'KIN', | ||
| 310 | 'KIT', | ||
| 311 | 'LA', | ||
| 312 | 'LAB', | ||
| 313 | 'LAC', | ||
| 314 | 'LAD', | ||
| 315 | 'LAG', | ||
| 316 | 'LAM', | ||
| 317 | 'LAP', | ||
| 318 | 'LAW', | ||
| 319 | 'LAY', | ||
| 320 | 'LEA', | ||
| 321 | 'LED', | ||
| 322 | 'LEE', | ||
| 323 | 'LEG', | ||
| 324 | 'LEN', | ||
| 325 | 'LEO', | ||
| 326 | 'LET', | ||
| 327 | 'LEW', | ||
| 328 | 'LID', | ||
| 329 | 'LIE', | ||
| 330 | 'LIN', | ||
| 331 | 'LIP', | ||
| 332 | 'LIT', | ||
| 333 | 'LO', | ||
| 334 | 'LOB', | ||
| 335 | 'LOG', | ||
| 336 | 'LOP', | ||
| 337 | 'LOS', | ||
| 338 | 'LOT', | ||
| 339 | 'LOU', | ||
| 340 | 'LOW', | ||
| 341 | 'LOY', | ||
| 342 | 'LUG', | ||
| 343 | 'LYE', | ||
| 344 | 'MA', | ||
| 345 | 'MAC', | ||
| 346 | 'MAD', | ||
| 347 | 'MAE', | ||
| 348 | 'MAN', | ||
| 349 | 'MAO', | ||
| 350 | 'MAP', | ||
| 351 | 'MAT', | ||
| 352 | 'MAW', | ||
| 353 | 'MAY', | ||
| 354 | 'ME', | ||
| 355 | 'MEG', | ||
| 356 | 'MEL', | ||
| 357 | 'MEN', | ||
| 358 | 'MET', | ||
| 359 | 'MEW', | ||
| 360 | 'MID', | ||
| 361 | 'MIN', | ||
| 362 | 'MIT', | ||
| 363 | 'MOB', | ||
| 364 | 'MOD', | ||
| 365 | 'MOE', | ||
| 366 | 'MOO', | ||
| 367 | 'MOP', | ||
| 368 | 'MOS', | ||
| 369 | 'MOT', | ||
| 370 | 'MOW', | ||
| 371 | 'MUD', | ||
| 372 | 'MUG', | ||
| 373 | 'MUM', | ||
| 374 | 'MY', | ||
| 375 | 'NAB', | ||
| 376 | 'NAG', | ||
| 377 | 'NAN', | ||
| 378 | 'NAP', | ||
| 379 | 'NAT', | ||
| 380 | 'NAY', | ||
| 381 | 'NE', | ||
| 382 | 'NED', | ||
| 383 | 'NEE', | ||
| 384 | 'NET', | ||
| 385 | 'NEW', | ||
| 386 | 'NIB', | ||
| 387 | 'NIL', | ||
| 388 | 'NIP', | ||
| 389 | 'NIT', | ||
| 390 | 'NO', | ||
| 391 | 'NOB', | ||
| 392 | 'NOD', | ||
| 393 | 'NON', | ||
| 394 | 'NOR', | ||
| 395 | 'NOT', | ||
| 396 | 'NOV', | ||
| 397 | 'NOW', | ||
| 398 | 'NU', | ||
| 399 | 'NUN', | ||
| 400 | 'NUT', | ||
| 401 | 'O', | ||
| 402 | 'OAF', | ||
| 403 | 'OAK', | ||
| 404 | 'OAR', | ||
| 405 | 'OAT', | ||
| 406 | 'ODD', | ||
| 407 | 'ODE', | ||
| 408 | 'OF', | ||
| 409 | 'OFF', | ||
| 410 | 'OFT', | ||
| 411 | 'OH', | ||
| 412 | 'OIL', | ||
| 413 | 'OK', | ||
| 414 | 'OLD', | ||
| 415 | 'ON', | ||
| 416 | 'ONE', | ||
| 417 | 'OR', | ||
| 418 | 'ORB', | ||
| 419 | 'ORE', | ||
| 420 | 'ORR', | ||
| 421 | 'OS', | ||
| 422 | 'OTT', | ||
| 423 | 'OUR', | ||
| 424 | 'OUT', | ||
| 425 | 'OVA', | ||
| 426 | 'OW', | ||
| 427 | 'OWE', | ||
| 428 | 'OWL', | ||
| 429 | 'OWN', | ||
| 430 | 'OX', | ||
| 431 | 'PA', | ||
| 432 | 'PAD', | ||
| 433 | 'PAL', | ||
| 434 | 'PAM', | ||
| 435 | 'PAN', | ||
| 436 | 'PAP', | ||
| 437 | 'PAR', | ||
| 438 | 'PAT', | ||
| 439 | 'PAW', | ||
| 440 | 'PAY', | ||
| 441 | 'PEA', | ||
| 442 | 'PEG', | ||
| 443 | 'PEN', | ||
| 444 | 'PEP', | ||
| 445 | 'PER', | ||
| 446 | 'PET', | ||
| 447 | 'PEW', | ||
| 448 | 'PHI', | ||
| 449 | 'PI', | ||
| 450 | 'PIE', | ||
| 451 | 'PIN', | ||
| 452 | 'PIT', | ||
| 453 | 'PLY', | ||
| 454 | 'PO', | ||
| 455 | 'POD', | ||
| 456 | 'POE', | ||
| 457 | 'POP', | ||
| 458 | 'POT', | ||
| 459 | 'POW', | ||
| 460 | 'PRO', | ||
| 461 | 'PRY', | ||
| 462 | 'PUB', | ||
| 463 | 'PUG', | ||
| 464 | 'PUN', | ||
| 465 | 'PUP', | ||
| 466 | 'PUT', | ||
| 467 | 'QUO', | ||
| 468 | 'RAG', | ||
| 469 | 'RAM', | ||
| 470 | 'RAN', | ||
| 471 | 'RAP', | ||
| 472 | 'RAT', | ||
| 473 | 'RAW', | ||
| 474 | 'RAY', | ||
| 475 | 'REB', | ||
| 476 | 'RED', | ||
| 477 | 'REP', | ||
| 478 | 'RET', | ||
| 479 | 'RIB', | ||
| 480 | 'RID', | ||
| 481 | 'RIG', | ||
| 482 | 'RIM', | ||
| 483 | 'RIO', | ||
| 484 | 'RIP', | ||
| 485 | 'ROB', | ||
| 486 | 'ROD', | ||
| 487 | 'ROE', | ||
| 488 | 'RON', | ||
| 489 | 'ROT', | ||
| 490 | 'ROW', | ||
| 491 | 'ROY', | ||
| 492 | 'RUB', | ||
| 493 | 'RUE', | ||
| 494 | 'RUG', | ||
| 495 | 'RUM', | ||
| 496 | 'RUN', | ||
| 497 | 'RYE', | ||
| 498 | 'SAC', | ||
| 499 | 'SAD', | ||
| 500 | 'SAG', | ||
| 501 | 'SAL', | ||
| 502 | 'SAM', | ||
| 503 | 'SAN', | ||
| 504 | 'SAP', | ||
| 505 | 'SAT', | ||
| 506 | 'SAW', | ||
| 507 | 'SAY', | ||
| 508 | 'SEA', | ||
| 509 | 'SEC', | ||
| 510 | 'SEE', | ||
| 511 | 'SEN', | ||
| 512 | 'SET', | ||
| 513 | 'SEW', | ||
| 514 | 'SHE', | ||
| 515 | 'SHY', | ||
| 516 | 'SIN', | ||
| 517 | 'SIP', | ||
| 518 | 'SIR', | ||
| 519 | 'SIS', | ||
| 520 | 'SIT', | ||
| 521 | 'SKI', | ||
| 522 | 'SKY', | ||
| 523 | 'SLY', | ||
| 524 | 'SO', | ||
| 525 | 'SOB', | ||
| 526 | 'SOD', | ||
| 527 | 'SON', | ||
| 528 | 'SOP', | ||
| 529 | 'SOW', | ||
| 530 | 'SOY', | ||
| 531 | 'SPA', | ||
| 532 | 'SPY', | ||
| 533 | 'SUB', | ||
| 534 | 'SUD', | ||
| 535 | 'SUE', | ||
| 536 | 'SUM', | ||
| 537 | 'SUN', | ||
| 538 | 'SUP', | ||
| 539 | 'TAB', | ||
| 540 | 'TAD', | ||
| 541 | 'TAG', | ||
| 542 | 'TAN', | ||
| 543 | 'TAP', | ||
| 544 | 'TAR', | ||
| 545 | 'TEA', | ||
| 546 | 'TED', | ||
| 547 | 'TEE', | ||
| 548 | 'TEN', | ||
| 549 | 'THE', | ||
| 550 | 'THY', | ||
| 551 | 'TIC', | ||
| 552 | 'TIE', | ||
| 553 | 'TIM', | ||
| 554 | 'TIN', | ||
| 555 | 'TIP', | ||
| 556 | 'TO', | ||
| 557 | 'TOE', | ||
| 558 | 'TOG', | ||
| 559 | 'TOM', | ||
| 560 | 'TON', | ||
| 561 | 'TOO', | ||
| 562 | 'TOP', | ||
| 563 | 'TOW', | ||
| 564 | 'TOY', | ||
| 565 | 'TRY', | ||
| 566 | 'TUB', | ||
| 567 | 'TUG', | ||
| 568 | 'TUM', | ||
| 569 | 'TUN', | ||
| 570 | 'TWO', | ||
| 571 | 'UN', | ||
| 572 | 'UP', | ||
| 573 | 'US', | ||
| 574 | 'USE', | ||
| 575 | 'VAN', | ||
| 576 | 'VAT', | ||
| 577 | 'VET', | ||
| 578 | 'VIE', | ||
| 579 | 'WAD', | ||
| 580 | 'WAG', | ||
| 581 | 'WAR', | ||
| 582 | 'WAS', | ||
| 583 | 'WAY', | ||
| 584 | 'WE', | ||
| 585 | 'WEB', | ||
| 586 | 'WED', | ||
| 587 | 'WEE', | ||
| 588 | 'WET', | ||
| 589 | 'WHO', | ||
| 590 | 'WHY', | ||
| 591 | 'WIN', | ||
| 592 | 'WIT', | ||
| 593 | 'WOK', | ||
| 594 | 'WON', | ||
| 595 | 'WOO', | ||
| 596 | 'WOW', | ||
| 597 | 'WRY', | ||
| 598 | 'WU', | ||
| 599 | 'YAM', | ||
| 600 | 'YAP', | ||
| 601 | 'YAW', | ||
| 602 | 'YE', | ||
| 603 | 'YEA', | ||
| 604 | 'YES', | ||
| 605 | 'YET', | ||
| 606 | 'YOU', | ||
| 607 | 'ABED', | ||
| 608 | 'ABEL', | ||
| 609 | 'ABET', | ||
| 610 | 'ABLE', | ||
| 611 | 'ABUT', | ||
| 612 | 'ACHE', | ||
| 613 | 'ACID', | ||
| 614 | 'ACME', | ||
| 615 | 'ACRE', | ||
| 616 | 'ACTA', | ||
| 617 | 'ACTS', | ||
| 618 | 'ADAM', | ||
| 619 | 'ADDS', | ||
| 620 | 'ADEN', | ||
| 621 | 'AFAR', | ||
| 622 | 'AFRO', | ||
| 623 | 'AGEE', | ||
| 624 | 'AHEM', | ||
| 625 | 'AHOY', | ||
| 626 | 'AIDA', | ||
| 627 | 'AIDE', | ||
| 628 | 'AIDS', | ||
| 629 | 'AIRY', | ||
| 630 | 'AJAR', | ||
| 631 | 'AKIN', | ||
| 632 | 'ALAN', | ||
| 633 | 'ALEC', | ||
| 634 | 'ALGA', | ||
| 635 | 'ALIA', | ||
| 636 | 'ALLY', | ||
| 637 | 'ALMA', | ||
| 638 | 'ALOE', | ||
| 639 | 'ALSO', | ||
| 640 | 'ALTO', | ||
| 641 | 'ALUM', | ||
| 642 | 'ALVA', | ||
| 643 | 'AMEN', | ||
| 644 | 'AMES', | ||
| 645 | 'AMID', | ||
| 646 | 'AMMO', | ||
| 647 | 'AMOK', | ||
| 648 | 'AMOS', | ||
| 649 | 'AMRA', | ||
| 650 | 'ANDY', | ||
| 651 | 'ANEW', | ||
| 652 | 'ANNA', | ||
| 653 | 'ANNE', | ||
| 654 | 'ANTE', | ||
| 655 | 'ANTI', | ||
| 656 | 'AQUA', | ||
| 657 | 'ARAB', | ||
| 658 | 'ARCH', | ||
| 659 | 'AREA', | ||
| 660 | 'ARGO', | ||
| 661 | 'ARID', | ||
| 662 | 'ARMY', | ||
| 663 | 'ARTS', | ||
| 664 | 'ARTY', | ||
| 665 | 'ASIA', | ||
| 666 | 'ASKS', | ||
| 667 | 'ATOM', | ||
| 668 | 'AUNT', | ||
| 669 | 'AURA', | ||
| 670 | 'AUTO', | ||
| 671 | 'AVER', | ||
| 672 | 'AVID', | ||
| 673 | 'AVIS', | ||
| 674 | 'AVON', | ||
| 675 | 'AVOW', | ||
| 676 | 'AWAY', | ||
| 677 | 'AWRY', | ||
| 678 | 'BABE', | ||
| 679 | 'BABY', | ||
| 680 | 'BACH', | ||
| 681 | 'BACK', | ||
| 682 | 'BADE', | ||
| 683 | 'BAIL', | ||
| 684 | 'BAIT', | ||
| 685 | 'BAKE', | ||
| 686 | 'BALD', | ||
| 687 | 'BALE', | ||
| 688 | 'BALI', | ||
| 689 | 'BALK', | ||
| 690 | 'BALL', | ||
| 691 | 'BALM', | ||
| 692 | 'BAND', | ||
| 693 | 'BANE', | ||
| 694 | 'BANG', | ||
| 695 | 'BANK', | ||
| 696 | 'BARB', | ||
| 697 | 'BARD', | ||
| 698 | 'BARE', | ||
| 699 | 'BARK', | ||
| 700 | 'BARN', | ||
| 701 | 'BARR', | ||
| 702 | 'BASE', | ||
| 703 | 'BASH', | ||
| 704 | 'BASK', | ||
| 705 | 'BASS', | ||
| 706 | 'BATE', | ||
| 707 | 'BATH', | ||
| 708 | 'BAWD', | ||
| 709 | 'BAWL', | ||
| 710 | 'BEAD', | ||
| 711 | 'BEAK', | ||
| 712 | 'BEAM', | ||
| 713 | 'BEAN', | ||
| 714 | 'BEAR', | ||
| 715 | 'BEAT', | ||
| 716 | 'BEAU', | ||
| 717 | 'BECK', | ||
| 718 | 'BEEF', | ||
| 719 | 'BEEN', | ||
| 720 | 'BEER', | ||
| 721 | 'BEET', | ||
| 722 | 'BELA', | ||
| 723 | 'BELL', | ||
| 724 | 'BELT', | ||
| 725 | 'BEND', | ||
| 726 | 'BENT', | ||
| 727 | 'BERG', | ||
| 728 | 'BERN', | ||
| 729 | 'BERT', | ||
| 730 | 'BESS', | ||
| 731 | 'BEST', | ||
| 732 | 'BETA', | ||
| 733 | 'BETH', | ||
| 734 | 'BHOY', | ||
| 735 | 'BIAS', | ||
| 736 | 'BIDE', | ||
| 737 | 'BIEN', | ||
| 738 | 'BILE', | ||
| 739 | 'BILK', | ||
| 740 | 'BILL', | ||
| 741 | 'BIND', | ||
| 742 | 'BING', | ||
| 743 | 'BIRD', | ||
| 744 | 'BITE', | ||
| 745 | 'BITS', | ||
| 746 | 'BLAB', | ||
| 747 | 'BLAT', | ||
| 748 | 'BLED', | ||
| 749 | 'BLEW', | ||
| 750 | 'BLOB', | ||
| 751 | 'BLOC', | ||
| 752 | 'BLOT', | ||
| 753 | 'BLOW', | ||
| 754 | 'BLUE', | ||
| 755 | 'BLUM', | ||
| 756 | 'BLUR', | ||
| 757 | 'BOAR', | ||
| 758 | 'BOAT', | ||
| 759 | 'BOCA', | ||
| 760 | 'BOCK', | ||
| 761 | 'BODE', | ||
| 762 | 'BODY', | ||
| 763 | 'BOGY', | ||
| 764 | 'BOHR', | ||
| 765 | 'BOIL', | ||
| 766 | 'BOLD', | ||
| 767 | 'BOLO', | ||
| 768 | 'BOLT', | ||
| 769 | 'BOMB', | ||
| 770 | 'BONA', | ||
| 771 | 'BOND', | ||
| 772 | 'BONE', | ||
| 773 | 'BONG', | ||
| 774 | 'BONN', | ||
| 775 | 'BONY', | ||
| 776 | 'BOOK', | ||
| 777 | 'BOOM', | ||
| 778 | 'BOON', | ||
| 779 | 'BOOT', | ||
| 780 | 'BORE', | ||
| 781 | 'BORG', | ||
| 782 | 'BORN', | ||
| 783 | 'BOSE', | ||
| 784 | 'BOSS', | ||
| 785 | 'BOTH', | ||
| 786 | 'BOUT', | ||
| 787 | 'BOWL', | ||
| 788 | 'BOYD', | ||
| 789 | 'BRAD', | ||
| 790 | 'BRAE', | ||
| 791 | 'BRAG', | ||
| 792 | 'BRAN', | ||
| 793 | 'BRAY', | ||
| 794 | 'BRED', | ||
| 795 | 'BREW', | ||
| 796 | 'BRIG', | ||
| 797 | 'BRIM', | ||
| 798 | 'BROW', | ||
| 799 | 'BUCK', | ||
| 800 | 'BUDD', | ||
| 801 | 'BUFF', | ||
| 802 | 'BULB', | ||
| 803 | 'BULK', | ||
| 804 | 'BULL', | ||
| 805 | 'BUNK', | ||
| 806 | 'BUNT', | ||
| 807 | 'BUOY', | ||
| 808 | 'BURG', | ||
| 809 | 'BURL', | ||
| 810 | 'BURN', | ||
| 811 | 'BURR', | ||
| 812 | 'BURT', | ||
| 813 | 'BURY', | ||
| 814 | 'BUSH', | ||
| 815 | 'BUSS', | ||
| 816 | 'BUST', | ||
| 817 | 'BUSY', | ||
| 818 | 'BYTE', | ||
| 819 | 'CADY', | ||
| 820 | 'CAFE', | ||
| 821 | 'CAGE', | ||
| 822 | 'CAIN', | ||
| 823 | 'CAKE', | ||
| 824 | 'CALF', | ||
| 825 | 'CALL', | ||
| 826 | 'CALM', | ||
| 827 | 'CAME', | ||
| 828 | 'CANE', | ||
| 829 | 'CANT', | ||
| 830 | 'CARD', | ||
| 831 | 'CARE', | ||
| 832 | 'CARL', | ||
| 833 | 'CARR', | ||
| 834 | 'CART', | ||
| 835 | 'CASE', | ||
| 836 | 'CASH', | ||
| 837 | 'CASK', | ||
| 838 | 'CAST', | ||
| 839 | 'CAVE', | ||
| 840 | 'CEIL', | ||
| 841 | 'CELL', | ||
| 842 | 'CENT', | ||
| 843 | 'CERN', | ||
| 844 | 'CHAD', | ||
| 845 | 'CHAR', | ||
| 846 | 'CHAT', | ||
| 847 | 'CHAW', | ||
| 848 | 'CHEF', | ||
| 849 | 'CHEN', | ||
| 850 | 'CHEW', | ||
| 851 | 'CHIC', | ||
| 852 | 'CHIN', | ||
| 853 | 'CHOU', | ||
| 854 | 'CHOW', | ||
| 855 | 'CHUB', | ||
| 856 | 'CHUG', | ||
| 857 | 'CHUM', | ||
| 858 | 'CITE', | ||
| 859 | 'CITY', | ||
| 860 | 'CLAD', | ||
| 861 | 'CLAM', | ||
| 862 | 'CLAN', | ||
| 863 | 'CLAW', | ||
| 864 | 'CLAY', | ||
| 865 | 'CLOD', | ||
| 866 | 'CLOG', | ||
| 867 | 'CLOT', | ||
| 868 | 'CLUB', | ||
| 869 | 'CLUE', | ||
| 870 | 'COAL', | ||
| 871 | 'COAT', | ||
| 872 | 'COCA', | ||
| 873 | 'COCK', | ||
| 874 | 'COCO', | ||
| 875 | 'CODA', | ||
| 876 | 'CODE', | ||
| 877 | 'CODY', | ||
| 878 | 'COED', | ||
| 879 | 'COIL', | ||
| 880 | 'COIN', | ||
| 881 | 'COKE', | ||
| 882 | 'COLA', | ||
| 883 | 'COLD', | ||
| 884 | 'COLT', | ||
| 885 | 'COMA', | ||
| 886 | 'COMB', | ||
| 887 | 'COME', | ||
| 888 | 'COOK', | ||
| 889 | 'COOL', | ||
| 890 | 'COON', | ||
| 891 | 'COOT', | ||
| 892 | 'CORD', | ||
| 893 | 'CORE', | ||
| 894 | 'CORK', | ||
| 895 | 'CORN', | ||
| 896 | 'COST', | ||
| 897 | 'COVE', | ||
| 898 | 'COWL', | ||
| 899 | 'CRAB', | ||
| 900 | 'CRAG', | ||
| 901 | 'CRAM', | ||
| 902 | 'CRAY', | ||
| 903 | 'CREW', | ||
| 904 | 'CRIB', | ||
| 905 | 'CROW', | ||
| 906 | 'CRUD', | ||
| 907 | 'CUBA', | ||
| 908 | 'CUBE', | ||
| 909 | 'CUFF', | ||
| 910 | 'CULL', | ||
| 911 | 'CULT', | ||
| 912 | 'CUNY', | ||
| 913 | 'CURB', | ||
| 914 | 'CURD', | ||
| 915 | 'CURE', | ||
| 916 | 'CURL', | ||
| 917 | 'CURT', | ||
| 918 | 'CUTS', | ||
| 919 | 'DADE', | ||
| 920 | 'DALE', | ||
| 921 | 'DAME', | ||
| 922 | 'DANA', | ||
| 923 | 'DANE', | ||
| 924 | 'DANG', | ||
| 925 | 'DANK', | ||
| 926 | 'DARE', | ||
| 927 | 'DARK', | ||
| 928 | 'DARN', | ||
| 929 | 'DART', | ||
| 930 | 'DASH', | ||
| 931 | 'DATA', | ||
| 932 | 'DATE', | ||
| 933 | 'DAVE', | ||
| 934 | 'DAVY', | ||
| 935 | 'DAWN', | ||
| 936 | 'DAYS', | ||
| 937 | 'DEAD', | ||
| 938 | 'DEAF', | ||
| 939 | 'DEAL', | ||
| 940 | 'DEAN', | ||
| 941 | 'DEAR', | ||
| 942 | 'DEBT', | ||
| 943 | 'DECK', | ||
| 944 | 'DEED', | ||
| 945 | 'DEEM', | ||
| 946 | 'DEER', | ||
| 947 | 'DEFT', | ||
| 948 | 'DEFY', | ||
| 949 | 'DELL', | ||
| 950 | 'DENT', | ||
| 951 | 'DENY', | ||
| 952 | 'DESK', | ||
| 953 | 'DIAL', | ||
| 954 | 'DICE', | ||
| 955 | 'DIED', | ||
| 956 | 'DIET', | ||
| 957 | 'DIME', | ||
| 958 | 'DINE', | ||
| 959 | 'DING', | ||
| 960 | 'DINT', | ||
| 961 | 'DIRE', | ||
| 962 | 'DIRT', | ||
| 963 | 'DISC', | ||
| 964 | 'DISH', | ||
| 965 | 'DISK', | ||
| 966 | 'DIVE', | ||
| 967 | 'DOCK', | ||
| 968 | 'DOES', | ||
| 969 | 'DOLE', | ||
| 970 | 'DOLL', | ||
| 971 | 'DOLT', | ||
| 972 | 'DOME', | ||
| 973 | 'DONE', | ||
| 974 | 'DOOM', | ||
| 975 | 'DOOR', | ||
| 976 | 'DORA', | ||
| 977 | 'DOSE', | ||
| 978 | 'DOTE', | ||
| 979 | 'DOUG', | ||
| 980 | 'DOUR', | ||
| 981 | 'DOVE', | ||
| 982 | 'DOWN', | ||
| 983 | 'DRAB', | ||
| 984 | 'DRAG', | ||
| 985 | 'DRAM', | ||
| 986 | 'DRAW', | ||
| 987 | 'DREW', | ||
| 988 | 'DRUB', | ||
| 989 | 'DRUG', | ||
| 990 | 'DRUM', | ||
| 991 | 'DUAL', | ||
| 992 | 'DUCK', | ||
| 993 | 'DUCT', | ||
| 994 | 'DUEL', | ||
| 995 | 'DUET', | ||
| 996 | 'DUKE', | ||
| 997 | 'DULL', | ||
| 998 | 'DUMB', | ||
| 999 | 'DUNE', | ||
| 1000 | 'DUNK', | ||
| 1001 | 'DUSK', | ||
| 1002 | 'DUST', | ||
| 1003 | 'DUTY', | ||
| 1004 | 'EACH', | ||
| 1005 | 'EARL', | ||
| 1006 | 'EARN', | ||
| 1007 | 'EASE', | ||
| 1008 | 'EAST', | ||
| 1009 | 'EASY', | ||
| 1010 | 'EBEN', | ||
| 1011 | 'ECHO', | ||
| 1012 | 'EDDY', | ||
| 1013 | 'EDEN', | ||
| 1014 | 'EDGE', | ||
| 1015 | 'EDGY', | ||
| 1016 | 'EDIT', | ||
| 1017 | 'EDNA', | ||
| 1018 | 'EGAN', | ||
| 1019 | 'ELAN', | ||
| 1020 | 'ELBA', | ||
| 1021 | 'ELLA', | ||
| 1022 | 'ELSE', | ||
| 1023 | 'EMIL', | ||
| 1024 | 'EMIT', | ||
| 1025 | 'EMMA', | ||
| 1026 | 'ENDS', | ||
| 1027 | 'ERIC', | ||
| 1028 | 'EROS', | ||
| 1029 | 'EVEN', | ||
| 1030 | 'EVER', | ||
| 1031 | 'EVIL', | ||
| 1032 | 'EYED', | ||
| 1033 | 'FACE', | ||
| 1034 | 'FACT', | ||
| 1035 | 'FADE', | ||
| 1036 | 'FAIL', | ||
| 1037 | 'FAIN', | ||
| 1038 | 'FAIR', | ||
| 1039 | 'FAKE', | ||
| 1040 | 'FALL', | ||
| 1041 | 'FAME', | ||
| 1042 | 'FANG', | ||
| 1043 | 'FARM', | ||
| 1044 | 'FAST', | ||
| 1045 | 'FATE', | ||
| 1046 | 'FAWN', | ||
| 1047 | 'FEAR', | ||
| 1048 | 'FEAT', | ||
| 1049 | 'FEED', | ||
| 1050 | 'FEEL', | ||
| 1051 | 'FEET', | ||
| 1052 | 'FELL', | ||
| 1053 | 'FELT', | ||
| 1054 | 'FEND', | ||
| 1055 | 'FERN', | ||
| 1056 | 'FEST', | ||
| 1057 | 'FEUD', | ||
| 1058 | 'FIEF', | ||
| 1059 | 'FIGS', | ||
| 1060 | 'FILE', | ||
| 1061 | 'FILL', | ||
| 1062 | 'FILM', | ||
| 1063 | 'FIND', | ||
| 1064 | 'FINE', | ||
| 1065 | 'FINK', | ||
| 1066 | 'FIRE', | ||
| 1067 | 'FIRM', | ||
| 1068 | 'FISH', | ||
| 1069 | 'FISK', | ||
| 1070 | 'FIST', | ||
| 1071 | 'FITS', | ||
| 1072 | 'FIVE', | ||
| 1073 | 'FLAG', | ||
| 1074 | 'FLAK', | ||
| 1075 | 'FLAM', | ||
| 1076 | 'FLAT', | ||
| 1077 | 'FLAW', | ||
| 1078 | 'FLEA', | ||
| 1079 | 'FLED', | ||
| 1080 | 'FLEW', | ||
| 1081 | 'FLIT', | ||
| 1082 | 'FLOC', | ||
| 1083 | 'FLOG', | ||
| 1084 | 'FLOW', | ||
| 1085 | 'FLUB', | ||
| 1086 | 'FLUE', | ||
| 1087 | 'FOAL', | ||
| 1088 | 'FOAM', | ||
| 1089 | 'FOGY', | ||
| 1090 | 'FOIL', | ||
| 1091 | 'FOLD', | ||
| 1092 | 'FOLK', | ||
| 1093 | 'FOND', | ||
| 1094 | 'FONT', | ||
| 1095 | 'FOOD', | ||
| 1096 | 'FOOL', | ||
| 1097 | 'FOOT', | ||
| 1098 | 'FORD', | ||
| 1099 | 'FORE', | ||
| 1100 | 'FORK', | ||
| 1101 | 'FORM', | ||
| 1102 | 'FORT', | ||
| 1103 | 'FOSS', | ||
| 1104 | 'FOUL', | ||
| 1105 | 'FOUR', | ||
| 1106 | 'FOWL', | ||
| 1107 | 'FRAU', | ||
| 1108 | 'FRAY', | ||
| 1109 | 'FRED', | ||
| 1110 | 'FREE', | ||
| 1111 | 'FRET', | ||
| 1112 | 'FREY', | ||
| 1113 | 'FROG', | ||
| 1114 | 'FROM', | ||
| 1115 | 'FUEL', | ||
| 1116 | 'FULL', | ||
| 1117 | 'FUME', | ||
| 1118 | 'FUND', | ||
| 1119 | 'FUNK', | ||
| 1120 | 'FURY', | ||
| 1121 | 'FUSE', | ||
| 1122 | 'FUSS', | ||
| 1123 | 'GAFF', | ||
| 1124 | 'GAGE', | ||
| 1125 | 'GAIL', | ||
| 1126 | 'GAIN', | ||
| 1127 | 'GAIT', | ||
| 1128 | 'GALA', | ||
| 1129 | 'GALE', | ||
| 1130 | 'GALL', | ||
| 1131 | 'GALT', | ||
| 1132 | 'GAME', | ||
| 1133 | 'GANG', | ||
| 1134 | 'GARB', | ||
| 1135 | 'GARY', | ||
| 1136 | 'GASH', | ||
| 1137 | 'GATE', | ||
| 1138 | 'GAUL', | ||
| 1139 | 'GAUR', | ||
| 1140 | 'GAVE', | ||
| 1141 | 'GAWK', | ||
| 1142 | 'GEAR', | ||
| 1143 | 'GELD', | ||
| 1144 | 'GENE', | ||
| 1145 | 'GENT', | ||
| 1146 | 'GERM', | ||
| 1147 | 'GETS', | ||
| 1148 | 'GIBE', | ||
| 1149 | 'GIFT', | ||
| 1150 | 'GILD', | ||
| 1151 | 'GILL', | ||
| 1152 | 'GILT', | ||
| 1153 | 'GINA', | ||
| 1154 | 'GIRD', | ||
| 1155 | 'GIRL', | ||
| 1156 | 'GIST', | ||
| 1157 | 'GIVE', | ||
| 1158 | 'GLAD', | ||
| 1159 | 'GLEE', | ||
| 1160 | 'GLEN', | ||
| 1161 | 'GLIB', | ||
| 1162 | 'GLOB', | ||
| 1163 | 'GLOM', | ||
| 1164 | 'GLOW', | ||
| 1165 | 'GLUE', | ||
| 1166 | 'GLUM', | ||
| 1167 | 'GLUT', | ||
| 1168 | 'GOAD', | ||
| 1169 | 'GOAL', | ||
| 1170 | 'GOAT', | ||
| 1171 | 'GOER', | ||
| 1172 | 'GOES', | ||
| 1173 | 'GOLD', | ||
| 1174 | 'GOLF', | ||
| 1175 | 'GONE', | ||
| 1176 | 'GONG', | ||
| 1177 | 'GOOD', | ||
| 1178 | 'GOOF', | ||
| 1179 | 'GORE', | ||
| 1180 | 'GORY', | ||
| 1181 | 'GOSH', | ||
| 1182 | 'GOUT', | ||
| 1183 | 'GOWN', | ||
| 1184 | 'GRAB', | ||
| 1185 | 'GRAD', | ||
| 1186 | 'GRAY', | ||
| 1187 | 'GREG', | ||
| 1188 | 'GREW', | ||
| 1189 | 'GREY', | ||
| 1190 | 'GRID', | ||
| 1191 | 'GRIM', | ||
| 1192 | 'GRIN', | ||
| 1193 | 'GRIT', | ||
| 1194 | 'GROW', | ||
| 1195 | 'GRUB', | ||
| 1196 | 'GULF', | ||
| 1197 | 'GULL', | ||
| 1198 | 'GUNK', | ||
| 1199 | 'GURU', | ||
| 1200 | 'GUSH', | ||
| 1201 | 'GUST', | ||
| 1202 | 'GWEN', | ||
| 1203 | 'GWYN', | ||
| 1204 | 'HAAG', | ||
| 1205 | 'HAAS', | ||
| 1206 | 'HACK', | ||
| 1207 | 'HAIL', | ||
| 1208 | 'HAIR', | ||
| 1209 | 'HALE', | ||
| 1210 | 'HALF', | ||
| 1211 | 'HALL', | ||
| 1212 | 'HALO', | ||
| 1213 | 'HALT', | ||
| 1214 | 'HAND', | ||
| 1215 | 'HANG', | ||
| 1216 | 'HANK', | ||
| 1217 | 'HANS', | ||
| 1218 | 'HARD', | ||
| 1219 | 'HARK', | ||
| 1220 | 'HARM', | ||
| 1221 | 'HART', | ||
| 1222 | 'HASH', | ||
| 1223 | 'HAST', | ||
| 1224 | 'HATE', | ||
| 1225 | 'HATH', | ||
| 1226 | 'HAUL', | ||
| 1227 | 'HAVE', | ||
| 1228 | 'HAWK', | ||
| 1229 | 'HAYS', | ||
| 1230 | 'HEAD', | ||
| 1231 | 'HEAL', | ||
| 1232 | 'HEAR', | ||
| 1233 | 'HEAT', | ||
| 1234 | 'HEBE', | ||
| 1235 | 'HECK', | ||
| 1236 | 'HEED', | ||
| 1237 | 'HEEL', | ||
| 1238 | 'HEFT', | ||
| 1239 | 'HELD', | ||
| 1240 | 'HELL', | ||
| 1241 | 'HELM', | ||
| 1242 | 'HERB', | ||
| 1243 | 'HERD', | ||
| 1244 | 'HERE', | ||
| 1245 | 'HERO', | ||
| 1246 | 'HERS', | ||
| 1247 | 'HESS', | ||
| 1248 | 'HEWN', | ||
| 1249 | 'HICK', | ||
| 1250 | 'HIDE', | ||
| 1251 | 'HIGH', | ||
| 1252 | 'HIKE', | ||
| 1253 | 'HILL', | ||
| 1254 | 'HILT', | ||
| 1255 | 'HIND', | ||
| 1256 | 'HINT', | ||
| 1257 | 'HIRE', | ||
| 1258 | 'HISS', | ||
| 1259 | 'HIVE', | ||
| 1260 | 'HOBO', | ||
| 1261 | 'HOCK', | ||
| 1262 | 'HOFF', | ||
| 1263 | 'HOLD', | ||
| 1264 | 'HOLE', | ||
| 1265 | 'HOLM', | ||
| 1266 | 'HOLT', | ||
| 1267 | 'HOME', | ||
| 1268 | 'HONE', | ||
| 1269 | 'HONK', | ||
| 1270 | 'HOOD', | ||
| 1271 | 'HOOF', | ||
| 1272 | 'HOOK', | ||
| 1273 | 'HOOT', | ||
| 1274 | 'HORN', | ||
| 1275 | 'HOSE', | ||
| 1276 | 'HOST', | ||
| 1277 | 'HOUR', | ||
| 1278 | 'HOVE', | ||
| 1279 | 'HOWE', | ||
| 1280 | 'HOWL', | ||
| 1281 | 'HOYT', | ||
| 1282 | 'HUCK', | ||
| 1283 | 'HUED', | ||
| 1284 | 'HUFF', | ||
| 1285 | 'HUGE', | ||
| 1286 | 'HUGH', | ||
| 1287 | 'HUGO', | ||
| 1288 | 'HULK', | ||
| 1289 | 'HULL', | ||
| 1290 | 'HUNK', | ||
| 1291 | 'HUNT', | ||
| 1292 | 'HURD', | ||
| 1293 | 'HURL', | ||
| 1294 | 'HURT', | ||
| 1295 | 'HUSH', | ||
| 1296 | 'HYDE', | ||
| 1297 | 'HYMN', | ||
| 1298 | 'IBIS', | ||
| 1299 | 'ICON', | ||
| 1300 | 'IDEA', | ||
| 1301 | 'IDLE', | ||
| 1302 | 'IFFY', | ||
| 1303 | 'INCA', | ||
| 1304 | 'INCH', | ||
| 1305 | 'INTO', | ||
| 1306 | 'IONS', | ||
| 1307 | 'IOTA', | ||
| 1308 | 'IOWA', | ||
| 1309 | 'IRIS', | ||
| 1310 | 'IRMA', | ||
| 1311 | 'IRON', | ||
| 1312 | 'ISLE', | ||
| 1313 | 'ITCH', | ||
| 1314 | 'ITEM', | ||
| 1315 | 'IVAN', | ||
| 1316 | 'JACK', | ||
| 1317 | 'JADE', | ||
| 1318 | 'JAIL', | ||
| 1319 | 'JAKE', | ||
| 1320 | 'JANE', | ||
| 1321 | 'JAVA', | ||
| 1322 | 'JEAN', | ||
| 1323 | 'JEFF', | ||
| 1324 | 'JERK', | ||
| 1325 | 'JESS', | ||
| 1326 | 'JEST', | ||
| 1327 | 'JIBE', | ||
| 1328 | 'JILL', | ||
| 1329 | 'JILT', | ||
| 1330 | 'JIVE', | ||
| 1331 | 'JOAN', | ||
| 1332 | 'JOBS', | ||
| 1333 | 'JOCK', | ||
| 1334 | 'JOEL', | ||
| 1335 | 'JOEY', | ||
| 1336 | 'JOHN', | ||
| 1337 | 'JOIN', | ||
| 1338 | 'JOKE', | ||
| 1339 | 'JOLT', | ||
| 1340 | 'JOVE', | ||
| 1341 | 'JUDD', | ||
| 1342 | 'JUDE', | ||
| 1343 | 'JUDO', | ||
| 1344 | 'JUDY', | ||
| 1345 | 'JUJU', | ||
| 1346 | 'JUKE', | ||
| 1347 | 'JULY', | ||
| 1348 | 'JUNE', | ||
| 1349 | 'JUNK', | ||
| 1350 | 'JUNO', | ||
| 1351 | 'JURY', | ||
| 1352 | 'JUST', | ||
| 1353 | 'JUTE', | ||
| 1354 | 'KAHN', | ||
| 1355 | 'KALE', | ||
| 1356 | 'KANE', | ||
| 1357 | 'KANT', | ||
| 1358 | 'KARL', | ||
| 1359 | 'KATE', | ||
| 1360 | 'KEEL', | ||
| 1361 | 'KEEN', | ||
| 1362 | 'KENO', | ||
| 1363 | 'KENT', | ||
| 1364 | 'KERN', | ||
| 1365 | 'KERR', | ||
| 1366 | 'KEYS', | ||
| 1367 | 'KICK', | ||
| 1368 | 'KILL', | ||
| 1369 | 'KIND', | ||
| 1370 | 'KING', | ||
| 1371 | 'KIRK', | ||
| 1372 | 'KISS', | ||
| 1373 | 'KITE', | ||
| 1374 | 'KLAN', | ||
| 1375 | 'KNEE', | ||
| 1376 | 'KNEW', | ||
| 1377 | 'KNIT', | ||
| 1378 | 'KNOB', | ||
| 1379 | 'KNOT', | ||
| 1380 | 'KNOW', | ||
| 1381 | 'KOCH', | ||
| 1382 | 'KONG', | ||
| 1383 | 'KUDO', | ||
| 1384 | 'KURD', | ||
| 1385 | 'KURT', | ||
| 1386 | 'KYLE', | ||
| 1387 | 'LACE', | ||
| 1388 | 'LACK', | ||
| 1389 | 'LACY', | ||
| 1390 | 'LADY', | ||
| 1391 | 'LAID', | ||
| 1392 | 'LAIN', | ||
| 1393 | 'LAIR', | ||
| 1394 | 'LAKE', | ||
| 1395 | 'LAMB', | ||
| 1396 | 'LAME', | ||
| 1397 | 'LAND', | ||
| 1398 | 'LANE', | ||
| 1399 | 'LANG', | ||
| 1400 | 'LARD', | ||
| 1401 | 'LARK', | ||
| 1402 | 'LASS', | ||
| 1403 | 'LAST', | ||
| 1404 | 'LATE', | ||
| 1405 | 'LAUD', | ||
| 1406 | 'LAVA', | ||
| 1407 | 'LAWN', | ||
| 1408 | 'LAWS', | ||
| 1409 | 'LAYS', | ||
| 1410 | 'LEAD', | ||
| 1411 | 'LEAF', | ||
| 1412 | 'LEAK', | ||
| 1413 | 'LEAN', | ||
| 1414 | 'LEAR', | ||
| 1415 | 'LEEK', | ||
| 1416 | 'LEER', | ||
| 1417 | 'LEFT', | ||
| 1418 | 'LEND', | ||
| 1419 | 'LENS', | ||
| 1420 | 'LENT', | ||
| 1421 | 'LEON', | ||
| 1422 | 'LESK', | ||
| 1423 | 'LESS', | ||
| 1424 | 'LEST', | ||
| 1425 | 'LETS', | ||
| 1426 | 'LIAR', | ||
| 1427 | 'LICE', | ||
| 1428 | 'LICK', | ||
| 1429 | 'LIED', | ||
| 1430 | 'LIEN', | ||
| 1431 | 'LIES', | ||
| 1432 | 'LIEU', | ||
| 1433 | 'LIFE', | ||
| 1434 | 'LIFT', | ||
| 1435 | 'LIKE', | ||
| 1436 | 'LILA', | ||
| 1437 | 'LILT', | ||
| 1438 | 'LILY', | ||
| 1439 | 'LIMA', | ||
| 1440 | 'LIMB', | ||
| 1441 | 'LIME', | ||
| 1442 | 'LIND', | ||
| 1443 | 'LINE', | ||
| 1444 | 'LINK', | ||
| 1445 | 'LINT', | ||
| 1446 | 'LION', | ||
| 1447 | 'LISA', | ||
| 1448 | 'LIST', | ||
| 1449 | 'LIVE', | ||
| 1450 | 'LOAD', | ||
| 1451 | 'LOAF', | ||
| 1452 | 'LOAM', | ||
| 1453 | 'LOAN', | ||
| 1454 | 'LOCK', | ||
| 1455 | 'LOFT', | ||
| 1456 | 'LOGE', | ||
| 1457 | 'LOIS', | ||
| 1458 | 'LOLA', | ||
| 1459 | 'LONE', | ||
| 1460 | 'LONG', | ||
| 1461 | 'LOOK', | ||
| 1462 | 'LOON', | ||
| 1463 | 'LOOT', | ||
| 1464 | 'LORD', | ||
| 1465 | 'LORE', | ||
| 1466 | 'LOSE', | ||
| 1467 | 'LOSS', | ||
| 1468 | 'LOST', | ||
| 1469 | 'LOUD', | ||
| 1470 | 'LOVE', | ||
| 1471 | 'LOWE', | ||
| 1472 | 'LUCK', | ||
| 1473 | 'LUCY', | ||
| 1474 | 'LUGE', | ||
| 1475 | 'LUKE', | ||
| 1476 | 'LULU', | ||
| 1477 | 'LUND', | ||
| 1478 | 'LUNG', | ||
| 1479 | 'LURA', | ||
| 1480 | 'LURE', | ||
| 1481 | 'LURK', | ||
| 1482 | 'LUSH', | ||
| 1483 | 'LUST', | ||
| 1484 | 'LYLE', | ||
| 1485 | 'LYNN', | ||
| 1486 | 'LYON', | ||
| 1487 | 'LYRA', | ||
| 1488 | 'MACE', | ||
| 1489 | 'MADE', | ||
| 1490 | 'MAGI', | ||
| 1491 | 'MAID', | ||
| 1492 | 'MAIL', | ||
| 1493 | 'MAIN', | ||
| 1494 | 'MAKE', | ||
| 1495 | 'MALE', | ||
| 1496 | 'MALI', | ||
| 1497 | 'MALL', | ||
| 1498 | 'MALT', | ||
| 1499 | 'MANA', | ||
| 1500 | 'MANN', | ||
| 1501 | 'MANY', | ||
| 1502 | 'MARC', | ||
| 1503 | 'MARE', | ||
| 1504 | 'MARK', | ||
| 1505 | 'MARS', | ||
| 1506 | 'MART', | ||
| 1507 | 'MARY', | ||
| 1508 | 'MASH', | ||
| 1509 | 'MASK', | ||
| 1510 | 'MASS', | ||
| 1511 | 'MAST', | ||
| 1512 | 'MATE', | ||
| 1513 | 'MATH', | ||
| 1514 | 'MAUL', | ||
| 1515 | 'MAYO', | ||
| 1516 | 'MEAD', | ||
| 1517 | 'MEAL', | ||
| 1518 | 'MEAN', | ||
| 1519 | 'MEAT', | ||
| 1520 | 'MEEK', | ||
| 1521 | 'MEET', | ||
| 1522 | 'MELD', | ||
| 1523 | 'MELT', | ||
| 1524 | 'MEMO', | ||
| 1525 | 'MEND', | ||
| 1526 | 'MENU', | ||
| 1527 | 'MERT', | ||
| 1528 | 'MESH', | ||
| 1529 | 'MESS', | ||
| 1530 | 'MICE', | ||
| 1531 | 'MIKE', | ||
| 1532 | 'MILD', | ||
| 1533 | 'MILE', | ||
| 1534 | 'MILK', | ||
| 1535 | 'MILL', | ||
| 1536 | 'MILT', | ||
| 1537 | 'MIMI', | ||
| 1538 | 'MIND', | ||
| 1539 | 'MINE', | ||
| 1540 | 'MINI', | ||
| 1541 | 'MINK', | ||
| 1542 | 'MINT', | ||
| 1543 | 'MIRE', | ||
| 1544 | 'MISS', | ||
| 1545 | 'MIST', | ||
| 1546 | 'MITE', | ||
| 1547 | 'MITT', | ||
| 1548 | 'MOAN', | ||
| 1549 | 'MOAT', | ||
| 1550 | 'MOCK', | ||
| 1551 | 'MODE', | ||
| 1552 | 'MOLD', | ||
| 1553 | 'MOLE', | ||
| 1554 | 'MOLL', | ||
| 1555 | 'MOLT', | ||
| 1556 | 'MONA', | ||
| 1557 | 'MONK', | ||
| 1558 | 'MONT', | ||
| 1559 | 'MOOD', | ||
| 1560 | 'MOON', | ||
| 1561 | 'MOOR', | ||
| 1562 | 'MOOT', | ||
| 1563 | 'MORE', | ||
| 1564 | 'MORN', | ||
| 1565 | 'MORT', | ||
| 1566 | 'MOSS', | ||
| 1567 | 'MOST', | ||
| 1568 | 'MOTH', | ||
| 1569 | 'MOVE', | ||
| 1570 | 'MUCH', | ||
| 1571 | 'MUCK', | ||
| 1572 | 'MUDD', | ||
| 1573 | 'MUFF', | ||
| 1574 | 'MULE', | ||
| 1575 | 'MULL', | ||
| 1576 | 'MURK', | ||
| 1577 | 'MUSH', | ||
| 1578 | 'MUST', | ||
| 1579 | 'MUTE', | ||
| 1580 | 'MUTT', | ||
| 1581 | 'MYRA', | ||
| 1582 | 'MYTH', | ||
| 1583 | 'NAGY', | ||
| 1584 | 'NAIL', | ||
| 1585 | 'NAIR', | ||
| 1586 | 'NAME', | ||
| 1587 | 'NARY', | ||
| 1588 | 'NASH', | ||
| 1589 | 'NAVE', | ||
| 1590 | 'NAVY', | ||
| 1591 | 'NEAL', | ||
| 1592 | 'NEAR', | ||
| 1593 | 'NEAT', | ||
| 1594 | 'NECK', | ||
| 1595 | 'NEED', | ||
| 1596 | 'NEIL', | ||
| 1597 | 'NELL', | ||
| 1598 | 'NEON', | ||
| 1599 | 'NERO', | ||
| 1600 | 'NESS', | ||
| 1601 | 'NEST', | ||
| 1602 | 'NEWS', | ||
| 1603 | 'NEWT', | ||
| 1604 | 'NIBS', | ||
| 1605 | 'NICE', | ||
| 1606 | 'NICK', | ||
| 1607 | 'NILE', | ||
| 1608 | 'NINA', | ||
| 1609 | 'NINE', | ||
| 1610 | 'NOAH', | ||
| 1611 | 'NODE', | ||
| 1612 | 'NOEL', | ||
| 1613 | 'NOLL', | ||
| 1614 | 'NONE', | ||
| 1615 | 'NOOK', | ||
| 1616 | 'NOON', | ||
| 1617 | 'NORM', | ||
| 1618 | 'NOSE', | ||
| 1619 | 'NOTE', | ||
| 1620 | 'NOUN', | ||
| 1621 | 'NOVA', | ||
| 1622 | 'NUDE', | ||
| 1623 | 'NULL', | ||
| 1624 | 'NUMB', | ||
| 1625 | 'OATH', | ||
| 1626 | 'OBEY', | ||
| 1627 | 'OBOE', | ||
| 1628 | 'ODIN', | ||
| 1629 | 'OHIO', | ||
| 1630 | 'OILY', | ||
| 1631 | 'OINT', | ||
| 1632 | 'OKAY', | ||
| 1633 | 'OLAF', | ||
| 1634 | 'OLDY', | ||
| 1635 | 'OLGA', | ||
| 1636 | 'OLIN', | ||
| 1637 | 'OMAN', | ||
| 1638 | 'OMEN', | ||
| 1639 | 'OMIT', | ||
| 1640 | 'ONCE', | ||
| 1641 | 'ONES', | ||
| 1642 | 'ONLY', | ||
| 1643 | 'ONTO', | ||
| 1644 | 'ONUS', | ||
| 1645 | 'ORAL', | ||
| 1646 | 'ORGY', | ||
| 1647 | 'OSLO', | ||
| 1648 | 'OTIS', | ||
| 1649 | 'OTTO', | ||
| 1650 | 'OUCH', | ||
| 1651 | 'OUST', | ||
| 1652 | 'OUTS', | ||
| 1653 | 'OVAL', | ||
| 1654 | 'OVEN', | ||
| 1655 | 'OVER', | ||
| 1656 | 'OWLY', | ||
| 1657 | 'OWNS', | ||
| 1658 | 'QUAD', | ||
| 1659 | 'QUIT', | ||
| 1660 | 'QUOD', | ||
| 1661 | 'RACE', | ||
| 1662 | 'RACK', | ||
| 1663 | 'RACY', | ||
| 1664 | 'RAFT', | ||
| 1665 | 'RAGE', | ||
| 1666 | 'RAID', | ||
| 1667 | 'RAIL', | ||
| 1668 | 'RAIN', | ||
| 1669 | 'RAKE', | ||
| 1670 | 'RANK', | ||
| 1671 | 'RANT', | ||
| 1672 | 'RARE', | ||
| 1673 | 'RASH', | ||
| 1674 | 'RATE', | ||
| 1675 | 'RAVE', | ||
| 1676 | 'RAYS', | ||
| 1677 | 'READ', | ||
| 1678 | 'REAL', | ||
| 1679 | 'REAM', | ||
| 1680 | 'REAR', | ||
| 1681 | 'RECK', | ||
| 1682 | 'REED', | ||
| 1683 | 'REEF', | ||
| 1684 | 'REEK', | ||
| 1685 | 'REEL', | ||
| 1686 | 'REID', | ||
| 1687 | 'REIN', | ||
| 1688 | 'RENA', | ||
| 1689 | 'REND', | ||
| 1690 | 'RENT', | ||
| 1691 | 'REST', | ||
| 1692 | 'RICE', | ||
| 1693 | 'RICH', | ||
| 1694 | 'RICK', | ||
| 1695 | 'RIDE', | ||
| 1696 | 'RIFT', | ||
| 1697 | 'RILL', | ||
| 1698 | 'RIME', | ||
| 1699 | 'RING', | ||
| 1700 | 'RINK', | ||
| 1701 | 'RISE', | ||
| 1702 | 'RISK', | ||
| 1703 | 'RITE', | ||
| 1704 | 'ROAD', | ||
| 1705 | 'ROAM', | ||
| 1706 | 'ROAR', | ||
| 1707 | 'ROBE', | ||
| 1708 | 'ROCK', | ||
| 1709 | 'RODE', | ||
| 1710 | 'ROIL', | ||
| 1711 | 'ROLL', | ||
| 1712 | 'ROME', | ||
| 1713 | 'ROOD', | ||
| 1714 | 'ROOF', | ||
| 1715 | 'ROOK', | ||
| 1716 | 'ROOM', | ||
| 1717 | 'ROOT', | ||
| 1718 | 'ROSA', | ||
| 1719 | 'ROSE', | ||
| 1720 | 'ROSS', | ||
| 1721 | 'ROSY', | ||
| 1722 | 'ROTH', | ||
| 1723 | 'ROUT', | ||
| 1724 | 'ROVE', | ||
| 1725 | 'ROWE', | ||
| 1726 | 'ROWS', | ||
| 1727 | 'RUBE', | ||
| 1728 | 'RUBY', | ||
| 1729 | 'RUDE', | ||
| 1730 | 'RUDY', | ||
| 1731 | 'RUIN', | ||
| 1732 | 'RULE', | ||
| 1733 | 'RUNG', | ||
| 1734 | 'RUNS', | ||
| 1735 | 'RUNT', | ||
| 1736 | 'RUSE', | ||
| 1737 | 'RUSH', | ||
| 1738 | 'RUSK', | ||
| 1739 | 'RUSS', | ||
| 1740 | 'RUST', | ||
| 1741 | 'RUTH', | ||
| 1742 | 'SACK', | ||
| 1743 | 'SAFE', | ||
| 1744 | 'SAGE', | ||
| 1745 | 'SAID', | ||
| 1746 | 'SAIL', | ||
| 1747 | 'SALE', | ||
| 1748 | 'SALK', | ||
| 1749 | 'SALT', | ||
| 1750 | 'SAME', | ||
| 1751 | 'SAND', | ||
| 1752 | 'SANE', | ||
| 1753 | 'SANG', | ||
| 1754 | 'SANK', | ||
| 1755 | 'SARA', | ||
| 1756 | 'SAUL', | ||
| 1757 | 'SAVE', | ||
| 1758 | 'SAYS', | ||
| 1759 | 'SCAN', | ||
| 1760 | 'SCAR', | ||
| 1761 | 'SCAT', | ||
| 1762 | 'SCOT', | ||
| 1763 | 'SEAL', | ||
| 1764 | 'SEAM', | ||
| 1765 | 'SEAR', | ||
| 1766 | 'SEAT', | ||
| 1767 | 'SEED', | ||
| 1768 | 'SEEK', | ||
| 1769 | 'SEEM', | ||
| 1770 | 'SEEN', | ||
| 1771 | 'SEES', | ||
| 1772 | 'SELF', | ||
| 1773 | 'SELL', | ||
| 1774 | 'SEND', | ||
| 1775 | 'SENT', | ||
| 1776 | 'SETS', | ||
| 1777 | 'SEWN', | ||
| 1778 | 'SHAG', | ||
| 1779 | 'SHAM', | ||
| 1780 | 'SHAW', | ||
| 1781 | 'SHAY', | ||
| 1782 | 'SHED', | ||
| 1783 | 'SHIM', | ||
| 1784 | 'SHIN', | ||
| 1785 | 'SHOD', | ||
| 1786 | 'SHOE', | ||
| 1787 | 'SHOT', | ||
| 1788 | 'SHOW', | ||
| 1789 | 'SHUN', | ||
| 1790 | 'SHUT', | ||
| 1791 | 'SICK', | ||
| 1792 | 'SIDE', | ||
| 1793 | 'SIFT', | ||
| 1794 | 'SIGH', | ||
| 1795 | 'SIGN', | ||
| 1796 | 'SILK', | ||
| 1797 | 'SILL', | ||
| 1798 | 'SILO', | ||
| 1799 | 'SILT', | ||
| 1800 | 'SINE', | ||
| 1801 | 'SING', | ||
| 1802 | 'SINK', | ||
| 1803 | 'SIRE', | ||
| 1804 | 'SITE', | ||
| 1805 | 'SITS', | ||
| 1806 | 'SITU', | ||
| 1807 | 'SKAT', | ||
| 1808 | 'SKEW', | ||
| 1809 | 'SKID', | ||
| 1810 | 'SKIM', | ||
| 1811 | 'SKIN', | ||
| 1812 | 'SKIT', | ||
| 1813 | 'SLAB', | ||
| 1814 | 'SLAM', | ||
| 1815 | 'SLAT', | ||
| 1816 | 'SLAY', | ||
| 1817 | 'SLED', | ||
| 1818 | 'SLEW', | ||
| 1819 | 'SLID', | ||
| 1820 | 'SLIM', | ||
| 1821 | 'SLIT', | ||
| 1822 | 'SLOB', | ||
| 1823 | 'SLOG', | ||
| 1824 | 'SLOT', | ||
| 1825 | 'SLOW', | ||
| 1826 | 'SLUG', | ||
| 1827 | 'SLUM', | ||
| 1828 | 'SLUR', | ||
| 1829 | 'SMOG', | ||
| 1830 | 'SMUG', | ||
| 1831 | 'SNAG', | ||
| 1832 | 'SNOB', | ||
| 1833 | 'SNOW', | ||
| 1834 | 'SNUB', | ||
| 1835 | 'SNUG', | ||
| 1836 | 'SOAK', | ||
| 1837 | 'SOAR', | ||
| 1838 | 'SOCK', | ||
| 1839 | 'SODA', | ||
| 1840 | 'SOFA', | ||
| 1841 | 'SOFT', | ||
| 1842 | 'SOIL', | ||
| 1843 | 'SOLD', | ||
| 1844 | 'SOME', | ||
| 1845 | 'SONG', | ||
| 1846 | 'SOON', | ||
| 1847 | 'SOOT', | ||
| 1848 | 'SORE', | ||
| 1849 | 'SORT', | ||
| 1850 | 'SOUL', | ||
| 1851 | 'SOUR', | ||
| 1852 | 'SOWN', | ||
| 1853 | 'STAB', | ||
| 1854 | 'STAG', | ||
| 1855 | 'STAN', | ||
| 1856 | 'STAR', | ||
| 1857 | 'STAY', | ||
| 1858 | 'STEM', | ||
| 1859 | 'STEW', | ||
| 1860 | 'STIR', | ||
| 1861 | 'STOW', | ||
| 1862 | 'STUB', | ||
| 1863 | 'STUN', | ||
| 1864 | 'SUCH', | ||
| 1865 | 'SUDS', | ||
| 1866 | 'SUIT', | ||
| 1867 | 'SULK', | ||
| 1868 | 'SUMS', | ||
| 1869 | 'SUNG', | ||
| 1870 | 'SUNK', | ||
| 1871 | 'SURE', | ||
| 1872 | 'SURF', | ||
| 1873 | 'SWAB', | ||
| 1874 | 'SWAG', | ||
| 1875 | 'SWAM', | ||
| 1876 | 'SWAN', | ||
| 1877 | 'SWAT', | ||
| 1878 | 'SWAY', | ||
| 1879 | 'SWIM', | ||
| 1880 | 'SWUM', | ||
| 1881 | 'TACK', | ||
| 1882 | 'TACT', | ||
| 1883 | 'TAIL', | ||
| 1884 | 'TAKE', | ||
| 1885 | 'TALE', | ||
| 1886 | 'TALK', | ||
| 1887 | 'TALL', | ||
| 1888 | 'TANK', | ||
| 1889 | 'TASK', | ||
| 1890 | 'TATE', | ||
| 1891 | 'TAUT', | ||
| 1892 | 'TEAL', | ||
| 1893 | 'TEAM', | ||
| 1894 | 'TEAR', | ||
| 1895 | 'TECH', | ||
| 1896 | 'TEEM', | ||
| 1897 | 'TEEN', | ||
| 1898 | 'TEET', | ||
| 1899 | 'TELL', | ||
| 1900 | 'TEND', | ||
| 1901 | 'TENT', | ||
| 1902 | 'TERM', | ||
| 1903 | 'TERN', | ||
| 1904 | 'TESS', | ||
| 1905 | 'TEST', | ||
| 1906 | 'THAN', | ||
| 1907 | 'THAT', | ||
| 1908 | 'THEE', | ||
| 1909 | 'THEM', | ||
| 1910 | 'THEN', | ||
| 1911 | 'THEY', | ||
| 1912 | 'THIN', | ||
| 1913 | 'THIS', | ||
| 1914 | 'THUD', | ||
| 1915 | 'THUG', | ||
| 1916 | 'TICK', | ||
| 1917 | 'TIDE', | ||
| 1918 | 'TIDY', | ||
| 1919 | 'TIED', | ||
| 1920 | 'TIER', | ||
| 1921 | 'TILE', | ||
| 1922 | 'TILL', | ||
| 1923 | 'TILT', | ||
| 1924 | 'TIME', | ||
| 1925 | 'TINA', | ||
| 1926 | 'TINE', | ||
| 1927 | 'TINT', | ||
| 1928 | 'TINY', | ||
| 1929 | 'TIRE', | ||
| 1930 | 'TOAD', | ||
| 1931 | 'TOGO', | ||
| 1932 | 'TOIL', | ||
| 1933 | 'TOLD', | ||
| 1934 | 'TOLL', | ||
| 1935 | 'TONE', | ||
| 1936 | 'TONG', | ||
| 1937 | 'TONY', | ||
| 1938 | 'TOOK', | ||
| 1939 | 'TOOL', | ||
| 1940 | 'TOOT', | ||
| 1941 | 'TORE', | ||
| 1942 | 'TORN', | ||
| 1943 | 'TOTE', | ||
| 1944 | 'TOUR', | ||
| 1945 | 'TOUT', | ||
| 1946 | 'TOWN', | ||
| 1947 | 'TRAG', | ||
| 1948 | 'TRAM', | ||
| 1949 | 'TRAY', | ||
| 1950 | 'TREE', | ||
| 1951 | 'TREK', | ||
| 1952 | 'TRIG', | ||
| 1953 | 'TRIM', | ||
| 1954 | 'TRIO', | ||
| 1955 | 'TROD', | ||
| 1956 | 'TROT', | ||
| 1957 | 'TROY', | ||
| 1958 | 'TRUE', | ||
| 1959 | 'TUBA', | ||
| 1960 | 'TUBE', | ||
| 1961 | 'TUCK', | ||
| 1962 | 'TUFT', | ||
| 1963 | 'TUNA', | ||
| 1964 | 'TUNE', | ||
| 1965 | 'TUNG', | ||
| 1966 | 'TURF', | ||
| 1967 | 'TURN', | ||
| 1968 | 'TUSK', | ||
| 1969 | 'TWIG', | ||
| 1970 | 'TWIN', | ||
| 1971 | 'TWIT', | ||
| 1972 | 'ULAN', | ||
| 1973 | 'UNIT', | ||
| 1974 | 'URGE', | ||
| 1975 | 'USED', | ||
| 1976 | 'USER', | ||
| 1977 | 'USES', | ||
| 1978 | 'UTAH', | ||
| 1979 | 'VAIL', | ||
| 1980 | 'VAIN', | ||
| 1981 | 'VALE', | ||
| 1982 | 'VARY', | ||
| 1983 | 'VASE', | ||
| 1984 | 'VAST', | ||
| 1985 | 'VEAL', | ||
| 1986 | 'VEDA', | ||
| 1987 | 'VEIL', | ||
| 1988 | 'VEIN', | ||
| 1989 | 'VEND', | ||
| 1990 | 'VENT', | ||
| 1991 | 'VERB', | ||
| 1992 | 'VERY', | ||
| 1993 | 'VETO', | ||
| 1994 | 'VICE', | ||
| 1995 | 'VIEW', | ||
| 1996 | 'VINE', | ||
| 1997 | 'VISE', | ||
| 1998 | 'VOID', | ||
| 1999 | 'VOLT', | ||
| 2000 | 'VOTE', | ||
| 2001 | 'WACK', | ||
| 2002 | 'WADE', | ||
| 2003 | 'WAGE', | ||
| 2004 | 'WAIL', | ||
| 2005 | 'WAIT', | ||
| 2006 | 'WAKE', | ||
| 2007 | 'WALE', | ||
| 2008 | 'WALK', | ||
| 2009 | 'WALL', | ||
| 2010 | 'WALT', | ||
| 2011 | 'WAND', | ||
| 2012 | 'WANE', | ||
| 2013 | 'WANG', | ||
| 2014 | 'WANT', | ||
| 2015 | 'WARD', | ||
| 2016 | 'WARM', | ||
| 2017 | 'WARN', | ||
| 2018 | 'WART', | ||
| 2019 | 'WASH', | ||
| 2020 | 'WAST', | ||
| 2021 | 'WATS', | ||
| 2022 | 'WATT', | ||
| 2023 | 'WAVE', | ||
| 2024 | 'WAVY', | ||
| 2025 | 'WAYS', | ||
| 2026 | 'WEAK', | ||
| 2027 | 'WEAL', | ||
| 2028 | 'WEAN', | ||
| 2029 | 'WEAR', | ||
| 2030 | 'WEED', | ||
| 2031 | 'WEEK', | ||
| 2032 | 'WEIR', | ||
| 2033 | 'WELD', | ||
| 2034 | 'WELL', | ||
| 2035 | 'WELT', | ||
| 2036 | 'WENT', | ||
| 2037 | 'WERE', | ||
| 2038 | 'WERT', | ||
| 2039 | 'WEST', | ||
| 2040 | 'WHAM', | ||
| 2041 | 'WHAT', | ||
| 2042 | 'WHEE', | ||
| 2043 | 'WHEN', | ||
| 2044 | 'WHET', | ||
| 2045 | 'WHOA', | ||
| 2046 | 'WHOM', | ||
| 2047 | 'WICK', | ||
| 2048 | 'WIFE', | ||
| 2049 | 'WILD', | ||
| 2050 | 'WILL', | ||
| 2051 | 'WIND', | ||
| 2052 | 'WINE', | ||
| 2053 | 'WING', | ||
| 2054 | 'WINK', | ||
| 2055 | 'WINO', | ||
| 2056 | 'WIRE', | ||
| 2057 | 'WISE', | ||
| 2058 | 'WISH', | ||
| 2059 | 'WITH', | ||
| 2060 | 'WOLF', | ||
| 2061 | 'WONT', | ||
| 2062 | 'WOOD', | ||
| 2063 | 'WOOL', | ||
| 2064 | 'WORD', | ||
| 2065 | 'WORE', | ||
| 2066 | 'WORK', | ||
| 2067 | 'WORM', | ||
| 2068 | 'WORN', | ||
| 2069 | 'WOVE', | ||
| 2070 | 'WRIT', | ||
| 2071 | 'WYNN', | ||
| 2072 | 'YALE', | ||
| 2073 | 'YANG', | ||
| 2074 | 'YANK', | ||
| 2075 | 'YARD', | ||
| 2076 | 'YARN', | ||
| 2077 | 'YAWL', | ||
| 2078 | 'YAWN', | ||
| 2079 | 'YEAH', | ||
| 2080 | 'YEAR', | ||
| 2081 | 'YELL', | ||
| 2082 | 'YOGA', | ||
| 2083 | 'YOKE', | ||
| 2084 | ] | ||
| 293 | 2085 | ||
| 294 | _ALGO_DICT = {OTP_ALGO_MD5: 'md5', OTP_ALGO_SHA1: 'sha1'} | 2086 | _ALGO_DICT = {OTP_ALGO_MD5: 'md5', OTP_ALGO_SHA1: 'sha1'} |
| 295 | 2087 | ||
| 296 | 2088 | ||
| 297 | class OTPGeneratorException(Exception): | 2089 | class OTPGeneratorError(Exception): |
| 298 | """OTPGeneratorException class""" | 2090 | """OTPGeneratorError class""" |
| 299 | 2091 | ||
| 300 | 2092 | ||
| 301 | class OTPChallengeException(Exception): | 2093 | class OTPChallengeError(Exception): |
| 302 | """OTPChallengeException class""" | 2094 | """OTPChallengeError class""" |
| 303 | 2095 | ||
| 304 | 2096 | ||
| 305 | class OTPGenerator: | 2097 | class OTPGenerator: |
| 306 | """OTPGenerator class""" | 2098 | """OTPGenerator class""" |
| 307 | 2099 | ||
| 308 | def __init__( | 2100 | def __init__( |
| 309 | self, | 2101 | self, password: bytes, seed: str = '', hash_algo=OTP_ALGO_MD5 |
| 310 | password: bytes, | ||
| 311 | seed: str = '', | ||
| 312 | hash_algo=OTP_ALGO_MD5, | ||
| 313 | ): | 2102 | ): |
| 314 | """ | 2103 | """ |
| 315 | Constructs an OTPGenerator object with a given password and seed. | 2104 | Constructs an OTPGenerator object with a given password and seed. |
| @@ -323,7 +2112,7 @@ class OTPGenerator: | |||
| 323 | :param hash_algo: The hash algo, defaults to OTP_ALGO_MD5 | 2112 | :param hash_algo: The hash algo, defaults to OTP_ALGO_MD5 |
| 324 | :type hash_algo: int or str | 2113 | :type hash_algo: int or str |
| 325 | 2114 | ||
| 326 | :raises otp2289.OTPGeneratorException: If the input does not validate | 2115 | :raises otp2289.OTPGeneratorError: If the input does not validate |
| 327 | """ | 2116 | """ |
| 328 | # enforce the rfc2289 constraints | 2117 | # enforce the rfc2289 constraints |
| 329 | self._seed = seed | 2118 | self._seed = seed |
| @@ -331,11 +2120,9 @@ class OTPGenerator: | |||
| 331 | self._seed = self.validate_seed(self._seed) | 2120 | self._seed = self.validate_seed(self._seed) |
| 332 | self._hash_algo = self.validate_hash_algo(hash_algo) | 2121 | self._hash_algo = self.validate_hash_algo(hash_algo) |
| 333 | if not isinstance(password, bytes): | 2122 | if not isinstance(password, bytes): |
| 334 | raise OTPGeneratorException('Password must be a byte-string') | 2123 | raise OTPGeneratorError('Password must be a byte-string') |
| 335 | if len(password) < 10: | 2124 | if len(password) < 10: |
| 336 | raise OTPGeneratorException( | 2125 | raise OTPGeneratorError('Password must be longer than 10 bytes') |
| 337 | 'Password must be longer than 10 bytes' | ||
| 338 | ) | ||
| 339 | self._password = password | 2126 | self._password = password |
| 340 | 2127 | ||
| 341 | def __repr__(self): | 2128 | def __repr__(self): |
| @@ -357,11 +2144,11 @@ class OTPGenerator: | |||
| 357 | :rtype: int | 2144 | :rtype: int |
| 358 | """ | 2145 | """ |
| 359 | if not isinstance(bit_stream, str): | 2146 | if not isinstance(bit_stream, str): |
| 360 | raise OTPGeneratorException('bit_stream must be of type str') | 2147 | raise OTPGeneratorError('bit_stream must be of type str') |
| 361 | if len(bit_stream) != 64: | 2148 | if len(bit_stream) != 64: |
| 362 | raise OTPGeneratorException('bit_stream must be of size 64') | 2149 | raise OTPGeneratorError('bit_stream must be of size 64') |
| 363 | value = 0 | 2150 | value = 0 |
| 364 | for pair in zip(bit_stream[::2], bit_stream[1::2]): | 2151 | for pair in zip(bit_stream[::2], bit_stream[1::2], strict=True): |
| 365 | value += int(''.join(pair), 2) | 2152 | value += int(''.join(pair), 2) |
| 366 | return value | 2153 | return value |
| 367 | 2154 | ||
| @@ -386,10 +2173,7 @@ class OTPGenerator: | |||
| 386 | tokens.append(RFC1760_TOKENS[int(bit_stream[44:55], 2)]) | 2173 | tokens.append(RFC1760_TOKENS[int(bit_stream[44:55], 2)]) |
| 387 | tokens.append( | 2174 | tokens.append( |
| 388 | RFC1760_TOKENS[ | 2175 | RFC1760_TOKENS[ |
| 389 | int( | 2176 | int(bit_stream[55:64] + f'{bit_pair_sum:0>8b}'[-2:], 2) |
| 390 | bit_stream[55:64] + f'{bit_pair_sum:0>8b}'[-2:], | ||
| 391 | 2, | ||
| 392 | ) | ||
| 393 | ] | 2177 | ] |
| 394 | ) | 2178 | ) |
| 395 | return ' '.join(tokens) | 2179 | return ' '.join(tokens) |
| @@ -404,21 +2188,21 @@ class OTPGenerator: | |||
| 404 | :param challenge: The challenge string described in RFC-2289 | 2188 | :param challenge: The challenge string described in RFC-2289 |
| 405 | :type challenge: str | 2189 | :type challenge: str |
| 406 | 2190 | ||
| 407 | :raises otp2289.OTPChallengeException: If the challenge is invalid | 2191 | :raises otp2289.OTPChallengeError: If the challenge is invalid |
| 408 | 2192 | ||
| 409 | :return: (seed, hash_algo, step) tuple. | 2193 | :return: (seed, hash_algo, step) tuple. |
| 410 | :rtype: tuple | 2194 | :rtype: tuple |
| 411 | """ | 2195 | """ |
| 412 | if not isinstance(challenge, str): | 2196 | if not isinstance(challenge, str): |
| 413 | raise OTPChallengeException('Challenge must be str') | 2197 | raise OTPChallengeError('Challenge must be str') |
| 414 | challenge = challenge.strip() | 2198 | challenge = challenge.strip() |
| 415 | if not challenge.startswith('otp-'): | 2199 | if not challenge.startswith('otp-'): |
| 416 | raise OTPChallengeException('Invalid challenge') | 2200 | raise OTPChallengeError('Invalid challenge') |
| 417 | try: | 2201 | try: |
| 418 | hash_algo, step, seed = challenge[4:].split() | 2202 | hash_algo, step, seed = challenge[4:].split() |
| 419 | return (seed, hash_algo, int(step)) | 2203 | return (seed, hash_algo, int(step)) |
| 420 | except ValueError: | 2204 | except ValueError: |
| 421 | raise OTPChallengeException('Invalid challenge') from None | 2205 | raise OTPChallengeError('Invalid challenge') from None |
| 422 | 2206 | ||
| 423 | @staticmethod | 2207 | @staticmethod |
| 424 | def sha1_digest_folding(sha1_digest: bytes) -> bytes: | 2208 | def sha1_digest_folding(sha1_digest: bytes) -> bytes: |
| @@ -432,10 +2216,10 @@ class OTPGenerator: | |||
| 432 | :return: The byte-string representing the folded sha1-digest | 2216 | :return: The byte-string representing the folded sha1-digest |
| 433 | :rtype: bytes | 2217 | :rtype: bytes |
| 434 | """ | 2218 | """ |
| 435 | if not (isinstance(sha1_digest, bytes)): | 2219 | if not isinstance(sha1_digest, bytes): |
| 436 | raise OTPGeneratorException('sha1_digest must be of type bytes') | 2220 | raise OTPGeneratorError('sha1_digest must be of type bytes') |
| 437 | if len(sha1_digest) != 20: | 2221 | if len(sha1_digest) != 20: |
| 438 | raise OTPGeneratorException( | 2222 | raise OTPGeneratorError( |
| 439 | 'sha1_digest must be 160 bits (20 bytes) long' | 2223 | 'sha1_digest must be 160 bits (20 bytes) long' |
| 440 | ) | 2224 | ) |
| 441 | digested = list(5 * b'i') # 5 bytes (40 bits) | 2225 | digested = list(5 * b'i') # 5 bytes (40 bits) |
| @@ -485,12 +2269,12 @@ class OTPGenerator: | |||
| 485 | :rtype: bytes | 2269 | :rtype: bytes |
| 486 | """ | 2270 | """ |
| 487 | if not (isinstance(byte_str1, bytes) and isinstance(byte_str2, bytes)): | 2271 | if not (isinstance(byte_str1, bytes) and isinstance(byte_str2, bytes)): |
| 488 | raise OTPGeneratorException( | 2272 | raise OTPGeneratorError( |
| 489 | 'byte_str1 and byte_str2 must be of type bytes' | 2273 | 'byte_str1 and byte_str2 must be of type bytes' |
| 490 | ) | 2274 | ) |
| 491 | length = len(byte_str1) | 2275 | length = len(byte_str1) |
| 492 | if length != len(byte_str2) or length < 1: | 2276 | if length != len(byte_str2) or length < 1: |
| 493 | raise OTPGeneratorException( | 2277 | raise OTPGeneratorError( |
| 494 | 'byte_str1 and byte_str2 must be of the same length > 0' | 2278 | 'byte_str1 and byte_str2 must be of the same length > 0' |
| 495 | ) | 2279 | ) |
| 496 | return bytes([byte_str1[i] ^ byte_str2[i] for i in range(length)]) | 2280 | return bytes([byte_str1[i] ^ byte_str2[i] for i in range(length)]) |
| @@ -503,25 +2287,23 @@ class OTPGenerator: | |||
| 503 | :param tokens_str: String representing 6 words tokens | 2287 | :param tokens_str: String representing 6 words tokens |
| 504 | :type tokens_str: str | 2288 | :type tokens_str: str |
| 505 | 2289 | ||
| 506 | :raises otp2289.OTPGeneratorException: When the tokens_str is invalid | 2290 | :raises otp2289.OTPGeneratorError: When the tokens_str is invalid |
| 507 | 2291 | ||
| 508 | :return: 6 words tokens | 2292 | :return: 6 words tokens |
| 509 | :rtype: bytes | 2293 | :rtype: bytes |
| 510 | """ | 2294 | """ |
| 511 | if not isinstance(tokens_str, str): | 2295 | if not isinstance(tokens_str, str): |
| 512 | raise OTPGeneratorException('tokens must be a str') | 2296 | raise OTPGeneratorError('tokens must be a str') |
| 513 | tokens = tokens_str.split() | 2297 | tokens = tokens_str.split() |
| 514 | if len(tokens) != 6: | 2298 | if len(tokens) != 6: |
| 515 | raise OTPGeneratorException( | 2299 | raise OTPGeneratorError('Tokens-string does not contain 6 tokens') |
| 516 | 'Tokens-string does not contain 6 tokens' | ||
| 517 | ) | ||
| 518 | token_ints = [] | 2300 | token_ints = [] |
| 519 | try: | 2301 | try: |
| 520 | token_ints = [ | 2302 | token_ints = [ |
| 521 | RFC1760_TOKENS.index(token.upper()) for token in tokens | 2303 | RFC1760_TOKENS.index(token.upper()) for token in tokens |
| 522 | ] | 2304 | ] |
| 523 | except ValueError: | 2305 | except ValueError: |
| 524 | raise OTPGeneratorException( | 2306 | raise OTPGeneratorError( |
| 525 | 'One or more words not present in RFC1760' | 2307 | 'One or more words not present in RFC1760' |
| 526 | ) from None | 2308 | ) from None |
| 527 | # now we build a string of bits | 2309 | # now we build a string of bits |
| @@ -539,7 +2321,7 @@ class OTPGenerator: | |||
| 539 | f'{OTPGenerator.bit_pair_sum(bit_stream[:64]):0>8b}'[-2:] | 2321 | f'{OTPGenerator.bit_pair_sum(bit_stream[:64]):0>8b}'[-2:] |
| 540 | != bit_stream[-2:] | 2322 | != bit_stream[-2:] |
| 541 | ): | 2323 | ): |
| 542 | raise OTPGeneratorException('Invalid bit checksum') | 2324 | raise OTPGeneratorError('Invalid bit checksum') |
| 543 | return int(bit_stream[:64], 2).to_bytes(8, 'big') | 2325 | return int(bit_stream[:64], 2).to_bytes(8, 'big') |
| 544 | 2326 | ||
| 545 | @staticmethod | 2327 | @staticmethod |
| @@ -550,21 +2332,21 @@ class OTPGenerator: | |||
| 550 | :param hash_algo: The hash algo, defaults to OTP_ALGO_MD5 | 2332 | :param hash_algo: The hash algo, defaults to OTP_ALGO_MD5 |
| 551 | :type hash_algo: int or str | 2333 | :type hash_algo: int or str |
| 552 | 2334 | ||
| 553 | :raises otp2289.OTPGeneratorException: If hash_algo does not validate | 2335 | :raises otp2289.OTPGeneratorError: If hash_algo does not validate |
| 554 | 2336 | ||
| 555 | :return: The validated hash_algo in str-form | 2337 | :return: The validated hash_algo in str-form |
| 556 | :rtype: str | 2338 | :rtype: str |
| 557 | """ | 2339 | """ |
| 558 | if isinstance(hash_algo, int): | 2340 | if isinstance(hash_algo, int): |
| 559 | if hash_algo not in _ALGO_DICT: | 2341 | if hash_algo not in _ALGO_DICT: |
| 560 | raise OTPGeneratorException( | 2342 | raise OTPGeneratorError( |
| 561 | 'hash_algo is not among the known algorithms' | 2343 | 'hash_algo is not among the known algorithms' |
| 562 | ) | 2344 | ) |
| 563 | hash_algo = _ALGO_DICT.get(hash_algo) | 2345 | hash_algo = _ALGO_DICT.get(hash_algo) |
| 564 | if not isinstance(hash_algo, str): | 2346 | if not isinstance(hash_algo, str): |
| 565 | raise OTPGeneratorException('hash_algo must be an int or a str') | 2347 | raise OTPGeneratorError('hash_algo must be an int or a str') |
| 566 | if hash_algo not in hashlib.algorithms_available: | 2348 | if hash_algo not in hashlib.algorithms_available: |
| 567 | raise OTPGeneratorException( | 2349 | raise OTPGeneratorError( |
| 568 | f'{hash_algo} is not supported by this version of the ' | 2350 | f'{hash_algo} is not supported by this version of the ' |
| 569 | 'hashlib module' | 2351 | 'hashlib module' |
| 570 | ) | 2352 | ) |
| @@ -578,20 +2360,20 @@ class OTPGenerator: | |||
| 578 | :param seed: The seed received from the challenge, defaults to '' | 2360 | :param seed: The seed received from the challenge, defaults to '' |
| 579 | :type seed: str | 2361 | :type seed: str |
| 580 | 2362 | ||
| 581 | :raises otp2289.OTPGeneratorException: If seed does not validate | 2363 | :raises otp2289.OTPGeneratorError: If seed does not validate |
| 582 | 2364 | ||
| 583 | :return: The validated (and very same) seed | 2365 | :return: The validated (and very same) seed |
| 584 | :rtype: str | 2366 | :rtype: str |
| 585 | """ | 2367 | """ |
| 586 | if not isinstance(seed, str): | 2368 | if not isinstance(seed, str): |
| 587 | raise OTPGeneratorException('Seed must be a string') | 2369 | raise OTPGeneratorError('Seed must be a string') |
| 588 | if not seed or len(seed) > 16: | 2370 | if not seed or len(seed) > 16: |
| 589 | raise OTPGeneratorException( | 2371 | raise OTPGeneratorError( |
| 590 | 'The seed MUST be of 1 to 16 characters in length' | 2372 | 'The seed MUST be of 1 to 16 characters in length' |
| 591 | ) | 2373 | ) |
| 592 | for char in seed: | 2374 | for char in seed: |
| 593 | if char not in string.ascii_letters + string.digits: | 2375 | if char not in string.ascii_letters + string.digits: |
| 594 | raise OTPGeneratorException( | 2376 | raise OTPGeneratorError( |
| 595 | 'The seed MUST consist of purely alphanumeric characters' | 2377 | 'The seed MUST consist of purely alphanumeric characters' |
| 596 | ) | 2378 | ) |
| 597 | return seed | 2379 | return seed |
| @@ -604,15 +2386,15 @@ class OTPGenerator: | |||
| 604 | :param seed: The step received from the challenge | 2386 | :param seed: The step received from the challenge |
| 605 | :type seed: int | 2387 | :type seed: int |
| 606 | 2388 | ||
| 607 | :raises otp2289.OTPGeneratorException: If step does not validate | 2389 | :raises otp2289.OTPGeneratorError: If step does not validate |
| 608 | 2390 | ||
| 609 | :return: The validated (and very same) step | 2391 | :return: The validated (and very same) step |
| 610 | :rtype: int | 2392 | :rtype: int |
| 611 | """ | 2393 | """ |
| 612 | if not isinstance(step, int): | 2394 | if not isinstance(step, int): |
| 613 | raise OTPGeneratorException('Step value MUST be an int') | 2395 | raise OTPGeneratorError('Step value MUST be an int') |
| 614 | if step < 0: | 2396 | if step < 0: |
| 615 | raise OTPGeneratorException('Step value MUST be >= 0') | 2397 | raise OTPGeneratorError('Step value MUST be >= 0') |
| 616 | return step | 2398 | return step |
| 617 | 2399 | ||
| 618 | def generate_otp_hexdigest(self, step: int) -> str: | 2400 | def generate_otp_hexdigest(self, step: int) -> str: |
| @@ -696,11 +2478,9 @@ class OTPGenerator: | |||
| 696 | :rtype: generator | 2478 | :rtype: generator |
| 697 | """ | 2479 | """ |
| 698 | if not isinstance(start, int) and isinstance(stop, int): | 2480 | if not isinstance(start, int) and isinstance(stop, int): |
| 699 | raise OTPGeneratorException('Step value MUST be an int') | 2481 | raise OTPGeneratorError('Step value MUST be an int') |
| 700 | if start < stop: | 2482 | if start < stop: |
| 701 | raise OTPGeneratorException( | 2483 | raise OTPGeneratorError('Start value can not be lower than stop') |
| 702 | 'Start value can not be lower than stop' | ||
| 703 | ) | ||
| 704 | for step in range(start, stop - 1, -1): | 2484 | for step in range(start, stop - 1, -1): |
| 705 | yield self.generate_otp_hexdigest(step) | 2485 | yield self.generate_otp_hexdigest(step) |
| 706 | 2486 | ||
| @@ -719,11 +2499,9 @@ class OTPGenerator: | |||
| 719 | :rtype: generator | 2499 | :rtype: generator |
| 720 | """ | 2500 | """ |
| 721 | if not isinstance(start, int) and isinstance(stop, int): | 2501 | if not isinstance(start, int) and isinstance(stop, int): |
| 722 | raise OTPGeneratorException('Step value MUST be an int') | 2502 | raise OTPGeneratorError('Step value MUST be an int') |
| 723 | if start < stop: | 2503 | if start < stop: |
| 724 | raise OTPGeneratorException( | 2504 | raise OTPGeneratorError('Start value can not be lower than stop') |
| 725 | 'Start value can not be lower than stop' | ||
| 726 | ) | ||
| 727 | for step in range(start, stop - 1, -1): | 2505 | for step in range(start, stop - 1, -1): |
| 728 | yield self.generate_otp_words(step) | 2506 | yield self.generate_otp_words(step) |
| 729 | 2507 | ||
| @@ -754,7 +2532,7 @@ class OTPGenerator: | |||
| 754 | # sha1 160bit -> 64bit folding | 2532 | # sha1 160bit -> 64bit folding |
| 755 | digest = self.sha1_digest_folding(large_digest) | 2533 | digest = self.sha1_digest_folding(large_digest) |
| 756 | else: | 2534 | else: |
| 757 | raise OTPGeneratorException( | 2535 | raise OTPGeneratorError( |
| 758 | f'{self._hash_algo} is not supported by this module' | 2536 | f'{self._hash_algo} is not supported by this module' |
| 759 | ) | 2537 | ) |
| 760 | return digest | 2538 | return digest |
diff --git a/src/otp2289/server.py b/src/otp2289/server.py index 4305f75..e5ee0f2 100644 --- a/src/otp2289/server.py +++ b/src/otp2289/server.py | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD | 1 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
| 3 | # | 2 | # |
| 4 | # Copyright (c) 2020-2023 Simeon Simeonov | 3 | # Copyright (c) 2020-2025 Simeon Simeonov |
| 5 | # All rights reserved. | 4 | # All rights reserved. |
| 6 | # | 5 | # |
| 7 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
| @@ -24,22 +23,23 @@ | |||
| 24 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 23 | # (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. | 24 | # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 | """A pure Python implementation of the RFC-2289 OTP server""" | 25 | """A pure Python implementation of the RFC-2289 OTP server""" |
| 26 | |||
| 27 | import binascii | 27 | import binascii |
| 28 | import hashlib | 28 | import hashlib |
| 29 | 29 | ||
| 30 | from .generator import OTP_ALGO_MD5, OTPGenerator, OTPGeneratorException | 30 | from .generator import OTP_ALGO_MD5, OTPGenerator, OTPGeneratorError |
| 31 | 31 | ||
| 32 | 32 | ||
| 33 | class OTPStateException(Exception): | 33 | class OTPStateError(Exception): |
| 34 | """OTPStateException class""" | 34 | """OTPStateError class""" |
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | class OTPStoreException(Exception): | 37 | class OTPStoreError(Exception): |
| 38 | """OTPStoreException class""" | 38 | """OTPStoreError class""" |
| 39 | 39 | ||
| 40 | 40 | ||
| 41 | class OTPInvalidResponse(Exception): | 41 | class OTPInvalidResponseError(Exception): |
| 42 | """OTPInvalidResponse class""" | 42 | """OTPInvalidResponseError class""" |
| 43 | 43 | ||
| 44 | 44 | ||
| 45 | class OTPState: | 45 | class OTPState: |
| @@ -52,11 +52,7 @@ class OTPState: | |||
| 52 | """ | 52 | """ |
| 53 | 53 | ||
| 54 | def __init__( | 54 | def __init__( |
| 55 | self, | 55 | self, ot_hex: str, current_step: int, seed: str, hash_algo=OTP_ALGO_MD5 |
| 56 | ot_hex: str, | ||
| 57 | current_step: int, | ||
| 58 | seed: str, | ||
| 59 | hash_algo=OTP_ALGO_MD5, | ||
| 60 | ): | 56 | ): |
| 61 | """ | 57 | """ |
| 62 | Constructs an OTPState object with the given arguments. | 58 | Constructs an OTPState object with the given arguments. |
| @@ -75,15 +71,15 @@ class OTPState: | |||
| 75 | :param hash_algo: The hash algo, defaults to OTP_ALGO_MD5 | 71 | :param hash_algo: The hash algo, defaults to OTP_ALGO_MD5 |
| 76 | :type hash_algo: int or str | 72 | :type hash_algo: int or str |
| 77 | 73 | ||
| 78 | :raises otp2289.OTPStateException: If the input does not validate | 74 | :raises otp2289.OTPStateError: If the input does not validate |
| 79 | """ | 75 | """ |
| 80 | # enforce the rfc2289 constraints | 76 | # enforce the rfc2289 constraints |
| 81 | try: | 77 | try: |
| 82 | self._seed = OTPGenerator.validate_seed(seed) | 78 | self._seed = OTPGenerator.validate_seed(seed) |
| 83 | self._hash_algo = OTPGenerator.validate_hash_algo(hash_algo) | 79 | self._hash_algo = OTPGenerator.validate_hash_algo(hash_algo) |
| 84 | self._step = OTPGenerator.validate_step(current_step) | 80 | self._step = OTPGenerator.validate_step(current_step) |
| 85 | except OTPGeneratorException as exp: | 81 | except OTPGeneratorError as exp: |
| 86 | raise OTPStateException(exp.args[0]) from None | 82 | raise OTPStateError(exp.args[0]) from None |
| 87 | self._current_digest = None | 83 | self._current_digest = None |
| 88 | if ot_hex is not None: | 84 | if ot_hex is not None: |
| 89 | self._current_digest = self.validate_hex(ot_hex) | 85 | self._current_digest = self.validate_hex(ot_hex) |
| @@ -157,28 +153,28 @@ class OTPState: | |||
| 157 | 153 | ||
| 158 | The method first checks if response is a token and tries to convert | 154 | The method first checks if response is a token and tries to convert |
| 159 | it to bytes. If that fails, the method assumes that response is a hex. | 155 | it to bytes. If that fails, the method assumes that response is a hex. |
| 160 | If neither of those attempts succeeds OTPInvalidResponse is raised. | 156 | If neither of those attempts succeeds OTPInvalidResponseError is raised |
| 161 | It is up to the caller to run another iteration and compare the result | 157 | It is up to the caller to run another iteration and compare the result |
| 162 | to an existing digest in this state. | 158 | to an existing digest in this state. |
| 163 | 159 | ||
| 164 | :param response: The response to this state (its challenge) | 160 | :param response: The response to this state (its challenge) |
| 165 | :type response: str | 161 | :type response: str |
| 166 | 162 | ||
| 167 | :raises otp2289.OTPInvalidResponse: If the response is corrupt/illegal, | 163 | :raises otp2289.OTPInvalidResponseError: If the response is |
| 168 | but not if it simply does not | 164 | corrupt/illegal, but not if it |
| 169 | validate | 165 | simply does not validate |
| 170 | 166 | ||
| 171 | :return: The bytes representation of response (if any) | 167 | :return: The bytes representation of response (if any) |
| 172 | :rtype: bytes | 168 | :rtype: bytes |
| 173 | """ | 169 | """ |
| 174 | try: | 170 | try: |
| 175 | return OTPGenerator.tokens_to_bytes(response) | 171 | return OTPGenerator.tokens_to_bytes(response) |
| 176 | except OTPGeneratorException: | 172 | except OTPGeneratorError: |
| 177 | # now assume hex... | 173 | # now assume hex... |
| 178 | try: | 174 | try: |
| 179 | return OTPState.validate_hex(response) | 175 | return OTPState.validate_hex(response) |
| 180 | except OTPStateException: | 176 | except OTPStateError: |
| 181 | raise OTPInvalidResponse( | 177 | raise OTPInvalidResponseError( |
| 182 | 'The response is neither a valid token or hex' | 178 | 'The response is neither a valid token or hex' |
| 183 | ) from None | 179 | ) from None |
| 184 | 180 | ||
| @@ -190,25 +186,25 @@ class OTPState: | |||
| 190 | :param ot_hex: The one-time hex to validate | 186 | :param ot_hex: The one-time hex to validate |
| 191 | :type ot_hex: str | 187 | :type ot_hex: str |
| 192 | 188 | ||
| 193 | :raises otp2289.OTPStateException: If hex does not validate | 189 | :raises otp2289.OTPStateError: If hex does not validate |
| 194 | 190 | ||
| 195 | :return: The validated hex (without leading 0x) converted to bytes | 191 | :return: The validated hex (without leading 0x) converted to bytes |
| 196 | :rtype: bytes | 192 | :rtype: bytes |
| 197 | """ | 193 | """ |
| 198 | if not isinstance(ot_hex, str): | 194 | if not isinstance(ot_hex, str): |
| 199 | raise OTPStateException('OT-hex must be a str') | 195 | raise OTPStateError('OT-hex must be a str') |
| 200 | if ot_hex.startswith('0x'): | 196 | if ot_hex.startswith('0x'): |
| 201 | ot_hex = ot_hex[2:] | 197 | ot_hex = ot_hex[2:] |
| 202 | ot_hex = ot_hex.strip().lower() | 198 | ot_hex = ot_hex.strip().lower() |
| 203 | if len(ot_hex) != 16: | 199 | if len(ot_hex) != 16: |
| 204 | raise OTPStateException( | 200 | raise OTPStateError( |
| 205 | 'The length of the hex should be 16 ' | 201 | 'The length of the hex should be 16 ' |
| 206 | '(representing 64 bits digest)' | 202 | '(representing 64 bits digest)' |
| 207 | ) | 203 | ) |
| 208 | try: | 204 | try: |
| 209 | return binascii.unhexlify(ot_hex) | 205 | return binascii.unhexlify(ot_hex) |
| 210 | except binascii.Error: | 206 | except binascii.Error: |
| 211 | raise OTPStateException('Invalid OT-hex') from None | 207 | raise OTPStateError('Invalid OT-hex') from None |
| 212 | 208 | ||
| 213 | def get_next_state(self): | 209 | def get_next_state(self): |
| 214 | """ | 210 | """ |
| @@ -223,16 +219,11 @@ class OTPState: | |||
| 223 | if self._new_digest_hex is None: | 219 | if self._new_digest_hex is None: |
| 224 | return None | 220 | return None |
| 225 | return OTPState( | 221 | return OTPState( |
| 226 | self._new_digest_hex, | 222 | self._new_digest_hex, self._step - 1, self._seed, self._hash_algo |
| 227 | self._step - 1, | ||
| 228 | self._seed, | ||
| 229 | self._hash_algo, | ||
| 230 | ) | 223 | ) |
| 231 | 224 | ||
| 232 | def response_validates( | 225 | def response_validates( |
| 233 | self, | 226 | self, response: str, store_valid_response: str = True |
| 234 | response: str, | ||
| 235 | store_valid_response: str = True, | ||
| 236 | ) -> bool: | 227 | ) -> bool: |
| 237 | """ | 228 | """ |
| 238 | Validates the incoming response as specified by RFC-2289. | 229 | Validates the incoming response as specified by RFC-2289. |
| @@ -243,14 +234,14 @@ class OTPState: | |||
| 243 | :param store_valid_response: Should a valid response be stored | 234 | :param store_valid_response: Should a valid response be stored |
| 244 | :type store_valid_response: bool | 235 | :type store_valid_response: bool |
| 245 | 236 | ||
| 246 | :raises otp2289.OTPInvalidResponse: If the response does not match | 237 | :raises otp2289.OTPInvalidResponseError: If the response does not match |
| 247 | this state | 238 | this state |
| 248 | 239 | ||
| 249 | :return: Returns True if response validates, False otherwise | 240 | :return: Returns True if response validates, False otherwise |
| 250 | :rtype: bool | 241 | :rtype: bool |
| 251 | """ | 242 | """ |
| 252 | # self.response_to_bytes raises OTPInvalidResponse in case response | 243 | # self.response_to_bytes raises OTPInvalidResponseError in case |
| 253 | # is corrupt or in a wrong format | 244 | # response is corrupt or in a wrong format |
| 254 | response_bytes = self.response_to_bytes(response) | 245 | response_bytes = self.response_to_bytes(response) |
| 255 | if self._hash_algo == 'md5': | 246 | if self._hash_algo == 'md5': |
| 256 | digest = hashlib.md5(response_bytes).digest() | 247 | digest = hashlib.md5(response_bytes).digest() |
| @@ -281,7 +272,7 @@ class OTPState: | |||
| 281 | return True | 272 | return True |
| 282 | return False | 273 | return False |
| 283 | # this should not happen since the hash_algo is validated by the caller | 274 | # this should not happen since the hash_algo is validated by the caller |
| 284 | raise OTPInvalidResponse(f'Ivalid hash_algo: {self._hash_algo}') | 275 | raise OTPInvalidResponseError(f'Ivalid hash_algo: {self._hash_algo}') |
| 285 | 276 | ||
| 286 | def to_dict(self) -> dict: | 277 | def to_dict(self) -> dict: |
| 287 | """ | 278 | """ |
| @@ -367,12 +358,12 @@ class OTPStore: | |||
| 367 | :param state: The OTPState object | 358 | :param state: The OTPState object |
| 368 | :type state: otp2289.OTPState | 359 | :type state: otp2289.OTPState |
| 369 | 360 | ||
| 370 | :raises otp2289.OTPStoreException: On failure | 361 | :raises otp2289.OTPStoreError: On failure |
| 371 | """ | 362 | """ |
| 372 | if not isinstance(key, str): | 363 | if not isinstance(key, str): |
| 373 | raise OTPStoreException('key must be a str') | 364 | raise OTPStoreError('key must be a str') |
| 374 | if not isinstance(state, OTPState): | 365 | if not isinstance(state, OTPState): |
| 375 | raise OTPStoreException('state must be an OTPState-object') | 366 | raise OTPStoreError('state must be an OTPState-object') |
| 376 | self._data[key] = state | 367 | self._data[key] = state |
| 377 | self._states[state] = key | 368 | self._states[state] = key |
| 378 | 369 | ||
| @@ -393,22 +384,19 @@ class OTPStore: | |||
| 393 | 384 | ||
| 394 | :raises KeyError: If key does not exist | 385 | :raises KeyError: If key does not exist |
| 395 | 386 | ||
| 396 | :raises otp2289.OTPStoreException: On failure | 387 | :raises otp2289.OTPStoreError: On failure |
| 397 | 388 | ||
| 398 | :return: The state corresponding to the key | 389 | :return: The state corresponding to the key |
| 399 | :rtype: otp2289.OTPState | 390 | :rtype: otp2289.OTPState |
| 400 | """ | 391 | """ |
| 401 | if not isinstance(key, str): | 392 | if not isinstance(key, str): |
| 402 | raise OTPStoreException('key must be a str') | 393 | raise OTPStoreError('key must be a str') |
| 403 | state = self._data.pop(key) | 394 | state = self._data.pop(key) |
| 404 | self._states.pop(state) | 395 | self._states.pop(state) |
| 405 | return state | 396 | return state |
| 406 | 397 | ||
| 407 | def response_validates( | 398 | def response_validates( |
| 408 | self, | 399 | self, key: str, response: str, store_valid_response: bool = True |
| 409 | key: str, | ||
| 410 | response: str, | ||
| 411 | store_valid_response: bool = True, | ||
| 412 | ) -> bool: | 400 | ) -> bool: |
| 413 | """ | 401 | """ |
| 414 | A method that wraps around OTPState.response_validates and | 402 | A method that wraps around OTPState.response_validates and |
| @@ -429,8 +417,8 @@ class OTPStore: | |||
| 429 | 417 | ||
| 430 | :raises KeyError: If the key is not present | 418 | :raises KeyError: If the key is not present |
| 431 | 419 | ||
| 432 | :raises otp2289.OTPInvalidResponse: If the response does not match | 420 | :raises otp2289.OTPInvalidResponseError: If the response does not match |
| 433 | this state | 421 | this state |
| 434 | 422 | ||
| 435 | :return: Returns True if response validates, False otherwise | 423 | :return: Returns True if response validates, False otherwise |
| 436 | :rtype: bool | 424 | :rtype: bool |
diff --git a/test/test_generator.py b/test/test_generator.py index b4bb961..4329ae4 100644 --- a/test/test_generator.py +++ b/test/test_generator.py | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD | 1 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
| 3 | # | 2 | # |
| 4 | # Copyright (c) 2020-2023, Simeon Simeonov | 3 | # Copyright (c) 2020-2025, Simeon Simeonov |
| 5 | # All rights reserved. | 4 | # All rights reserved. |
| 6 | # | 5 | # |
| 7 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
| @@ -36,25 +35,25 @@ def test_caller_exceptions(): | |||
| 36 | 'TeSt', | 35 | 'TeSt', |
| 37 | otp2289.OTP_ALGO_MD5, | 36 | otp2289.OTP_ALGO_MD5, |
| 38 | ) | 37 | ) |
| 39 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 38 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 40 | gen.generate_otp_words('3') | 39 | gen.generate_otp_words('3') |
| 41 | assert exc_info.type is otp2289.OTPGeneratorException | 40 | assert exc_info.type is otp2289.OTPGeneratorError |
| 42 | assert exc_info.value.args[0] == 'Step value MUST be an int' | 41 | assert exc_info.value.args[0] == 'Step value MUST be an int' |
| 43 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 42 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 44 | gen.generate_otp_hexdigest(-1) | 43 | gen.generate_otp_hexdigest(-1) |
| 45 | assert exc_info.type is otp2289.OTPGeneratorException | 44 | assert exc_info.type is otp2289.OTPGeneratorError |
| 46 | assert exc_info.value.args[0] == 'Step value MUST be >= 0' | 45 | assert exc_info.value.args[0] == 'Step value MUST be >= 0' |
| 47 | with pytest.raises(otp2289.OTPChallengeException) as exc_info: | 46 | with pytest.raises(otp2289.OTPChallengeError) as exc_info: |
| 48 | gen.generate_otp_hexdigest_from_challenge(b'md5 fbd TeSt') | 47 | gen.generate_otp_hexdigest_from_challenge(b'md5 fbd TeSt') |
| 49 | assert exc_info.type is otp2289.OTPChallengeException | 48 | assert exc_info.type is otp2289.OTPChallengeError |
| 50 | assert exc_info.value.args[0] == 'Challenge must be str' | 49 | assert exc_info.value.args[0] == 'Challenge must be str' |
| 51 | with pytest.raises(otp2289.OTPChallengeException) as exc_info: | 50 | with pytest.raises(otp2289.OTPChallengeError) as exc_info: |
| 52 | gen.generate_otp_hexdigest_from_challenge('md5 fbd TeSt') | 51 | gen.generate_otp_hexdigest_from_challenge('md5 fbd TeSt') |
| 53 | assert exc_info.type is otp2289.OTPChallengeException | 52 | assert exc_info.type is otp2289.OTPChallengeError |
| 54 | assert exc_info.value.args[0] == 'Invalid challenge' | 53 | assert exc_info.value.args[0] == 'Invalid challenge' |
| 55 | with pytest.raises(otp2289.generator.OTPChallengeException) as exc_info: | 54 | with pytest.raises(otp2289.generator.OTPChallengeError) as exc_info: |
| 56 | gen.generate_otp_hexdigest_from_challenge('otp-md5 fbd TeSt') | 55 | gen.generate_otp_hexdigest_from_challenge('otp-md5 fbd TeSt') |
| 57 | assert exc_info.type is otp2289.generator.OTPChallengeException | 56 | assert exc_info.type is otp2289.generator.OTPChallengeError |
| 58 | assert exc_info.value.args[0] == 'Invalid challenge' | 57 | assert exc_info.value.args[0] == 'Invalid challenge' |
| 59 | 58 | ||
| 60 | 59 | ||
| @@ -63,74 +62,74 @@ def test_constructor_exceptions(): | |||
| 63 | Tests the exceptions when initializing a new object (in the constructor) | 62 | Tests the exceptions when initializing a new object (in the constructor) |
| 64 | """ | 63 | """ |
| 65 | # test the otp2289.OTPGenerator __init__ and validators | 64 | # test the otp2289.OTPGenerator __init__ and validators |
| 66 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 65 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 67 | otp2289.OTPGenerator( | 66 | otp2289.OTPGenerator( |
| 68 | 'This is a test.'.encode(), | 67 | 'This is a test.'.encode(), |
| 69 | 'TeStø'.encode(), | 68 | 'TeStø'.encode(), |
| 70 | otp2289.OTP_ALGO_MD5, | 69 | otp2289.OTP_ALGO_MD5, |
| 71 | ) | 70 | ) |
| 72 | assert exc_info.type is otp2289.OTPGeneratorException | 71 | assert exc_info.type is otp2289.OTPGeneratorError |
| 73 | assert exc_info.value.args[0] == 'Seed must be a string' | 72 | assert exc_info.value.args[0] == 'Seed must be a string' |
| 74 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 73 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 75 | otp2289.OTPGenerator( | 74 | otp2289.OTPGenerator( |
| 76 | 'This is a test.'.encode(), | 75 | 'This is a test.'.encode(), |
| 77 | 'TeStøtEsTteSTteStTest', | 76 | 'TeStøtEsTteSTteStTest', |
| 78 | otp2289.OTP_ALGO_SHA1, | 77 | otp2289.OTP_ALGO_SHA1, |
| 79 | ) | 78 | ) |
| 80 | assert exc_info.type is otp2289.OTPGeneratorException | 79 | assert exc_info.type is otp2289.OTPGeneratorError |
| 81 | assert exc_info.value.args[0] == ( | 80 | assert exc_info.value.args[0] == ( |
| 82 | 'The seed MUST be of 1 to 16 characters in length' | 81 | 'The seed MUST be of 1 to 16 characters in length' |
| 83 | ) | 82 | ) |
| 84 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 83 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 85 | otp2289.OTPGenerator( | 84 | otp2289.OTPGenerator( |
| 86 | 'This is a test.'.encode(), | 85 | 'This is a test.'.encode(), |
| 87 | 'TeStø', | 86 | 'TeStø', |
| 88 | otp2289.OTP_ALGO_SHA1, | 87 | otp2289.OTP_ALGO_SHA1, |
| 89 | ) | 88 | ) |
| 90 | assert exc_info.type is otp2289.OTPGeneratorException | 89 | assert exc_info.type is otp2289.OTPGeneratorError |
| 91 | assert exc_info.value.args[0] == ( | 90 | assert exc_info.value.args[0] == ( |
| 92 | 'The seed MUST consist of purely alphanumeric characters' | 91 | 'The seed MUST consist of purely alphanumeric characters' |
| 93 | ) | 92 | ) |
| 94 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 93 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 95 | otp2289.OTPGenerator( | 94 | otp2289.OTPGenerator( |
| 96 | 'This is a test.'.encode(), | 95 | 'This is a test.'.encode(), |
| 97 | 'TeSt', | 96 | 'TeSt', |
| 98 | 9, | 97 | 9, |
| 99 | ) | 98 | ) |
| 100 | assert exc_info.type is otp2289.OTPGeneratorException | 99 | assert exc_info.type is otp2289.OTPGeneratorError |
| 101 | assert exc_info.value.args[0] == ( | 100 | assert exc_info.value.args[0] == ( |
| 102 | 'hash_algo is not among the known algorithms' | 101 | 'hash_algo is not among the known algorithms' |
| 103 | ) | 102 | ) |
| 104 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 103 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 105 | otp2289.OTPGenerator( | 104 | otp2289.OTPGenerator( |
| 106 | 'This is a test.'.encode(), | 105 | 'This is a test.'.encode(), |
| 107 | 'TeSt', | 106 | 'TeSt', |
| 108 | b'md5', | 107 | b'md5', |
| 109 | ) | 108 | ) |
| 110 | assert exc_info.type is otp2289.OTPGeneratorException | 109 | assert exc_info.type is otp2289.OTPGeneratorError |
| 111 | assert exc_info.value.args[0] == 'hash_algo must be an int or a str' | 110 | assert exc_info.value.args[0] == 'hash_algo must be an int or a str' |
| 112 | # test the package structure as well | 111 | # test the package structure as well |
| 113 | with pytest.raises(otp2289.generator.OTPGeneratorException) as exc_info: | 112 | with pytest.raises(otp2289.generator.OTPGeneratorError) as exc_info: |
| 114 | otp2289.generator.OTPGenerator( | 113 | otp2289.generator.OTPGenerator( |
| 115 | 'This is a test.'.encode(), | 114 | 'This is a test.'.encode(), |
| 116 | 'TeSt', | 115 | 'TeSt', |
| 117 | 'foo', | 116 | 'foo', |
| 118 | ) | 117 | ) |
| 119 | assert exc_info.type is otp2289.generator.OTPGeneratorException | 118 | assert exc_info.type is otp2289.generator.OTPGeneratorError |
| 120 | assert exc_info.value.args[0] == ( | 119 | assert exc_info.value.args[0] == ( |
| 121 | 'foo is not supported by this version of the hashlib module' | 120 | 'foo is not supported by this version of the hashlib module' |
| 122 | ) | 121 | ) |
| 123 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 122 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 124 | otp2289.OTPGenerator('1234567', 'TeSt', otp2289.OTP_ALGO_MD5) | 123 | otp2289.OTPGenerator('1234567', 'TeSt', otp2289.OTP_ALGO_MD5) |
| 125 | assert exc_info.type is otp2289.OTPGeneratorException | 124 | assert exc_info.type is otp2289.OTPGeneratorError |
| 126 | assert exc_info.value.args[0] == 'Password must be a byte-string' | 125 | assert exc_info.value.args[0] == 'Password must be a byte-string' |
| 127 | with pytest.raises(otp2289.OTPGeneratorException) as exc_info: | 126 | with pytest.raises(otp2289.OTPGeneratorError) as exc_info: |
| 128 | otp2289.OTPGenerator( | 127 | otp2289.OTPGenerator( |
| 129 | '1234567'.encode(), | 128 | '1234567'.encode(), |
| 130 | 'TeSt', | 129 | 'TeSt', |
| 131 | otp2289.OTP_ALGO_MD5, | 130 | otp2289.OTP_ALGO_MD5, |
| 132 | ) | 131 | ) |
| 133 | assert exc_info.type is otp2289.OTPGeneratorException | 132 | assert exc_info.type is otp2289.OTPGeneratorError |
| 134 | assert exc_info.value.args[0] == 'Password must be longer than 10 bytes' | 133 | assert exc_info.value.args[0] == 'Password must be longer than 10 bytes' |
| 135 | 134 | ||
| 136 | 135 | ||
diff --git a/test/test_main.py b/test/test_main.py index 35bd2a2..593bf80 100644 --- a/test/test_main.py +++ b/test/test_main.py | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD | 1 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
| 3 | # | 2 | # |
| 4 | # Copyright (c) 2020-2023, Simeon Simeonov | 3 | # Copyright (c) 2020-2025, Simeon Simeonov |
| 5 | # All rights reserved. | 4 | # All rights reserved. |
| 6 | # | 5 | # |
| 7 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
diff --git a/test/test_server.py b/test/test_server.py index 64e7f67..e81532f 100644 --- a/test/test_server.py +++ b/test/test_server.py | |||
| @@ -1,7 +1,6 @@ | |||
| 1 | # -*- coding: utf-8 -*- | ||
| 2 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD | 1 | # SPDX-License-Identifier: BSD-2-Clause-FreeBSD |
| 3 | # | 2 | # |
| 4 | # Copyright (c) 2020-2023, Simeon Simeonov | 3 | # Copyright (c) 2020-2025, Simeon Simeonov |
| 5 | # All rights reserved. | 4 | # All rights reserved. |
| 6 | # | 5 | # |
| 7 | # Redistribution and use in source and binary forms, with or without | 6 | # Redistribution and use in source and binary forms, with or without |
| @@ -39,9 +38,9 @@ def test_state_caller_exceptions(): | |||
| 39 | 'TeSt', | 38 | 'TeSt', |
| 40 | otp2289.OTP_ALGO_MD5, | 39 | otp2289.OTP_ALGO_MD5, |
| 41 | ) | 40 | ) |
| 42 | with pytest.raises(otp2289.OTPInvalidResponse) as exc_info: | 41 | with pytest.raises(otp2289.OTPInvalidResponseError) as exc_info: |
| 43 | state.response_validates('bla') | 42 | state.response_validates('bla') |
| 44 | assert exc_info.type is otp2289.OTPInvalidResponse | 43 | assert exc_info.type is otp2289.OTPInvalidResponseError |
| 45 | assert exc_info.value.args[0] == ( | 44 | assert exc_info.value.args[0] == ( |
| 46 | 'The response is neither a valid token or hex' | 45 | 'The response is neither a valid token or hex' |
| 47 | ) | 46 | ) |
| @@ -49,23 +48,23 @@ def test_state_caller_exceptions(): | |||
| 49 | 48 | ||
| 50 | def test_state_constructor_exceptions(): | 49 | def test_state_constructor_exceptions(): |
| 51 | """Tests the exceptions when initializing new OTPState objects""" | 50 | """Tests the exceptions when initializing new OTPState objects""" |
| 52 | with pytest.raises(otp2289.OTPStateException) as exc_info: | 51 | with pytest.raises(otp2289.OTPStateError) as exc_info: |
| 53 | otp2289.OTPState( | 52 | otp2289.OTPState( |
| 54 | '0x7965e05436f5029t', | 53 | '0x7965e05436f5029t', |
| 55 | 1, | 54 | 1, |
| 56 | 'TeStø'.encode(), | 55 | 'TeStø'.encode(), |
| 57 | otp2289.OTP_ALGO_MD5, | 56 | otp2289.OTP_ALGO_MD5, |
| 58 | ) | 57 | ) |
| 59 | assert exc_info.type is otp2289.OTPStateException | 58 | assert exc_info.type is otp2289.OTPStateError |
| 60 | assert exc_info.value.args[0] == 'Seed must be a string' | 59 | assert exc_info.value.args[0] == 'Seed must be a string' |
| 61 | with pytest.raises(otp2289.OTPStateException) as exc_info: | 60 | with pytest.raises(otp2289.OTPStateError) as exc_info: |
| 62 | otp2289.OTPState( | 61 | otp2289.OTPState( |
| 63 | '0x7965e05436f5029t', | 62 | '0x7965e05436f5029t', |
| 64 | '1', | 63 | '1', |
| 65 | 'TeSt', | 64 | 'TeSt', |
| 66 | otp2289.OTP_ALGO_MD5, | 65 | otp2289.OTP_ALGO_MD5, |
| 67 | ) | 66 | ) |
| 68 | assert exc_info.type is otp2289.OTPStateException | 67 | assert exc_info.type is otp2289.OTPStateError |
| 69 | assert exc_info.value.args[0] == 'Step value MUST be an int' | 68 | assert exc_info.value.args[0] == 'Step value MUST be an int' |
| 70 | 69 | ||
| 71 | 70 | ||
