1
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
# See LICENSE for details.
4
""" A One-Time Password System based on RFC 2289
6
The class Authenticator contains the hashing-logic, and the parser for the
7
readable output. It also contains challenge which returns a string describing
8
the authentication scheme for a client.
10
OTP is a password container for an user on a server.
12
NOTE: Does not take care of transmitting the shared secret password.
14
At the end there's a dict called dict which is dictionary contain 2048
15
words for storing pronouncable 11-bit values. Taken from RFC 1760.
17
Uses the MD5- and SHA-algorithms for hashing
19
Todo: RFC2444, SASL (perhaps), parsing hex-responses
26
""" Convert digest to long """
29
result = (256 * result) + ord(byte)
32
def stringToDWords(s):
33
""" Convert digest to a list of four 32-bits words """
35
for a in xrange(len(s) / 4):
38
tmp = (256 * tmp) + ord(byte)
44
""" Convert long to digest """
47
result = chr(l % 256) + result
52
hashid = {md5: 'md5', sha: 'sha1'}
54
INITIALSEQUENCE = 1000
57
class Unauthorized(Exception):
58
"""the Unauthorized exception
60
This exception is raised when an action is not allowed, or a user is not
61
authenticated properly.
64
class OTPAuthenticator:
65
"""A One Time Password System
67
Based on RFC 2289, which is based on a the S/KEY Authentication-scheme.
68
It uses the MD5- and SHA-algorithms for hashing
70
The variable OTP is at all times a 64bit string"""
72
def __init__(self, hash = md5):
73
"Set the hash to either md5 or sha1"
77
def generateSeed(self):
78
"Return a 10 char random seed, with 6 lowercase chars and 4 digits"
81
seed = seed + chr(random.randrange(97,122))
83
seed = seed + chr(random.randrange(48,57))
86
def foldDigest(self, otp):
88
return self.foldDigest128(otp)
90
return self.foldDigest160(otp)
92
def foldDigest128(self, otp128):
93
"Fold a 128 bit digest to 64 bit"
94
regs = stringToDWords(otp128)
95
p0 = regs[0] ^ regs[2]
96
p1 = regs[1] ^ regs[3]
99
S = chr(p0 & 0xFF) + S
102
S = chr(p1 & 0xFF) + S
106
def foldDigest160(self, otp160):
107
"Fold a 160 bit digest to 64 bit"
108
regs = stringToDWords(otp160)
109
p0 = regs[0] ^ regs[2]
110
p1 = regs[1] ^ regs[3]
111
p0 = regs[0] ^ regs[4]
114
S = chr(p0 & 0xFF) + S
117
S = chr(p1 & 0xFF) + S
121
def hashUpdate(self, digest):
122
"Run through the hash and fold to 64 bit"
123
h = self.hash.new(digest)
124
return self.foldDigest(h.digest())
126
def generateOTP(self, seed, passwd, sequence):
127
"""Return a 64 bit OTP based on inputs
128
Run through makeReadable to get a 6 word pass-phrase"""
129
seed = string.lower(seed)
130
otp = self.hashUpdate(seed + passwd)
131
for a in xrange(sequence):
132
otp = self.hashUpdate(otp)
135
def calculateParity(self, otp):
136
"Calculate the parity from a 64bit OTP"
138
for i in xrange(0, 64, 2):
139
parity = parity + otp & 0x3
143
def makeReadable(self, otp):
144
"Returns a 6 word pass-phrase from a 64bit OTP"
145
digest = stringToLong(otp)
147
parity = self.calculateParity(digest)
148
for i in xrange(4,-1, -1):
149
list.append(dict[(digest >> (i * 11 + 9)) & 0x7FF])
150
list.append(dict[(digest << 2) & 0x7FC | (parity & 0x03)])
151
return string.join(list)
153
def challenge(self, seed, sequence):
154
"""Return a challenge in the format otp-<hash> <sequence> <seed>"""
155
return "otp-%s %i %s" % (hashid[self.hash], sequence, seed)
157
def parsePhrase(self, phrase):
158
"""Decode the phrase, and return a 64bit OTP
159
I will raise Unauthorized if the parity is wrong
160
TODO: Add support for hex (MUST) and the '2nd scheme'(SHOULD)"""
161
words = string.split(phrase)
162
for i in xrange(len(words)):
163
words[i] = string.upper(words[i])
165
for i in xrange(0,5):
166
b = b | ((long(dict.index(words[i])) << ((4-i)*11L+9L)))
167
tmp = dict.index(words[5])
168
b = b | (tmp & 0x7FC ) >> 2
169
if (tmp & 3) <> self.calculateParity(b):
170
raise Unauthorized("Parity error")
171
digest = longToString(b)
174
class OTP(OTPAuthenticator):
175
"""An automatic version of the OTP-Authenticator
177
Updates the sequence and the keeps last approved password on success
178
On the next authentication, the stored password is hashed and checked
179
up against the one given by the user. If they match, the sequencecounter
180
is decreased and the circle is closed.
182
This object should be glued to each user
185
It does NOT reset the sequence when the combinations left approach zero,
186
This has to be done manuelly by instancing a new object
192
def __init__(self, passwd, sequence = INITIALSEQUENCE, hash=md5):
193
"""Initialize the OTP-Sequence, and discard the password"""
194
OTPAuthenticator.__init__(self, hash)
195
seed = self.generateSeed()
196
# Generate the 'last' password
197
self.lastotp = OTPAuthenticator.generateOTP(self, seed, passwd, sequence+1)
199
self.sequence = sequence
202
"""Return a challenge string"""
203
result = OTPAuthenticator.challenge(self, self.seed, self.sequence)
206
def authenticate(self, phrase):
207
"""Test the phrase against the last challenge issued"""
209
digest = self.parsePhrase(phrase)
210
hasheddigest = self.hashUpdate(digest)
211
if (self.lastotp == hasheddigest):
212
self.lastotp = digest
213
if self.sequence > MINIMUMSEQUENCE:
214
self.sequence = self.sequence - 1
217
raise Unauthorized("Failed")
218
except Unauthorized, msg:
219
raise Unauthorized(msg)
222
# The 2048 word standard dictionary from RFC 1760
224
dict = ["A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
225
"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY",
226
"AN", "ANA", "AND", "ANN", "ANT", "ANY", "APE", "APS",
227
"APT", "ARC", "ARE", "ARK", "ARM", "ART", "AS", "ASH",
228
"ASK", "AT", "ATE", "AUG", "AUK", "AVE", "AWE", "AWK",
229
"AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
230
"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG",
231
"BEN", "BET", "BEY", "BIB", "BID", "BIG", "BIN", "BIT",
232
"BOB", "BOG", "BON", "BOO", "BOP", "BOW", "BOY", "BUB",
233
"BUD", "BUG", "BUM", "BUN", "BUS", "BUT", "BUY", "BY",
234
"BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
235
"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT",
236
"COW", "COY", "CRY", "CUB", "CUE", "CUP", "CUR", "CUT",
237
"DAB", "DAD", "DAM", "DAN", "DAR", "DAY", "DEE", "DEL",
238
"DEN", "DES", "DEW", "DID", "DIE", "DIG", "DIN", "DIP",
239
"DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
240
"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL",
241
"EGG", "EGO", "ELI", "ELK", "ELM", "ELY", "EM", "END",
242
"EST", "ETC", "EVA", "EVE", "EWE", "EYE", "FAD", "FAN",
243
"FAR", "FAT", "FAY", "FED", "FEE", "FEW", "FIB", "FIG",
244
"FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
245
"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL",
246
"GAM", "GAP", "GAS", "GAY", "GEE", "GEL", "GEM", "GET",
247
"GIG", "GIL", "GIN", "GO", "GOT", "GUM", "GUN", "GUS",
248
"GUT", "GUY", "GYM", "GYP", "HA", "HAD", "HAL", "HAM",
249
"HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
250
"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP",
251
"HIS", "HIT", "HO", "HOB", "HOC", "HOE", "HOG", "HOP",
252
"HOT", "HOW", "HUB", "HUE", "HUG", "HUH", "HUM", "HUT",
253
"I", "ICY", "IDA", "IF", "IKE", "ILL", "INK", "INN",
254
"IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT",
255
"ITS", "IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW",
256
"JAY", "JET", "JIG", "JIM", "JO", "JOB", "JOE", "JOG",
257
"JOT", "JOY", "JUG", "JUT", "KAY", "KEG", "KEN", "KEY",
258
"KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC", "LAD",
259
"LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE",
260
"LEG", "LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN",
261
"LIP", "LIT", "LO", "LOB", "LOG", "LOP", "LOS", "LOT",
262
"LOU", "LOW", "LOY", "LUG", "LYE", "MA", "MAC", "MAD",
263
"MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY", "ME",
264
"MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT",
265
"MOB", "MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW",
266
"MUD", "MUG", "MUM", "MY", "NAB", "NAG", "NAN", "NAP",
267
"NAT", "NAY", "NE", "NED", "NEE", "NET", "NEW", "NIB",
268
"NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON", "NOR",
269
"NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF",
270
"OAK", "OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT",
271
"OH", "OIL", "OK", "OLD", "ON", "ONE", "OR", "ORB",
272
"ORE", "ORR", "OS", "OTT", "OUR", "OUT", "OVA", "OW",
273
"OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL", "PAM",
274
"PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG",
275
"PEN", "PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE",
276
"PIN", "PIT", "PLY", "PO", "POD", "POE", "POP", "POT",
277
"POW", "PRO", "PRY", "PUB", "PUG", "PUN", "PUP", "PUT",
278
"QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW", "RAY",
279
"REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM",
280
"RIO", "RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW",
281
"ROY", "RUB", "RUE", "RUG", "RUM", "RUN", "RYE", "SAC",
282
"SAD", "SAG", "SAL", "SAM", "SAN", "SAP", "SAT", "SAW",
283
"SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW", "SHE",
284
"SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY",
285
"SLY", "SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY",
286
"SPA", "SPY", "SUB", "SUD", "SUE", "SUM", "SUN", "SUP",
287
"TAB", "TAD", "TAG", "TAN", "TAP", "TAR", "TEA", "TED",
288
"TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM", "TIN",
289
"TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP",
290
"TOW", "TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO",
291
"UN", "UP", "US", "USE", "VAN", "VAT", "VET", "VIE",
292
"WAD", "WAG", "WAR", "WAS", "WAY", "WE", "WEB", "WED",
293
"WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK", "WON",
294
"WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE",
295
"YEA", "YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE",
296
"ABUT", "ACHE", "ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM",
297
"ADDS", "ADEN", "AFAR", "AFRO", "AGEE", "AHEM", "AHOY", "AIDA",
298
"AIDE", "AIDS", "AIRY", "AJAR", "AKIN", "ALAN", "ALEC", "ALGA",
299
"ALIA", "ALLY", "ALMA", "ALOE", "ALSO", "ALTO", "ALUM", "ALVA",
300
"AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS", "AMRA", "ANDY",
301
"ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB", "ARCH",
302
"AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS",
303
"ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON",
304
"AVOW", "AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE",
305
"BAIL", "BAIT", "BAKE", "BALD", "BALE", "BALI", "BALK", "BALL",
306
"BALM", "BAND", "BANE", "BANG", "BANK", "BARB", "BARD", "BARE",
307
"BARK", "BARN", "BARR", "BASE", "BASH", "BASK", "BASS", "BATE",
308
"BATH", "BAWD", "BAWL", "BEAD", "BEAK", "BEAM", "BEAN", "BEAR",
309
"BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER", "BEET", "BELA",
310
"BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT", "BESS",
311
"BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE",
312
"BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB",
313
"BLAT", "BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE",
314
"BLUM", "BLUR", "BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY",
315
"BOGY", "BOHR", "BOIL", "BOLD", "BOLO", "BOLT", "BOMB", "BONA",
316
"BOND", "BONE", "BONG", "BONN", "BONY", "BOOK", "BOOM", "BOON",
317
"BOOT", "BORE", "BORG", "BORN", "BOSE", "BOSS", "BOTH", "BOUT",
318
"BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN", "BRAY", "BRED",
319
"BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF", "BULB",
320
"BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN",
321
"BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE",
322
"CADY", "CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM",
323
"CAME", "CANE", "CANT", "CARD", "CARE", "CARL", "CARR", "CART",
324
"CASE", "CASH", "CASK", "CAST", "CAVE", "CEIL", "CELL", "CENT",
325
"CERN", "CHAD", "CHAR", "CHAT", "CHAW", "CHEF", "CHEN", "CHEW",
326
"CHIC", "CHIN", "CHOU", "CHOW", "CHUB", "CHUG", "CHUM", "CITE",
327
"CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY", "CLOD", "CLOG",
328
"CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK", "COCO",
329
"CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA",
330
"COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON",
331
"COOT", "CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL",
332
"CRAB", "CRAG", "CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD",
333
"CUBA", "CUBE", "CUFF", "CULL", "CULT", "CUNY", "CURB", "CURD",
334
"CURE", "CURL", "CURT", "CUTS", "DADE", "DALE", "DAME", "DANA",
335
"DANE", "DANG", "DANK", "DARE", "DARK", "DARN", "DART", "DASH",
336
"DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS", "DEAD", "DEAF",
337
"DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM", "DEER",
338
"DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE",
339
"DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT",
340
"DISC", "DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL",
341
"DOLT", "DOME", "DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE",
342
"DOUG", "DOUR", "DOVE", "DOWN", "DRAB", "DRAG", "DRAM", "DRAW",
343
"DREW", "DRUB", "DRUG", "DRUM", "DUAL", "DUCK", "DUCT", "DUEL",
344
"DUET", "DUKE", "DULL", "DUMB", "DUNE", "DUNK", "DUSK", "DUST",
345
"DUTY", "EACH", "EARL", "EARN", "EASE", "EAST", "EASY", "EBEN",
346
"ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA", "EGAN",
347
"ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS",
348
"ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT",
349
"FADE", "FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG",
350
"FARM", "FAST", "FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL",
351
"FEET", "FELL", "FELT", "FEND", "FERN", "FEST", "FEUD", "FIEF",
352
"FIGS", "FILE", "FILL", "FILM", "FIND", "FINE", "FINK", "FIRE",
353
"FIRM", "FISH", "FISK", "FIST", "FITS", "FIVE", "FLAG", "FLAK",
354
"FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW", "FLIT", "FLOC",
355
"FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY", "FOIL",
356
"FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD",
357
"FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL",
358
"FRAU", "FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM",
359
"FUEL", "FULL", "FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS",
360
"GAFF", "GAGE", "GAIL", "GAIN", "GAIT", "GALA", "GALE", "GALL",
361
"GALT", "GAME", "GANG", "GARB", "GARY", "GASH", "GATE", "GAUL",
362
"GAUR", "GAVE", "GAWK", "GEAR", "GELD", "GENE", "GENT", "GERM",
363
"GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT", "GINA", "GIRD",
364
"GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB", "GLOB",
365
"GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT",
366
"GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF",
367
"GORE", "GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY",
368
"GREG", "GREW", "GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW",
369
"GRUB", "GULF", "GULL", "GUNK", "GURU", "GUSH", "GUST", "GWEN",
370
"GWYN", "HAAG", "HAAS", "HACK", "HAIL", "HAIR", "HALE", "HALF",
371
"HALL", "HALO", "HALT", "HAND", "HANG", "HANK", "HANS", "HARD",
372
"HARK", "HARM", "HART", "HASH", "HAST", "HATE", "HATH", "HAUL",
373
"HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT", "HEBE",
374
"HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB",
375
"HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE",
376
"HIGH", "HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS",
377
"HIVE", "HOBO", "HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT",
378
"HOME", "HONE", "HONK", "HOOD", "HOOF", "HOOK", "HOOT", "HORN",
379
"HOSE", "HOST", "HOUR", "HOVE", "HOWE", "HOWL", "HOYT", "HUCK",
380
"HUED", "HUFF", "HUGE", "HUGH", "HUGO", "HULK", "HULL", "HUNK",
381
"HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE", "HYMN", "IBIS",
382
"ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO", "IONS",
383
"IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM",
384
"IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN",
385
"JEFF", "JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE",
386
"JOAN", "JOBS", "JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE",
387
"JOLT", "JOVE", "JUDD", "JUDE", "JUDO", "JUDY", "JUJU", "JUKE",
388
"JULY", "JUNE", "JUNK", "JUNO", "JURY", "JUST", "JUTE", "KAHN",
389
"KALE", "KANE", "KANT", "KARL", "KATE", "KEEL", "KEEN", "KENO",
390
"KENT", "KERN", "KERR", "KEYS", "KICK", "KILL", "KIND", "KING",
391
"KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT", "KNOB",
392
"KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE",
393
"LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE",
394
"LAMB", "LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS",
395
"LAST", "LATE", "LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD",
396
"LEAF", "LEAK", "LEAN", "LEAR", "LEEK", "LEER", "LEFT", "LEND",
397
"LENS", "LENT", "LEON", "LESK", "LESS", "LEST", "LETS", "LIAR",
398
"LICE", "LICK", "LIED", "LIEN", "LIES", "LIEU", "LIFE", "LIFT",
399
"LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB", "LIME", "LIND",
400
"LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE", "LOAD",
401
"LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA",
402
"LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE",
403
"LOSS", "LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE",
404
"LUKE", "LULU", "LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH",
405
"LUST", "LYLE", "LYNN", "LYON", "LYRA", "MACE", "MADE", "MAGI",
406
"MAID", "MAIL", "MAIN", "MAKE", "MALE", "MALI", "MALL", "MALT",
407
"MANA", "MANN", "MANY", "MARC", "MARE", "MARK", "MARS", "MART",
408
"MARY", "MASH", "MASK", "MASS", "MAST", "MATE", "MATH", "MAUL",
409
"MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET", "MELD",
410
"MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE",
411
"MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND",
412
"MINE", "MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE",
413
"MITT", "MOAN", "MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL",
414
"MOLT", "MONA", "MONK", "MONT", "MOOD", "MOON", "MOOR", "MOOT",
415
"MORE", "MORN", "MORT", "MOSS", "MOST", "MOTH", "MOVE", "MUCH",
416
"MUCK", "MUDD", "MUFF", "MULE", "MULL", "MURK", "MUSH", "MUST",
417
"MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL", "NAIR", "NAME",
418
"NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT", "NECK",
419
"NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS",
420
"NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH",
421
"NODE", "NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE",
422
"NOTE", "NOUN", "NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY",
423
"OBOE", "ODIN", "OHIO", "OILY", "OINT", "OKAY", "OLAF", "OLDY",
424
"OLGA", "OLIN", "OMAN", "OMEN", "OMIT", "ONCE", "ONES", "ONLY",
425
"ONTO", "ONUS", "ORAL", "ORGY", "OSLO", "OTIS", "OTTO", "OUCH",
426
"OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY", "OWNS", "QUAD",
427
"QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE", "RAID",
428
"RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE",
429
"RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED",
430
"REEF", "REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT",
431
"REST", "RICE", "RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME",
432
"RING", "RINK", "RISE", "RISK", "RITE", "ROAD", "ROAM", "ROAR",
433
"ROBE", "ROCK", "RODE", "ROIL", "ROLL", "ROME", "ROOD", "ROOF",
434
"ROOK", "ROOM", "ROOT", "ROSA", "ROSE", "ROSS", "ROSY", "ROTH",
435
"ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY", "RUDE", "RUDY",
436
"RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH", "RUSK",
437
"RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL",
438
"SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK",
439
"SARA", "SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT",
440
"SEAL", "SEAM", "SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN",
441
"SEES", "SELF", "SELL", "SEND", "SENT", "SETS", "SEWN", "SHAG",
442
"SHAM", "SHAW", "SHAY", "SHED", "SHIM", "SHIN", "SHOD", "SHOE",
443
"SHOT", "SHOW", "SHUN", "SHUT", "SICK", "SIDE", "SIFT", "SIGH",
444
"SIGN", "SILK", "SILL", "SILO", "SILT", "SINE", "SING", "SINK",
445
"SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID", "SKIM",
446
"SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW",
447
"SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG",
448
"SLUM", "SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB",
449
"SNUG", "SOAK", "SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL",
450
"SOLD", "SOME", "SONG", "SOON", "SOOT", "SORE", "SORT", "SOUL",
451
"SOUR", "SOWN", "STAB", "STAG", "STAN", "STAR", "STAY", "STEM",
452
"STEW", "STIR", "STOW", "STUB", "STUN", "SUCH", "SUDS", "SUIT",
453
"SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF", "SWAB", "SWAG",
454
"SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK", "TACT",
455
"TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE",
456
"TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET",
457
"TELL", "TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN",
458
"THAT", "THEE", "THEM", "THEN", "THEY", "THIN", "THIS", "THUD",
459
"THUG", "TICK", "TIDE", "TIDY", "TIED", "TIER", "TILE", "TILL",
460
"TILT", "TIME", "TINA", "TINE", "TINT", "TINY", "TIRE", "TOAD",
461
"TOGO", "TOIL", "TOLD", "TOLL", "TONE", "TONG", "TONY", "TOOK",
462
"TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR", "TOUT", "TOWN",
463
"TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM", "TRIO",
464
"TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT",
465
"TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN",
466
"TWIT", "ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH",
467
"VAIL", "VAIN", "VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA",
468
"VEIL", "VEIN", "VEND", "VENT", "VERB", "VERY", "VETO", "VICE",
469
"VIEW", "VINE", "VISE", "VOID", "VOLT", "VOTE", "WACK", "WADE",
470
"WAGE", "WAIL", "WAIT", "WAKE", "WALE", "WALK", "WALL", "WALT",
471
"WAND", "WANE", "WANG", "WANT", "WARD", "WARM", "WARN", "WART",
472
"WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS", "WEAK",
473
"WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL",
474
"WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE",
475
"WHEN", "WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL",
476
"WIND", "WINE", "WING", "WINK", "WINO", "WIRE", "WISE", "WISH",
477
"WITH", "WOLF", "WONT", "WOOD", "WOOL", "WORD", "WORE", "WORK",
478
"WORM", "WORN", "WOVE", "WRIT", "WYNN", "YALE", "YANG", "YANK",
479
"YARD", "YARN", "YAWL", "YAWN", "YEAH", "YEAR", "YELL", "YOGA",