From aadb9e2e90925a187877241e50110e4ce7ea80a1 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Sat, 14 Mar 2015 19:47:09 -0400 Subject: Imported Upstream version 1.3 --- ChangeLog | 36 + Makefile.proto | 100 + README | 27 + cexcept.h | 243 ++ diagnostics.h | 41 + diceware8k.c | 8201 ++++++++++++++++++++++++++++++++++++++++++++++ exceptions.h | 43 + main.c | 222 ++ pwgen.c | 313 ++ pwgen.h | 130 + secpwgen.1 | 293 ++ secure_memory.h | 57 + secure_memory_unix.c | 135 + secure_random.h | 69 + secure_random_cryptlib.c | 84 + secure_random_openssl.c | 108 + skeylist.c | 263 ++ 17 files changed, 10365 insertions(+) create mode 100644 ChangeLog create mode 100644 Makefile.proto create mode 100644 README create mode 100644 cexcept.h create mode 100644 diagnostics.h create mode 100644 diceware8k.c create mode 100644 exceptions.h create mode 100644 main.c create mode 100644 pwgen.c create mode 100644 pwgen.h create mode 100644 secpwgen.1 create mode 100644 secure_memory.h create mode 100644 secure_memory_unix.c create mode 100644 secure_random.h create mode 100644 secure_random_cryptlib.c create mode 100644 secure_random_openssl.c create mode 100644 skeylist.c diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..ea40d18 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,36 @@ +Changes in 1.3 +* Added koremutake method for pronouncible password generation. +* Moved to MIT license + +Changes in 1.2 +* Added cryptlib support + +* Added an option to compile with mlock() instead of mlockall(). + - mlockall() caused problems on some Linux 2.6 distros because it would + succeed even for ordinary users. some library component would then + try to allocate too much memory which would exceed the process' + resource limits for locked memory. being unable to allocate memory has + resulted in a crash. + +* Minor code improvements: + - uses mprotect(PROT_NONE) on the last page of secure memory so that the + segmentation fault is guaranteed on buffer overflow + - minor cleanups + +* Updated manpage + +Changes in 1.1 +* Major security improvements: + - memory locking + - zeroing "secure" memory on exit + - disabling core dumps + - dropping root privileges after memory locking + - printing a warning if security can't be completely set up + +* The program does no buffer length checking. If you try to generate too long + passphrase, the program will CRASH because of buffer overrun. For that + event to happen the passphrase would have to be long about 3000 characters. + +* Major code cleanups. + +* Added the manual page. diff --git a/Makefile.proto b/Makefile.proto new file mode 100644 index 0000000..e932ed4 --- /dev/null +++ b/Makefile.proto @@ -0,0 +1,100 @@ +############################################################################## +# USER CONFIGURATION +# You MUST set all of the following variables for the compilation to succeed. +############################################################################## + +## +# paths to crypto library headers and archives. if they are not in the +# standard system locations (this really depends on the OS you are using), +# then UNCOMMENT the CRYPTO_INCLUDE_PATH and CRYPTO_LIBRARY_PATH and add the +# appropriate paths immediately after -I, resp. -L. +# +# OpenSSL +# ------- +# The include path is the directory containing the openssl include +# directory (e.g. if OpenSSL is installed in /usr/local/ssl, its include +# files are in /usr/local/ssl/include/openssl and you must set the +# CRYPTO_INCLUDE_PATH to -I/usr/local/ssl/include). +# +# The library path for OpenSSL is the one containing libcrypto.so or +# libcrypto.a (e.g. set CRYPTO_LIBRARY_PATH to -L/usr/local/ssl/lib) +# +# cryptlib +# -------- +# The include directory is the one containing the cryptlib.h file. +# The library path is the one containing libcl.so or libcl.a. +## +#CRYPTO_INCLUDE_PATH = -I/replace/this/with/real/path +#CRYPTO_LIBRARY_PATH = -L/replace/this/with/real/path + +## +# If using OpenSSL, uncomment the following 3 lines. +## +#CRYPTO_CFLAGS = +#CRYPTO_OBJS = secure_random_openssl.o +#CRYPTO_LIBS = -lcrypto + +## +# If using cryptlib, uncomment the following 3 lines. +## +#CRYPTO_CFLAGS = -D_REENTRANT +#CRYPTO_OBJS = secure_random_cryptlib.o +#CRYPTO_LIBS = -lcl -lpthread + +## +# Change PREFIX to install to different directories. The binary is installed +# in $PREFIX/bin, and the man in $PREFIX/man/man1 +## +PREFIX = /usr/local + +## +# On some operating systems (most notably Linux 2.6 kernels) using mlockall +# causes the program to fail with segmentation fault because it tries to +# allocate memory beyond its current resource limits for locked memory. If +# you experience crashes immediately at startup, uncomment the following line. +## +# +#NO_MLOCKALL = -DDISABLE_MLOCKALL + +## +# Sometimes you have only dynamic libraries available. In that case COMMENT +# the following line. +## +LINK_STATIC = -static + +############################################################################## +# NO USER MODIFIABLE PARTS AFTER THIS POINT +############################################################################## +CFLAGS = -Wall $(CRYPTO_INCLUDE_PATH) $(CRYPTO_CFLAGS) $(NO_MLOCKALL) +LDFLAGS = $(CRYPTO_LIBRARY_PATH) $(LINK_STATIC) $(CRYPTO_LIBS) -lm + +.PHONY : all install-strip install clean + +OBJS = diceware8k.o main.o pwgen.o secure_memory_unix.o \ + $(CRYPTO_OBJS) skeylist.o + +all: secpwgen + +secpwgen: $(OBJS) + $(CC) -o $@ $(OBJS) $(LDFLAGS) + +install-strip: secpwgen + strip secpwgen + $(MAKE) install + +install: secpwgen + cp -i secpwgen $(PREFIX)/bin + cp -i secpwgen.1 $(PREFIX)/man/man1 + +clean: + rm -f *.o secpwgen + +diceware8k.o: diceware8k.c +main.o: main.c secure_memory.h secure_random.h pwgen.h exceptions.h \ + cexcept.h +pwgen.o: pwgen.c secure_random.h pwgen.h exceptions.h cexcept.h +secure_memory_unix.o: secure_memory_unix.c secure_random.h \ + secure_memory.h exceptions.h cexcept.h +secure_random_cryptlib.o: secure_random_cryptlib.c exceptions.h cexcept.h +secure_random_openssl.o: secure_random_openssl.c exceptions.h cexcept.h +skeylist.o: skeylist.c diff --git a/README b/README new file mode 100644 index 0000000..d27b7f5 --- /dev/null +++ b/README @@ -0,0 +1,27 @@ +PREREQUISITES +============= +You need OpenSSL at least 0.9.7 OR cryptlib 3.1 or later. + +HOW +=== +Copy Makefile.proto to Makefile and edit it according to instructions found +there. + +USAGE +===== +Read the secpwgen man page. + +NOTE ON VERSIONING +================== +Unlike many open-source packages, this program's versioning follows the +normal DECIMAL NUMBER comparison rules: the following example shows the +ordering of versions: 0.9 < 1.0 < 1.1 < 1.2 < 1.21 < 1.22xx < 1.3 (some +time in the future) because the same relations hold for ordinary decimals. + +TODO +==== +Add an option to specify path to EGD socket. This will enable the program to +provide secure passwords even on crippled systems (with no /dev/{u,}random) +provided EGD (entropy gathering daemon) is running. + +Call OpenSSL Win32 specific function to init the entropy pool. diff --git a/cexcept.h b/cexcept.h new file mode 100644 index 0000000..dbea51e --- /dev/null +++ b/cexcept.h @@ -0,0 +1,243 @@ +/*=== +cexcept.h 2.0.0 (2001-Jul-12-Thu) +Adam M. Costello + +An interface for exception-handling in ANSI C (C89 and subsequent ISO +standards), developed jointly with Cosmin Truta . + + Copyright (c) 2001 Adam M. Costello and Cosmin Truta. Everyone + is hereby granted permission to do whatever they like with this + file, provided that if they modify it they take reasonable steps to + avoid confusing or misleading people about the authors, version, + and terms of use of the derived file. The copyright holders make + no guarantees regarding this file, and are not responsible for any + damage resulting from its use. + +Only user-defined exceptions are supported, not "real" exceptions like +division by zero or memory segmentation violations. + +If this interface is used by multiple .c files, they shouldn't include +this header file directly. Instead, create a wrapper header file that +includes this header file and then invokes the define_exception_type +macro (see below), and let your .c files include that header file. + +The interface consists of one type, one well-known name, and six macros. + + +define_exception_type(type_name); + + This macro is used like an external declaration. It specifies + the type of object that gets copied from the exception thrower to + the exception catcher. The type_name can be any type that can be + assigned to, that is, a non-constant arithmetic type, struct, union, + or pointer. Examples: + + define_exception_type(int); + + enum exception { out_of_memory, bad_arguments, disk_full }; + define_exception_type(enum exception); + + struct exception { int code; const char *msg; }; + define_exception_type(struct exception); + + Because throwing an exception causes the object to be copied (not + just once, but twice), programmers may wish to consider size when + choosing the exception type. + + +struct exception_context; + + This type may be used after the define_exception_type() macro has + been invoked. A struct exception_context must be known to both + the thrower and the catcher. It is expected that there be one + context for each thread that uses exceptions. It would certainly + be dangerous for multiple threads to access the same context. + One thread can use multiple contexts, but that is likely to be + confusing and not typically useful. The application can allocate + this structure in any way it pleases--automatic, static, or dynamic. + The application programmer should pretend not to know the structure + members, which are subject to change. + + +struct exception_context *the_exception_context; + + The Try/Catch and Throw statements (described below) implicitly + refer to a context, using the name the_exception_context. It is + the application's responsibility to make sure that this name yields + the address of a mutable (non-constant) struct exception_context + wherever those statements are used. Subject to that constraint, the + application may declare a variable of this name anywhere it likes + (inside a function, in a parameter list, or externally), and may + use whatever storage class specifiers (static, extern, etc) or type + qualifiers (const, volatile, etc) it likes. Examples: + + static struct exception_context + * const the_exception_context = &foo; + + { struct exception_context *the_exception_context = bar; ... } + + int blah(struct exception_context *the_exception_context, ...); + + extern struct exception_context the_exception_context[1]; + + The last example illustrates a trick that avoids creating a pointer + object separate from the structure object. + + The name could even be a macro, for example: + + struct exception_context ec_array[numthreads]; + #define the_exception_context (ec_array + thread_id) + + Be aware that the_exception_context is used several times by the + Try/Catch/Throw macros, so it shouldn't be expensive or have side + effects. The expansion must be a drop-in replacement for an + identifier, so it's safest to put parentheses around it. + + +void init_exception_context(struct exception_context *ec); + + For context structures allocated statically (by an external + definition or using the "static" keyword), the implicit + initialization to all zeros is sufficient, but contexts allocated + by other means must be initialized using this macro before they + are used by a Try/Catch statement. It does no harm to initialize + a context more than once (by using this macro on a statically + allocated context, or using this macro twice on the same context), + but a context must not be re-initialized after it has been used by a + Try/Catch statement. + + +Try statement +Catch (expression) statement + + The Try/Catch/Throw macros are capitalized in order to avoid + confusion with the C++ keywords, which have subtly different + semantics. + + A Try/Catch statement has a syntax similar to an if/else statement, + except that the parenthesized expression goes after the second + keyword rather than the first. As with if/else, there are two + clauses, each of which may be a simple statement ending with a + semicolon or a brace-enclosed compound statement. But whereas + the else clause is optional, the Catch clause is required. The + expression must be a modifiable lvalue (something capable of being + assigned to) of the same type (disregarding type qualifiers) that + was passed to define_exception_type(). + + If a Throw that uses the same exception context as the Try/Catch is + executed within the Try clause (typically within a function called + by the Try clause), and the exception is not caught by a nested + Try/Catch statement, then a copy of the exception will be assigned + to the expression, and control will jump to the Catch clause. If no + such Throw is executed, then the assignment is not performed, and + the Catch clause is not executed. + + The expression is not evaluated unless and until the exception is + caught, which is significant if it has side effects, for example: + + Try foo(); + Catch (p[++i].e) { ... } + + IMPORTANT: Jumping into or out of a Try clause (for example via + return, break, continue, goto, longjmp) is forbidden--the compiler + will not complain, but bad things will happen at run-time. Jumping + into or out of a Catch clause is okay, and so is jumping around + inside a Try clause. In many cases where one is tempted to return + from a Try clause, it will suffice to use Throw, and then return + from the Catch clause. Another option is to set a flag variable and + use goto to jump to the end of the Try clause, then check the flag + after the Try/Catch statement. + + IMPORTANT: The values of any non-volatile automatic variables + changed within the Try clause are undefined after an exception is + caught. Therefore, variables modified inside the Try block whose + values are needed later outside the Try block must either use static + storage or be declared with the "volatile" type qualifier. + + +Throw expression; + + A Throw statement is very much like a return statement, except that + the expression is required. Whereas return jumps back to the place + where the current function was called, Throw jumps back to the Catch + clause of the innermost enclosing Try clause. The expression must + be compatible with the type passed to define_exception_type(). The + exception must be caught, otherwise the program may crash. + + Slight limitation: If the expression is a comma-expression it must + be enclosed in parentheses. + + +Try statement +Catch_anonymous statement + + When the value of the exception is not needed, a Try/Catch statement + can use Catch_anonymous instead of Catch (expression). + + +Everything below this point is for the benefit of the compiler. The +application programmer should pretend not to know any of it, because it +is subject to change. + +===*/ + + +#ifndef CEXCEPT_H +#define CEXCEPT_H + + +#include + +#define define_exception_type(etype) \ +struct exception_context { \ + jmp_buf *penv; \ + int caught; \ + volatile struct { etype etmp; } v; \ +} + +/* etmp must be volatile because the application might use automatic */ +/* storage for the_exception_context, and etmp is modified between */ +/* the calls to setjmp() and longjmp(). A wrapper struct is used to */ +/* avoid warnings about a duplicate volatile qualifier in case etype */ +/* already includes it. */ + +#define init_exception_context(ec) ((void)((ec)->penv = 0)) + +#define Try \ + { \ + jmp_buf *exception__prev, exception__env; \ + exception__prev = the_exception_context->penv; \ + the_exception_context->penv = &exception__env; \ + if (setjmp(exception__env) == 0) { \ + if (&exception__prev) + +#define exception__catch(action) \ + else { } \ + the_exception_context->caught = 0; \ + } \ + else { \ + the_exception_context->caught = 1; \ + } \ + the_exception_context->penv = exception__prev; \ + } \ + if (!the_exception_context->caught || action) { } \ + else + +#define Catch(e) exception__catch(((e) = the_exception_context->v.etmp, 0)) +#define Catch_anonymous exception__catch(0) + +/* Try ends with if(), and Catch begins and ends with else. This */ +/* ensures that the Try/Catch syntax is really the same as the */ +/* if/else syntax. */ +/* */ +/* We use &exception__prev instead of 1 to appease compilers that */ +/* warn about constant expressions inside if(). Most compilers */ +/* should still recognize that &exception__prev is never zero and */ +/* avoid generating test code. */ + +#define Throw \ + for (;; longjmp(*the_exception_context->penv, 1)) \ + the_exception_context->v.etmp = + + +#endif /* CEXCEPT_H */ diff --git a/diagnostics.h b/diagnostics.h new file mode 100644 index 0000000..8b5d820 --- /dev/null +++ b/diagnostics.h @@ -0,0 +1,41 @@ +/* + diagnostics.h - standard error codes and messages + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef DIAGNOSTICS_H__ +#define DIAGNOSTICS_H__ + +#define I01 "destroying secure memory" +#define W01 "using insecure memory" +#define E01 "N must be an integer > 0" +#define F01 "out of memory" +#define F02 "system call failed" +#define F03 "unhandled exception" +#define F04 "can't drop privileges" + +#define IWDIAG(x, ...) fprintf(stderr, "%s: %s:\n", #x, x, __VA_ARGS__) +#define EFDIAG(x, ...) do { \ + fprintf(stderr, "%s: %s\n", #x, __VA_ARGS__);\ + exit(EXIT_FAILURE);\ +} + +#endif /* DIAGNOSTICS_H__ */ diff --git a/diceware8k.c b/diceware8k.c new file mode 100644 index 0000000..6cefa03 --- /dev/null +++ b/diceware8k.c @@ -0,0 +1,8201 @@ +/* Diceware 8k Word List in C + Arnold G. Reinhold + 2000-10-23 */ + +static const char * Dicewds8k[] = +{"a", +"a&p", +"a's", +"a2", +"a3", +"a4", +"a5", +"a6", +"a7", +"a8", +"a9", +"aa", +"aaa", +"aaaa", +"aaron", +"ab", +"aba", +"ababa", +"aback", +"abase", +"abash", +"abate", +"abbas", +"abbe", +"abbey", +"abbot", +"abbott", +"abc", +"abe", +"abed", +"abel", +"abet", +"abide", +"abject", +"ablaze", +"able", +"abner", +"abo", +"abode", +"abort", +"about", +"above", +"abrade", +"abram", +"absorb", +"abuse", +"abut", +"abyss", +"ac", +"acadia", +"accra", +"accrue", +"ace", +"acetic", +"ache", +"acid", +"acidic", +"acm", +"acme", +"acorn", +"acre", +"acrid", +"act", +"acton", +"actor", +"acts", +"acuity", +"acute", +"ad", +"ada", +"adage", +"adagio", +"adair", +"adam", +"adams", +"adapt", +"add", +"added", +"addict", +"addis", +"addle", +"adele", +"aden", +"adept", +"adieu", +"adjust", +"adler", +"admit", +"admix", +"ado", +"adobe", +"adonis", +"adopt", +"adore", +"adorn", +"adult", +"advent", +"advert", +"advise", +"ae", +"aegis", +"aeneid", +"af", +"afar", +"affair", +"affine", +"affix", +"afire", +"afoot", +"afraid", +"africa", +"afro", +"aft", +"ag", +"again", +"agate", +"agave", +"age", +"agee", +"agenda", +"agent", +"agile", +"aging", +"agnes", +"agnew", +"ago", +"agone", +"agony", +"agree", +"ague", +"agway", +"ah", +"ahead", +"ahem", +"ahoy", +"ai", +"aid", +"aida", +"aide", +"aides", +"aiken", +"ail", +"aile", +"aim", +"ain't", +"ainu", +"air", +"aires", +"airman", +"airway", +"airy", +"aisle", +"aj", +"ajar", +"ajax", +"ak", +"akers", +"akin", +"akron", +"al", +"ala", +"alai", +"alamo", +"alan", +"alarm", +"alaska", +"alb", +"alba", +"album", +"alcoa", +"alden", +"alder", +"ale", +"alec", +"aleck", +"aleph", +"alert", +"alex", +"alexei", +"alga", +"algae", +"algal", +"alger", +"algol", +"ali", +"alia", +"alias", +"alibi", +"alice", +"alien", +"alight", +"align", +"alike", +"alive", +"all", +"allah", +"allan", +"allay", +"allen", +"alley", +"allied", +"allis", +"allot", +"allow", +"alloy", +"allure", +"ally", +"allyl", +"allyn", +"alma", +"almost", +"aloe", +"aloft", +"aloha", +"alone", +"along", +"aloof", +"aloud", +"alp", +"alpha", +"alps", +"also", +"alsop", +"altair", +"altar", +"alter", +"alto", +"alton", +"alum", +"alumni", +"alva", +"alvin", +"alway", +"am", +"ama", +"amass", +"amaze", +"amber", +"amble", +"ambush", +"amen", +"amend", +"ames", +"ami", +"amid", +"amide", +"amigo", +"amino", +"amiss", +"amity", +"amman", +"ammo", +"amoco", +"amok", +"among", +"amort", +"amos", +"amp", +"ampere", +"ampex", +"ample", +"amply", +"amra", +"amulet", +"amuse", +"amy", +"an", +"ana", +"and", +"andes", +"andre", +"andrew", +"andy", +"anent", +"anew", +"angel", +"angelo", +"anger", +"angie", +"angle", +"anglo", +"angola", +"angry", +"angst", +"angus", +"ani", +"anion", +"anise", +"anita", +"ankle", +"ann", +"anna", +"annal", +"anne", +"annex", +"annie", +"annoy", +"annul", +"annuli", +"annum", +"anode", +"ansi", +"answer", +"ant", +"ante", +"anti", +"antic", +"anton", +"anus", +"anvil", +"any", +"anyhow", +"anyway", +"ao", +"aok", +"aorta", +"ap", +"apart", +"apathy", +"ape", +"apex", +"aphid", +"aplomb", +"appeal", +"append", +"apple", +"apply", +"april", +"apron", +"apse", +"apt", +"aq", +"aqua", +"ar", +"arab", +"araby", +"arc", +"arcana", +"arch", +"archer", +"arden", +"ardent", +"are", +"area", +"arena", +"ares", +"argive", +"argo", +"argon", +"argot", +"argue", +"argus", +"arhat", +"arid", +"aries", +"arise", +"ark", +"arlen", +"arlene", +"arm", +"armco", +"army", +"arnold", +"aroma", +"arose", +"arpa", +"array", +"arrear", +"arrow", +"arson", +"art", +"artery", +"arthur", +"artie", +"arty", +"aruba", +"arum", +"aryl", +"as", +"ascend", +"ash", +"ashen", +"asher", +"ashley", +"ashy", +"asia", +"aside", +"ask", +"askew", +"asleep", +"aspen", +"aspire", +"ass", +"assai", +"assam", +"assay", +"asset", +"assort", +"assure", +"aster", +"astm", +"astor", +"astral", +"at", +"at&t", +"ate", +"athens", +"atlas", +"atom", +"atomic", +"atone", +"atop", +"attic", +"attire", +"au", +"aubrey", +"audio", +"audit", +"aug", +"auger", +"augur", +"august", +"auk", +"aunt", +"aura", +"aural", +"auric", +"austin", +"auto", +"autumn", +"av", +"avail", +"ave", +"aver", +"avert", +"avery", +"aviate", +"avid", +"avis", +"aviv", +"avoid", +"avon", +"avow", +"aw", +"await", +"awake", +"award", +"aware", +"awash", +"away", +"awe", +"awful", +"awl", +"awn", +"awoke", +"awry", +"ax", +"axe", +"axes", +"axial", +"axiom", +"axis", +"axle", +"axon", +"ay", +"aye", +"ayers", +"az", +"aztec", +"azure", +"b", +"b's", +"b2", +"b3", +"b4", +"b5", +"b6", +"b7", +"b8", +"b9", +"ba", +"babe", +"babel", +"baby", +"bach", +"back", +"backup", +"bacon", +"bad", +"bade", +"baden", +"badge", +"baffle", +"bag", +"baggy", +"bah", +"bahama", +"bail", +"baird", +"bait", +"bake", +"baku", +"bald", +"baldy", +"bale", +"bali", +"balk", +"balkan", +"balky", +"ball", +"balled", +"ballot", +"balm", +"balmy", +"balsa", +"bam", +"bambi", +"ban", +"banal", +"band", +"bandit", +"bandy", +"bane", +"bang", +"banish", +"banjo", +"bank", +"banks", +"bantu", +"bar", +"barb", +"bard", +"bare", +"barfly", +"barge", +"bark", +"barley", +"barn", +"barnes", +"baron", +"barony", +"barr", +"barre", +"barry", +"barter", +"barth", +"barton", +"basal", +"base", +"basel", +"bash", +"basic", +"basil", +"basin", +"basis", +"bask", +"bass", +"bassi", +"basso", +"baste", +"bat", +"batch", +"bate", +"bater", +"bates", +"bath", +"bathe", +"batik", +"baton", +"bator", +"batt", +"bauble", +"baud", +"bauer", +"bawd", +"bawdy", +"bawl", +"baxter", +"bay", +"bayda", +"bayed", +"bayou", +"bazaar", +"bb", +"bbb", +"bbbb", +"bc", +"bcd", +"bd", +"be", +"beach", +"bead", +"beady", +"beak", +"beam", +"bean", +"bear", +"beard", +"beast", +"beat", +"beau", +"beauty", +"beaux", +"bebop", +"becalm", +"beck", +"becker", +"becky", +"bed", +"bedim", +"bee", +"beebe", +"beech", +"beef", +"beefy", +"been", +"beep", +"beer", +"beet", +"befall", +"befit", +"befog", +"beg", +"began", +"beget", +"beggar", +"begin", +"begun", +"behind", +"beige", +"being", +"beirut", +"bel", +"bela", +"belch", +"belfry", +"belie", +"bell", +"bella", +"belle", +"belly", +"below", +"belt", +"bema", +"beman", +"bemoan", +"ben", +"bench", +"bend", +"bender", +"benny", +"bent", +"benz", +"berea", +"bereft", +"beret", +"berg", +"berlin", +"bern", +"berne", +"bernet", +"berra", +"berry", +"bert", +"berth", +"beryl", +"beset", +"bess", +"bessel", +"best", +"bestir", +"bet", +"beta", +"betel", +"beth", +"bethel", +"betsy", +"bette", +"betty", +"bevel", +"bevy", +"beware", +"bey", +"bezel", +"bf", +"bg", +"bh", +"bhoy", +"bi", +"bias", +"bib", +"bibb", +"bible", +"bicep", +"biceps", +"bid", +"biddy", +"bide", +"bien", +"big", +"biggs", +"bigot", +"bile", +"bilge", +"bilk", +"bill", +"billow", +"billy", +"bin", +"binary", +"bind", +"bing", +"binge", +"bingle", +"bini", +"biota", +"birch", +"bird", +"birdie", +"birth", +"bison", +"bisque", +"bit", +"bitch", +"bite", +"bitt", +"bitten", +"biz", +"bizet", +"bj", +"bk", +"bl", +"blab", +"black", +"blade", +"blair", +"blake", +"blame", +"blanc", +"bland", +"blank", +"blare", +"blast", +"blat", +"blatz", +"blaze", +"bleak", +"bleat", +"bled", +"bleed", +"blend", +"bless", +"blest", +"blew", +"blimp", +"blind", +"blink", +"blinn", +"blip", +"bliss", +"blithe", +"blitz", +"bloat", +"blob", +"bloc", +"bloch", +"block", +"bloke", +"blond", +"blonde", +"blood", +"bloom", +"bloop", +"blot", +"blotch", +"blow", +"blown", +"blue", +"bluet", +"bluff", +"blum", +"blunt", +"blur", +"blurt", +"blush", +"blvd", +"blythe", +"bm", +"bmw", +"bn", +"bo", +"boa", +"boar", +"board", +"boast", +"boat", +"bob", +"bobbin", +"bobby", +"bobcat", +"boca", +"bock", +"bode", +"body", +"bog", +"bogey", +"boggy", +"bogus", +"bogy", +"bohr", +"boil", +"bois", +"boise", +"bold", +"bole", +"bolo", +"bolt", +"bomb", +"bombay", +"bon", +"bona", +"bond", +"bone", +"bong", +"bongo", +"bonn", +"bonus", +"bony", +"bonze", +"boo", +"booby", +"boogie", +"book", +"booky", +"boom", +"boon", +"boone", +"boor", +"boost", +"boot", +"booth", +"booty", +"booze", +"bop", +"borax", +"border", +"bore", +"borg", +"boric", +"boris", +"born", +"borne", +"borneo", +"boron", +"bosch", +"bose", +"bosom", +"boson", +"boss", +"boston", +"botch", +"both", +"bottle", +"bough", +"bouncy", +"bound", +"bourn", +"bout", +"bovine", +"bow", +"bowel", +"bowen", +"bowie", +"bowl", +"box", +"boxy", +"boy", +"boyar", +"boyce", +"boyd", +"boyle", +"bp", +"bq", +"br", +"brace", +"bract", +"brad", +"brady", +"brae", +"brag", +"bragg", +"braid", +"brain", +"brainy", +"brake", +"bran", +"brand", +"brandt", +"brant", +"brash", +"brass", +"brassy", +"braun", +"brave", +"bravo", +"brawl", +"bray", +"bread", +"break", +"bream", +"breath", +"bred", +"breed", +"breeze", +"bremen", +"brent", +"brest", +"brett", +"breve", +"brew", +"brian", +"briar", +"bribe", +"brice", +"brick", +"bride", +"brief", +"brig", +"briggs", +"brim", +"brine", +"bring", +"brink", +"briny", +"brisk", +"broad", +"brock", +"broil", +"broke", +"broken", +"bronx", +"brood", +"brook", +"brooke", +"broom", +"broth", +"brow", +"brown", +"browse", +"bruce", +"bruit", +"brunch", +"bruno", +"brunt", +"brush", +"brute", +"bryan", +"bryant", +"bryce", +"bryn", +"bs", +"bstj", +"bt", +"btl", +"bu", +"bub", +"buck", +"bud", +"budd", +"buddy", +"budge", +"buena", +"buenos", +"buff", +"bug", +"buggy", +"bugle", +"buick", +"build", +"built", +"bulb", +"bulge", +"bulk", +"bulky", +"bull", +"bully", +"bum", +"bump", +"bun", +"bunch", +"bundy", +"bunk", +"bunny", +"bunt", +"bunyan", +"buoy", +"burch", +"bureau", +"buret", +"burg", +"buried", +"burke", +"burl", +"burly", +"burma", +"burn", +"burnt", +"burp", +"burr", +"burro", +"burst", +"burt", +"burton", +"burtt", +"bury", +"bus", +"busch", +"bush", +"bushel", +"bushy", +"buss", +"bust", +"busy", +"but", +"butane", +"butch", +"buteo", +"butt", +"butte", +"butyl", +"buxom", +"buy", +"buyer", +"buzz", +"buzzy", +"bv", +"bw", +"bx", +"by", +"bye", +"byers", +"bylaw", +"byline", +"byrd", +"byrne", +"byron", +"byte", +"byway", +"byword", +"bz", +"c", +"c's", +"c2", +"c3", +"c4", +"c5", +"c6", +"c7", +"c8", +"c9", +"ca", +"cab", +"cabal", +"cabin", +"cable", +"cabot", +"cacao", +"cache", +"cacm", +"cacti", +"caddy", +"cadent", +"cadet", +"cadre", +"cady", +"cafe", +"cage", +"cagey", +"cahill", +"caiman", +"cain", +"caine", +"cairn", +"cairo", +"cake", +"cal", +"calder", +"caleb", +"calf", +"call", +"calla", +"callus", +"calm", +"calve", +"cam", +"camber", +"came", +"camel", +"cameo", +"camp", +"can", +"can't", +"canal", +"canary", +"cancer", +"candle", +"candy", +"cane", +"canis", +"canna", +"cannot", +"canny", +"canoe", +"canon", +"canopy", +"cant", +"canto", +"canton", +"cap", +"cape", +"caper", +"capo", +"car", +"carbon", +"card", +"care", +"caress", +"caret", +"carey", +"cargo", +"carib", +"carl", +"carla", +"carlo", +"carne", +"carob", +"carol", +"carp", +"carpet", +"carr", +"carrie", +"carry", +"carson", +"cart", +"carte", +"caruso", +"carve", +"case", +"casey", +"cash", +"cashew", +"cask", +"casket", +"cast", +"caste", +"cat", +"catch", +"cater", +"cathy", +"catkin", +"catsup", +"cauchy", +"caulk", +"cause", +"cave", +"cavern", +"cavil", +"cavort", +"caw", +"cayuga", +"cb", +"cbs", +"cc", +"ccc", +"cccc", +"cd", +"cdc", +"ce", +"cease", +"cecil", +"cedar", +"cede", +"ceil", +"celia", +"cell", +"census", +"cent", +"ceres", +"cern", +"cetera", +"cetus", +"cf", +"cg", +"ch", +"chad", +"chafe", +"chaff", +"chai", +"chain", +"chair", +"chalk", +"champ", +"chance", +"chang", +"chant", +"chao", +"chaos", +"chap", +"chapel", +"char", +"chard", +"charm", +"chart", +"chase", +"chasm", +"chaste", +"chat", +"chaw", +"cheap", +"cheat", +"check", +"cheek", +"cheeky", +"cheer", +"chef", +"chen", +"chert", +"cherub", +"chess", +"chest", +"chevy", +"chew", +"chi", +"chic", +"chick", +"chide", +"chief", +"child", +"chile", +"chili", +"chill", +"chilly", +"chime", +"chin", +"china", +"chine", +"chink", +"chip", +"chirp", +"chisel", +"chit", +"chive", +"chock", +"choir", +"choke", +"chomp", +"chop", +"chopin", +"choral", +"chord", +"chore", +"chose", +"chosen", +"chou", +"chow", +"chris", +"chub", +"chuck", +"chuff", +"chug", +"chum", +"chump", +"chunk", +"churn", +"chute", +"ci", +"cia", +"cicada", +"cider", +"cigar", +"cilia", +"cinch", +"cindy", +"cipher", +"circa", +"circe", +"cite", +"citrus", +"city", +"civet", +"civic", +"civil", +"cj", +"ck", +"cl", +"clad", +"claim", +"clam", +"clammy", +"clamp", +"clan", +"clang", +"clank", +"clap", +"clara", +"clare", +"clark", +"clarke", +"clash", +"clasp", +"class", +"claus", +"clause", +"claw", +"clay", +"clean", +"clear", +"cleat", +"cleft", +"clerk", +"cliche", +"click", +"cliff", +"climb", +"clime", +"cling", +"clink", +"clint", +"clio", +"clip", +"clive", +"cloak", +"clock", +"clod", +"clog", +"clomp", +"clone", +"close", +"closet", +"clot", +"cloth", +"cloud", +"clout", +"clove", +"clown", +"cloy", +"club", +"cluck", +"clue", +"cluj", +"clump", +"clumsy", +"clung", +"clyde", +"cm", +"cn", +"co", +"coach", +"coal", +"coast", +"coat", +"coax", +"cobb", +"cobble", +"cobol", +"cobra", +"coca", +"cock", +"cockle", +"cocky", +"coco", +"cocoa", +"cod", +"coda", +"coddle", +"code", +"codon", +"cody", +"coed", +"cog", +"cogent", +"cohen", +"cohn", +"coil", +"coin", +"coke", +"col", +"cola", +"colby", +"cold", +"cole", +"colon", +"colony", +"colt", +"colza", +"coma", +"comb", +"combat", +"come", +"comet", +"cometh", +"comic", +"comma", +"con", +"conch", +"cone", +"coney", +"congo", +"conic", +"conn", +"conner", +"conway", +"cony", +"coo", +"cook", +"cooke", +"cooky", +"cool", +"cooley", +"coon", +"coop", +"coors", +"coot", +"cop", +"cope", +"copra", +"copy", +"coral", +"corbel", +"cord", +"core", +"corey", +"cork", +"corn", +"corny", +"corp", +"corps", +"corvus", +"cos", +"cosec", +"coset", +"cosh", +"cost", +"costa", +"cosy", +"cot", +"cotta", +"cotty", +"couch", +"cough", +"could", +"count", +"coup", +"coupe", +"court", +"cousin", +"cove", +"coven", +"cover", +"covet", +"cow", +"cowan", +"cowl", +"cowman", +"cowry", +"cox", +"coy", +"coyote", +"coypu", +"cozen", +"cozy", +"cp", +"cpa", +"cq", +"cr", +"crab", +"crack", +"craft", +"crag", +"craig", +"cram", +"cramp", +"crane", +"crank", +"crap", +"crash", +"crass", +"crate", +"crater", +"crave", +"craw", +"crawl", +"craze", +"crazy", +"creak", +"cream", +"credit", +"credo", +"creed", +"creek", +"creep", +"creole", +"creon", +"crepe", +"crept", +"cress", +"crest", +"crete", +"crew", +"crib", +"cried", +"crime", +"crimp", +"crisp", +"criss", +"croak", +"crock", +"crocus", +"croft", +"croix", +"crone", +"crony", +"crook", +"croon", +"crop", +"cross", +"crow", +"crowd", +"crown", +"crt", +"crud", +"crude", +"cruel", +"crumb", +"crump", +"crush", +"crust", +"crux", +"cruz", +"cry", +"crypt", +"cs", +"ct", +"cu", +"cub", +"cuba", +"cube", +"cubic", +"cud", +"cuddle", +"cue", +"cuff", +"cull", +"culpa", +"cult", +"cumin", +"cuny", +"cup", +"cupful", +"cupid", +"cur", +"curb", +"curd", +"cure", +"curfew", +"curia", +"curie", +"curio", +"curl", +"curry", +"curse", +"curt", +"curve", +"cusp", +"cut", +"cute", +"cutlet", +"cv", +"cw", +"cx", +"cy", +"cycad", +"cycle", +"cynic", +"cyril", +"cyrus", +"cyst", +"cz", +"czar", +"czech", +"d", +"d'art", +"d's", +"d2", +"d3", +"d4", +"d5", +"d6", +"d7", +"d8", +"d9", +"da", +"dab", +"dacca", +"dactyl", +"dad", +"dada", +"daddy", +"dade", +"daffy", +"dahl", +"dahlia", +"dairy", +"dais", +"daisy", +"dakar", +"dale", +"daley", +"dally", +"daly", +"dam", +"dame", +"damn", +"damon", +"damp", +"damsel", +"dan", +"dana", +"dance", +"dandy", +"dane", +"dang", +"dank", +"danny", +"dante", +"dar", +"dare", +"dark", +"darken", +"darn", +"darry", +"dart", +"dash", +"data", +"date", +"dater", +"datum", +"daub", +"daunt", +"dave", +"david", +"davis", +"davit", +"davy", +"dawn", +"dawson", +"day", +"daze", +"db", +"dc", +"dd", +"ddd", +"dddd", +"de", +"deacon", +"dead", +"deaf", +"deal", +"dealt", +"dean", +"deane", +"dear", +"death", +"debar", +"debby", +"debit", +"debra", +"debris", +"debt", +"debug", +"debut", +"dec", +"decal", +"decay", +"decca", +"deck", +"decker", +"decor", +"decree", +"decry", +"dee", +"deed", +"deem", +"deep", +"deer", +"deere", +"def", +"defer", +"deform", +"deft", +"defy", +"degas", +"degum", +"deify", +"deign", +"deity", +"deja", +"del", +"delay", +"delft", +"delhi", +"delia", +"dell", +"della", +"delta", +"delve", +"demark", +"demit", +"demon", +"demur", +"den", +"deneb", +"denial", +"denny", +"dense", +"dent", +"denton", +"deny", +"depot", +"depth", +"depute", +"derby", +"derek", +"des", +"desist", +"desk", +"detach", +"deter", +"deuce", +"deus", +"devil", +"devoid", +"devon", +"dew", +"dewar", +"dewey", +"dewy", +"dey", +"df", +"dg", +"dh", +"dhabi", +"di", +"dial", +"diana", +"diane", +"diary", +"dibble", +"dice", +"dick", +"dicta", +"did", +"dido", +"die", +"died", +"diego", +"diem", +"diesel", +"diet", +"diety", +"dietz", +"dig", +"digit", +"dilate", +"dill", +"dim", +"dime", +"din", +"dinah", +"dine", +"ding", +"dingo", +"dingy", +"dint", +"diode", +"dip", +"dirac", +"dire", +"dirge", +"dirt", +"dirty", +"dis", +"disc", +"dish", +"disk", +"disney", +"ditch", +"ditto", +"ditty", +"diva", +"divan", +"dive", +"dixie", +"dixon", +"dizzy", +"dj", +"dk", +"dl", +"dm", +"dn", +"dna", +"do", +"dobbs", +"dobson", +"dock", +"docket", +"dod", +"dodd", +"dodge", +"dodo", +"doe", +"doff", +"dog", +"doge", +"dogma", +"dolan", +"dolce", +"dole", +"doll", +"dolly", +"dolt", +"dome", +"don", +"don't", +"done", +"doneck", +"donna", +"donor", +"doom", +"door", +"dope", +"dora", +"doria", +"doric", +"doris", +"dose", +"dot", +"dote", +"double", +"doubt", +"douce", +"doug", +"dough", +"dour", +"douse", +"dove", +"dow", +"dowel", +"down", +"downs", +"dowry", +"doyle", +"doze", +"dozen", +"dp", +"dq", +"dr", +"drab", +"draco", +"draft", +"drag", +"drain", +"drake", +"dram", +"drama", +"drank", +"drape", +"draw", +"drawl", +"drawn", +"dread", +"dream", +"dreamy", +"dreg", +"dress", +"dressy", +"drew", +"drib", +"dried", +"drier", +"drift", +"drill", +"drink", +"drip", +"drive", +"droll", +"drone", +"drool", +"droop", +"drop", +"dross", +"drove", +"drown", +"drub", +"drug", +"druid", +"drum", +"drunk", +"drury", +"dry", +"dryad", +"ds", +"dt", +"du", +"dual", +"duane", +"dub", +"dubhe", +"dublin", +"ducat", +"duck", +"duct", +"dud", +"due", +"duel", +"duet", +"duff", +"duffy", +"dug", +"dugan", +"duke", +"dull", +"dully", +"dulse", +"duly", +"duma", +"dumb", +"dummy", +"dump", +"dumpy", +"dun", +"dunce", +"dune", +"dung", +"dunham", +"dunk", +"dunlop", +"dunn", +"dupe", +"durer", +"dusk", +"dusky", +"dust", +"dusty", +"dutch", +"duty", +"dv", +"dw", +"dwarf", +"dwell", +"dwelt", +"dwight", +"dwyer", +"dx", +"dy", +"dyad", +"dye", +"dyer", +"dying", +"dyke", +"dylan", +"dyne", +"dz", +"e", +"e'er", +"e's", +"e2", +"e3", +"e4", +"e5", +"e6", +"e7", +"e8", +"e9", +"ea", +"each", +"eagan", +"eager", +"eagle", +"ear", +"earl", +"earn", +"earth", +"ease", +"easel", +"east", +"easy", +"eat", +"eaten", +"eater", +"eaton", +"eave", +"eb", +"ebb", +"eben", +"ebony", +"ec", +"echo", +"eclat", +"ecole", +"ed", +"eddie", +"eddy", +"eden", +"edgar", +"edge", +"edgy", +"edict", +"edify", +"edit", +"edith", +"editor", +"edna", +"edt", +"edwin", +"ee", +"eee", +"eeee", +"eel", +"eeoc", +"eerie", +"ef", +"efface", +"effie", +"efg", +"eft", +"eg", +"egan", +"egg", +"ego", +"egress", +"egret", +"egypt", +"eh", +"ei", +"eider", +"eight", +"eire", +"ej", +"eject", +"ek", +"eke", +"el", +"elan", +"elate", +"elba", +"elbow", +"elder", +"eldon", +"elect", +"elegy", +"elena", +"eleven", +"elfin", +"elgin", +"eli", +"elide", +"eliot", +"elite", +"elk", +"ell", +"ella", +"ellen", +"ellis", +"elm", +"elmer", +"elope", +"else", +"elsie", +"elton", +"elude", +"elute", +"elves", +"ely", +"em", +"embalm", +"embark", +"embed", +"ember", +"emcee", +"emery", +"emil", +"emile", +"emily", +"emit", +"emma", +"emory", +"empty", +"en", +"enact", +"enamel", +"end", +"endow", +"enemy", +"eng", +"engel", +"engle", +"engulf", +"enid", +"enjoy", +"enmity", +"enoch", +"enol", +"enos", +"enrico", +"ensue", +"enter", +"entrap", +"entry", +"envoy", +"envy", +"eo", +"ep", +"epa", +"epic", +"epoch", +"epoxy", +"epsom", +"eq", +"equal", +"equip", +"er", +"era", +"erase", +"erato", +"erda", +"ere", +"erect", +"erg", +"eric", +"erich", +"erie", +"erik", +"ernest", +"ernie", +"ernst", +"erode", +"eros", +"err", +"errand", +"errol", +"error", +"erupt", +"ervin", +"erwin", +"es", +"essay", +"essen", +"essex", +"est", +"ester", +"estes", +"estop", +"et", +"eta", +"etc", +"etch", +"ethan", +"ethel", +"ether", +"ethic", +"ethos", +"ethyl", +"etude", +"eu", +"eucre", +"euler", +"eureka", +"ev", +"eva", +"evade", +"evans", +"eve", +"even", +"event", +"every", +"evict", +"evil", +"evoke", +"evolve", +"ew", +"ewe", +"ewing", +"ex", +"exact", +"exalt", +"exam", +"excel", +"excess", +"exert", +"exile", +"exist", +"exit", +"exodus", +"expel", +"extant", +"extent", +"extol", +"extra", +"exude", +"exult", +"exxon", +"ey", +"eye", +"eyed", +"ez", +"ezra", +"f", +"f's", +"f2", +"f3", +"f4", +"f5", +"f6", +"f7", +"f8", +"f9", +"fa", +"faa", +"faber", +"fable", +"face", +"facet", +"facile", +"fact", +"facto", +"fad", +"fade", +"faery", +"fag", +"fahey", +"fail", +"fain", +"faint", +"fair", +"fairy", +"faith", +"fake", +"fall", +"FALSE", +"fame", +"fan", +"fancy", +"fang", +"fanny", +"fanout", +"far", +"farad", +"farce", +"fare", +"fargo", +"farley", +"farm", +"faro", +"fast", +"fat", +"fatal", +"fate", +"fatty", +"fault", +"faun", +"fauna", +"faust", +"fawn", +"fay", +"faze", +"fb", +"fbi", +"fc", +"fcc", +"fd", +"fda", +"fe", +"fear", +"feast", +"feat", +"feb", +"fed", +"fee", +"feed", +"feel", +"feet", +"feign", +"feint", +"felice", +"felix", +"fell", +"felon", +"felt", +"femur", +"fence", +"fend", +"fermi", +"fern", +"ferric", +"ferry", +"fest", +"fetal", +"fetch", +"fete", +"fetid", +"fetus", +"feud", +"fever", +"few", +"ff", +"fff", +"ffff", +"fg", +"fgh", +"fh", +"fi", +"fiat", +"fib", +"fibrin", +"fiche", +"fide", +"fief", +"field", +"fiend", +"fiery", +"fife", +"fifo", +"fifth", +"fifty", +"fig", +"fight", +"filch", +"file", +"filet", +"fill", +"filler", +"filly", +"film", +"filmy", +"filth", +"fin", +"final", +"finale", +"finch", +"find", +"fine", +"finite", +"fink", +"finn", +"finny", +"fir", +"fire", +"firm", +"first", +"fish", +"fishy", +"fisk", +"fiske", +"fist", +"fit", +"fitch", +"five", +"fix", +"fj", +"fjord", +"fk", +"fl", +"flack", +"flag", +"flail", +"flair", +"flak", +"flake", +"flaky", +"flam", +"flame", +"flank", +"flap", +"flare", +"flash", +"flask", +"flat", +"flatus", +"flaw", +"flax", +"flea", +"fleck", +"fled", +"flee", +"fleet", +"flesh", +"flew", +"flex", +"flick", +"flier", +"flinch", +"fling", +"flint", +"flip", +"flirt", +"flit", +"flo", +"float", +"floc", +"flock", +"floe", +"flog", +"flood", +"floor", +"flop", +"floppy", +"flora", +"flour", +"flout", +"flow", +"flown", +"floyd", +"flu", +"flub", +"flue", +"fluff", +"fluid", +"fluke", +"flung", +"flush", +"flute", +"flux", +"fly", +"flyer", +"flynn", +"fm", +"fmc", +"fn", +"fo", +"foal", +"foam", +"foamy", +"fob", +"focal", +"foci", +"focus", +"fodder", +"foe", +"fog", +"foggy", +"fogy", +"foil", +"foist", +"fold", +"foley", +"folio", +"folk", +"folly", +"fond", +"font", +"food", +"fool", +"foot", +"foote", +"fop", +"for", +"foray", +"force", +"ford", +"fore", +"forge", +"forgot", +"fork", +"form", +"fort", +"forte", +"forth", +"forty", +"forum", +"foss", +"fossil", +"foul", +"found", +"fount", +"four", +"fovea", +"fowl", +"fox", +"foxy", +"foyer", +"fp", +"fpc", +"fq", +"fr", +"frail", +"frame", +"fran", +"franc", +"franca", +"frank", +"franz", +"frau", +"fraud", +"fray", +"freak", +"fred", +"free", +"freed", +"freer", +"frenzy", +"freon", +"fresh", +"fret", +"freud", +"frey", +"freya", +"friar", +"frick", +"fried", +"frill", +"frilly", +"frisky", +"fritz", +"fro", +"frock", +"frog", +"from", +"front", +"frost", +"froth", +"frown", +"froze", +"fruit", +"fry", +"frye", +"fs", +"ft", +"ftc", +"fu", +"fuchs", +"fudge", +"fuel", +"fugal", +"fugue", +"fuji", +"full", +"fully", +"fum", +"fume", +"fun", +"fund", +"fungal", +"fungi", +"funk", +"funny", +"fur", +"furl", +"furry", +"fury", +"furze", +"fuse", +"fuss", +"fussy", +"fusty", +"fuzz", +"fuzzy", +"fv", +"fw", +"fx", +"fy", +"fz", +"g", +"g's", +"g2", +"g3", +"g4", +"g5", +"g6", +"g7", +"g8", +"g9", +"ga", +"gab", +"gable", +"gabon", +"gad", +"gadget", +"gaff", +"gaffe", +"gag", +"gage", +"gail", +"gain", +"gait", +"gal", +"gala", +"galaxy", +"gale", +"galen", +"gall", +"gallop", +"galt", +"gam", +"game", +"gamin", +"gamma", +"gamut", +"gander", +"gang", +"gao", +"gap", +"gape", +"gar", +"garb", +"garish", +"garner", +"garry", +"garth", +"gary", +"gas", +"gash", +"gasp", +"gassy", +"gate", +"gates", +"gator", +"gauche", +"gaudy", +"gauge", +"gaul", +"gaunt", +"gaur", +"gauss", +"gauze", +"gave", +"gavel", +"gavin", +"gawk", +"gawky", +"gay", +"gaze", +"gb", +"gc", +"gd", +"ge", +"gear", +"gecko", +"gee", +"geese", +"geigy", +"gel", +"geld", +"gem", +"gemma", +"gene", +"genie", +"genii", +"genoa", +"genre", +"gent", +"gentry", +"genus", +"gerbil", +"germ", +"gerry", +"get", +"getty", +"gf", +"gg", +"ggg", +"gggg", +"gh", +"ghana", +"ghent", +"ghetto", +"ghi", +"ghost", +"ghoul", +"gi", +"giant", +"gibbs", +"gibby", +"gibe", +"giddy", +"gift", +"gig", +"gil", +"gila", +"gild", +"giles", +"gill", +"gilt", +"gimbal", +"gimpy", +"gin", +"gina", +"ginn", +"gino", +"gird", +"girl", +"girth", +"gist", +"give", +"given", +"gj", +"gk", +"gl", +"glad", +"gladdy", +"glade", +"glamor", +"gland", +"glans", +"glare", +"glass", +"glaze", +"gleam", +"glean", +"glee", +"glen", +"glenn", +"glib", +"glide", +"glint", +"gloat", +"glob", +"globe", +"glom", +"gloom", +"glory", +"gloss", +"glove", +"glow", +"glue", +"glued", +"gluey", +"gluing", +"glum", +"glut", +"glyph", +"gm", +"gmt", +"gn", +"gnarl", +"gnash", +"gnat", +"gnaw", +"gnome", +"gnp", +"gnu", +"go", +"goa", +"goad", +"goal", +"goat", +"gob", +"goer", +"goes", +"goff", +"gog", +"goggle", +"gogh", +"gogo", +"gold", +"golf", +"golly", +"gone", +"gong", +"goo", +"good", +"goode", +"goody", +"goof", +"goofy", +"goose", +"gop", +"gordon", +"gore", +"goren", +"gorge", +"gorky", +"gorse", +"gory", +"gosh", +"gospel", +"got", +"gouda", +"gouge", +"gould", +"gourd", +"gout", +"gown", +"gp", +"gpo", +"gq", +"gr", +"grab", +"grace", +"grad", +"grade", +"grady", +"graff", +"graft", +"grail", +"grain", +"grand", +"grant", +"grape", +"graph", +"grasp", +"grass", +"grata", +"grate", +"grater", +"grave", +"gravy", +"gray", +"graze", +"great", +"grebe", +"greed", +"greedy", +"greek", +"green", +"greer", +"greet", +"greg", +"gregg", +"greta", +"grew", +"grey", +"grid", +"grief", +"grieve", +"grill", +"grim", +"grime", +"grimm", +"grin", +"grind", +"grip", +"gripe", +"grist", +"grit", +"groan", +"groat", +"groin", +"groom", +"grope", +"gross", +"groton", +"group", +"grout", +"grove", +"grow", +"growl", +"grown", +"grub", +"gruff", +"grunt", +"gs", +"gsa", +"gt", +"gu", +"guam", +"guano", +"guard", +"guess", +"guest", +"guide", +"guild", +"guile", +"guilt", +"guise", +"guitar", +"gules", +"gulf", +"gull", +"gully", +"gulp", +"gum", +"gumbo", +"gummy", +"gun", +"gunk", +"gunky", +"gunny", +"gurgle", +"guru", +"gus", +"gush", +"gust", +"gusto", +"gusty", +"gut", +"gutsy", +"guy", +"guyana", +"gv", +"gw", +"gwen", +"gwyn", +"gx", +"gy", +"gym", +"gyp", +"gypsy", +"gyro", +"gz", +"h", +"h's", +"h2", +"h3", +"h4", +"h5", +"h6", +"h7", +"h8", +"h9", +"ha", +"haag", +"haas", +"habib", +"habit", +"hack", +"had", +"hades", +"hadron", +"hagen", +"hager", +"hague", +"hahn", +"haifa", +"haiku", +"hail", +"hair", +"hairy", +"haiti", +"hal", +"hale", +"haley", +"half", +"hall", +"halma", +"halo", +"halt", +"halvah", +"halve", +"ham", +"hamal", +"hamlin", +"han", +"hand", +"handy", +"haney", +"hang", +"hank", +"hanna", +"hanoi", +"hans", +"hansel", +"hap", +"happy", +"hard", +"hardy", +"hare", +"harem", +"hark", +"harley", +"harm", +"harp", +"harpy", +"harry", +"harsh", +"hart", +"harvey", +"hash", +"hasp", +"hast", +"haste", +"hasty", +"hat", +"hatch", +"hate", +"hater", +"hath", +"hatred", +"haul", +"haunt", +"have", +"haven", +"havoc", +"haw", +"hawk", +"hay", +"haydn", +"hayes", +"hays", +"hazard", +"haze", +"hazel", +"hazy", +"hb", +"hc", +"hd", +"he", +"he'd", +"he'll", +"head", +"heady", +"heal", +"healy", +"heap", +"hear", +"heard", +"heart", +"heat", +"heath", +"heave", +"heavy", +"hebe", +"hebrew", +"heck", +"heckle", +"hedge", +"heed", +"heel", +"heft", +"hefty", +"heigh", +"heine", +"heinz", +"heir", +"held", +"helen", +"helga", +"helix", +"hell", +"hello", +"helm", +"helmut", +"help", +"hem", +"hemp", +"hen", +"hence", +"henri", +"henry", +"her", +"hera", +"herb", +"herd", +"here", +"hero", +"heroic", +"heron", +"herr", +"hertz", +"hess", +"hesse", +"hettie", +"hetty", +"hew", +"hewitt", +"hewn", +"hex", +"hey", +"hf", +"hg", +"hh", +"hhh", +"hhhh", +"hi", +"hiatt", +"hick", +"hicks", +"hid", +"hide", +"high", +"hij", +"hike", +"hill", +"hilly", +"hilt", +"hilum", +"him", +"hind", +"hindu", +"hines", +"hinge", +"hint", +"hip", +"hippo", +"hippy", +"hiram", +"hire", +"hirsch", +"his", +"hiss", +"hit", +"hitch", +"hive", +"hj", +"hk", +"hl", +"hm", +"hn", +"ho", +"hoagy", +"hoar", +"hoard", +"hob", +"hobbs", +"hobby", +"hobo", +"hoc", +"hock", +"hodge", +"hodges", +"hoe", +"hoff", +"hog", +"hogan", +"hoi", +"hokan", +"hold", +"holdup", +"hole", +"holly", +"holm", +"holst", +"holt", +"home", +"homo", +"honda", +"hondo", +"hone", +"honey", +"hong", +"honk", +"hooch", +"hood", +"hoof", +"hook", +"hookup", +"hoop", +"hoot", +"hop", +"hope", +"horde", +"horn", +"horny", +"horse", +"horus", +"hose", +"host", +"hot", +"hotbox", +"hotel", +"hough", +"hound", +"hour", +"house", +"hove", +"hovel", +"hover", +"how", +"howdy", +"howe", +"howl", +"hoy", +"hoyt", +"hp", +"hq", +"hr", +"hs", +"ht", +"hu", +"hub", +"hubbub", +"hubby", +"huber", +"huck", +"hue", +"hued", +"huff", +"hug", +"huge", +"hugh", +"hughes", +"hugo", +"huh", +"hulk", +"hull", +"hum", +"human", +"humid", +"hump", +"humus", +"hun", +"hunch", +"hung", +"hunk", +"hunt", +"hurd", +"hurl", +"huron", +"hurrah", +"hurry", +"hurst", +"hurt", +"hurty", +"hush", +"husky", +"hut", +"hutch", +"hv", +"hw", +"hx", +"hy", +"hyde", +"hydra", +"hydro", +"hyena", +"hying", +"hyman", +"hymen", +"hymn", +"hymnal", +"hz", +"i", +"i'd", +"i'll", +"i'm", +"i's", +"i've", +"i2", +"i3", +"i4", +"i5", +"i6", +"i7", +"i8", +"i9", +"ia", +"iambic", +"ian", +"ib", +"ibex", +"ibid", +"ibis", +"ibm", +"ibn", +"ic", +"icc", +"ice", +"icing", +"icky", +"icon", +"icy", +"id", +"ida", +"idaho", +"idea", +"ideal", +"idiom", +"idiot", +"idle", +"idol", +"idyll", +"ie", +"ieee", +"if", +"iffy", +"ifni", +"ig", +"igloo", +"igor", +"ih", +"ii", +"iii", +"iiii", +"ij", +"ijk", +"ik", +"ike", +"il", +"ileum", +"iliac", +"iliad", +"ill", +"illume", +"ilona", +"im", +"image", +"imbue", +"imp", +"impel", +"import", +"impute", +"in", +"inane", +"inapt", +"inc", +"inca", +"incest", +"inch", +"incur", +"index", +"india", +"indies", +"indy", +"inept", +"inert", +"infect", +"infer", +"infima", +"infix", +"infra", +"ingot", +"inhere", +"injun", +"ink", +"inlay", +"inlet", +"inman", +"inn", +"inner", +"input", +"insect", +"inset", +"insult", +"intend", +"inter", +"into", +"inure", +"invoke", +"io", +"ion", +"ionic", +"iota", +"iowa", +"ip", +"ipso", +"iq", +"ir", +"ira", +"iran", +"iraq", +"irate", +"ire", +"irene", +"iris", +"irish", +"irk", +"irma", +"iron", +"irony", +"irs", +"irvin", +"irwin", +"is", +"isaac", +"isabel", +"ising", +"isis", +"islam", +"island", +"isle", +"isn't", +"israel", +"issue", +"it", +"it&t", +"it'd", +"it'll", +"italy", +"itch", +"item", +"ito", +"itt", +"iu", +"iv", +"ivan", +"ive", +"ivory", +"ivy", +"iw", +"ix", +"iy", +"iz", +"j", +"j's", +"j2", +"j3", +"j4", +"j5", +"j6", +"j7", +"j8", +"j9", +"ja", +"jab", +"jack", +"jacky", +"jacm", +"jacob", +"jacobi", +"jade", +"jag", +"jail", +"jaime", +"jake", +"jam", +"james", +"jan", +"jane", +"janet", +"janos", +"janus", +"japan", +"jar", +"jason", +"java", +"jaw", +"jay", +"jazz", +"jazzy", +"jb", +"jc", +"jd", +"je", +"jean", +"jed", +"jeep", +"jeff", +"jejune", +"jelly", +"jenny", +"jeres", +"jerk", +"jerky", +"jerry", +"jersey", +"jess", +"jesse", +"jest", +"jesus", +"jet", +"jew", +"jewel", +"jewett", +"jewish", +"jf", +"jg", +"jh", +"ji", +"jibe", +"jiffy", +"jig", +"jill", +"jilt", +"jim", +"jimmy", +"jinx", +"jive", +"jj", +"jjj", +"jjjj", +"jk", +"jkl", +"jl", +"jm", +"jn", +"jo", +"joan", +"job", +"jock", +"jockey", +"joe", +"joel", +"joey", +"jog", +"john", +"johns", +"join", +"joint", +"joke", +"jolla", +"jolly", +"jolt", +"jon", +"jonas", +"jones", +"jorge", +"jose", +"josef", +"joshua", +"joss", +"jostle", +"jot", +"joule", +"joust", +"jove", +"jowl", +"jowly", +"joy", +"joyce", +"jp", +"jq", +"jr", +"js", +"jt", +"ju", +"juan", +"judas", +"judd", +"jude", +"judge", +"judo", +"judy", +"jug", +"juggle", +"juice", +"juicy", +"juju", +"juke", +"jukes", +"julep", +"jules", +"julia", +"julie", +"julio", +"july", +"jumbo", +"jump", +"jumpy", +"junco", +"june", +"junk", +"junky", +"juno", +"junta", +"jura", +"jure", +"juror", +"jury", +"just", +"jut", +"jute", +"jv", +"jw", +"jx", +"jy", +"jz", +"k", +"k's", +"k2", +"k3", +"k4", +"k5", +"k6", +"k7", +"k8", +"k9", +"ka", +"kabul", +"kafka", +"kahn", +"kajar", +"kale", +"kalmia", +"kane", +"kant", +"kapok", +"kappa", +"karate", +"karen", +"karl", +"karma", +"karol", +"karp", +"kate", +"kathy", +"katie", +"katz", +"kava", +"kay", +"kayo", +"kazoo", +"kb", +"kc", +"kd", +"ke", +"keats", +"keel", +"keen", +"keep", +"keg", +"keith", +"keller", +"kelly", +"kelp", +"kemp", +"ken", +"keno", +"kent", +"kenya", +"kepler", +"kept", +"kern", +"kerr", +"kerry", +"ketch", +"kevin", +"key", +"keyed", +"keyes", +"keys", +"kf", +"kg", +"kh", +"khaki", +"khan", +"khmer", +"ki", +"kick", +"kid", +"kidde", +"kidney", +"kiev", +"kigali", +"kill", +"kim", +"kin", +"kind", +"king", +"kink", +"kinky", +"kiosk", +"kiowa", +"kirby", +"kirk", +"kirov", +"kiss", +"kit", +"kite", +"kitty", +"kiva", +"kivu", +"kiwi", +"kj", +"kk", +"kkk", +"kkkk", +"kl", +"klan", +"klaus", +"klein", +"kline", +"klm", +"klux", +"km", +"kn", +"knack", +"knapp", +"knauer", +"knead", +"knee", +"kneel", +"knelt", +"knew", +"knick", +"knife", +"knit", +"knob", +"knock", +"knoll", +"knot", +"knott", +"know", +"known", +"knox", +"knurl", +"ko", +"koala", +"koch", +"kodak", +"kola", +"kombu", +"kong", +"koran", +"korea", +"kp", +"kq", +"kr", +"kraft", +"krause", +"kraut", +"krebs", +"kruse", +"ks", +"kt", +"ku", +"kudo", +"kudzu", +"kuhn", +"kulak", +"kurd", +"kurt", +"kv", +"kw", +"kx", +"ky", +"kyle", +"kyoto", +"kz", +"l", +"l's", +"l2", +"l3", +"l4", +"l5", +"l6", +"l7", +"l8", +"l9", +"la", +"lab", +"laban", +"label", +"labia", +"labile", +"lac", +"lace", +"lack", +"lacy", +"lad", +"laden", +"ladle", +"lady", +"lag", +"lager", +"lagoon", +"lagos", +"laid", +"lain", +"lair", +"laity", +"lake", +"lam", +"lamar", +"lamb", +"lame", +"lamp", +"lana", +"lance", +"land", +"lane", +"lang", +"lange", +"lanka", +"lanky", +"lao", +"laos", +"lap", +"lapel", +"lapse", +"larch", +"lard", +"lares", +"large", +"lark", +"larkin", +"larry", +"lars", +"larva", +"lase", +"lash", +"lass", +"lasso", +"last", +"latch", +"late", +"later", +"latest", +"latex", +"lath", +"lathe", +"latin", +"latus", +"laud", +"laue", +"laugh", +"launch", +"laura", +"lava", +"law", +"lawn", +"lawson", +"lax", +"lay", +"layup", +"laze", +"lazy", +"lb", +"lc", +"ld", +"le", +"lea", +"leach", +"lead", +"leaf", +"leafy", +"leak", +"leaky", +"lean", +"leap", +"leapt", +"lear", +"learn", +"lease", +"leash", +"least", +"leave", +"led", +"ledge", +"lee", +"leech", +"leeds", +"leek", +"leer", +"leery", +"leeway", +"left", +"lefty", +"leg", +"legal", +"leggy", +"legion", +"leigh", +"leila", +"leland", +"lemma", +"lemon", +"len", +"lena", +"lend", +"lenin", +"lenny", +"lens", +"lent", +"leo", +"leon", +"leona", +"leone", +"leper", +"leroy", +"less", +"lessee", +"lest", +"let", +"lethe", +"lev", +"levee", +"level", +"lever", +"levi", +"levin", +"levis", +"levy", +"lew", +"lewd", +"lewis", +"leyden", +"lf", +"lg", +"lh", +"li", +"liar", +"libel", +"libido", +"libya", +"lice", +"lick", +"lid", +"lie", +"lied", +"lien", +"lieu", +"life", +"lifo", +"lift", +"light", +"like", +"liken", +"lila", +"lilac", +"lilly", +"lilt", +"lily", +"lima", +"limb", +"limbo", +"lime", +"limit", +"limp", +"lin", +"lind", +"linda", +"linden", +"line", +"linen", +"lingo", +"link", +"lint", +"linus", +"lion", +"lip", +"lipid", +"lisa", +"lise", +"lisle", +"lisp", +"list", +"listen", +"lit", +"lithe", +"litton", +"live", +"liven", +"livid", +"livre", +"liz", +"lizzie", +"lj", +"lk", +"ll", +"lll", +"llll", +"lloyd", +"lm", +"lmn", +"ln", +"lo", +"load", +"loaf", +"loam", +"loamy", +"loan", +"loath", +"lob", +"lobar", +"lobby", +"lobe", +"lobo", +"local", +"loci", +"lock", +"locke", +"locus", +"lodge", +"loeb", +"loess", +"loft", +"lofty", +"log", +"logan", +"loge", +"logic", +"loin", +"loire", +"lois", +"loiter", +"loki", +"lola", +"loll", +"lolly", +"lomb", +"lome", +"lone", +"long", +"look", +"loom", +"loon", +"loop", +"loose", +"loot", +"lop", +"lope", +"lopez", +"lord", +"lore", +"loren", +"los", +"lose", +"loss", +"lossy", +"lost", +"lot", +"lotte", +"lotus", +"lou", +"loud", +"louis", +"louise", +"louse", +"lousy", +"louver", +"love", +"low", +"lowe", +"lower", +"lowry", +"loy", +"loyal", +"lp", +"lq", +"lr", +"ls", +"lsi", +"lt", +"ltv", +"lu", +"lucas", +"lucia", +"lucid", +"luck", +"lucky", +"lucre", +"lucy", +"lug", +"luge", +"luger", +"luis", +"luke", +"lull", +"lulu", +"lumbar", +"lumen", +"lump", +"lumpy", +"lunar", +"lunch", +"lund", +"lung", +"lunge", +"lura", +"lurch", +"lure", +"lurid", +"lurk", +"lush", +"lust", +"lusty", +"lute", +"lutz", +"lux", +"luxe", +"luzon", +"lv", +"lw", +"lx", +"ly", +"lydia", +"lye", +"lying", +"lykes", +"lyle", +"lyman", +"lymph", +"lynch", +"lynn", +"lynx", +"lyon", +"lyons", +"lyra", +"lyric", +"lz", +"m", +"m&m", +"m's", +"m2", +"m3", +"m4", +"m5", +"m6", +"m7", +"m8", +"m9", +"ma", +"mabel", +"mac", +"mace", +"mach", +"macho", +"mack", +"mackey", +"macon", +"macro", +"mad", +"madam", +"made", +"madman", +"madsen", +"mae", +"magi", +"magic", +"magma", +"magna", +"magog", +"maid", +"maier", +"mail", +"maim", +"main", +"maine", +"major", +"make", +"malady", +"malay", +"male", +"mali", +"mall", +"malt", +"malta", +"mambo", +"mamma", +"mammal", +"man", +"mana", +"manama", +"mane", +"mange", +"mania", +"manic", +"mann", +"manna", +"manor", +"mans", +"manse", +"mantle", +"many", +"mao", +"maori", +"map", +"maple", +"mar", +"marc", +"march", +"marco", +"marcy", +"mardi", +"mare", +"margo", +"maria", +"marie", +"marin", +"marine", +"mario", +"mark", +"marks", +"marlin", +"marrow", +"marry", +"mars", +"marsh", +"mart", +"marty", +"marx", +"mary", +"maser", +"mash", +"mask", +"mason", +"masque", +"mass", +"mast", +"mat", +"match", +"mate", +"mateo", +"mater", +"math", +"matte", +"maul", +"mauve", +"mavis", +"maw", +"mawr", +"max", +"maxim", +"maxima", +"may", +"maya", +"maybe", +"mayer", +"mayhem", +"mayo", +"mayor", +"mayst", +"mazda", +"maze", +"mb", +"mba", +"mc", +"mccoy", +"mcgee", +"mckay", +"mckee", +"mcleod", +"md", +"me", +"mead", +"meal", +"mealy", +"mean", +"meant", +"meat", +"meaty", +"mecca", +"mecum", +"medal", +"medea", +"media", +"medic", +"medley", +"meek", +"meet", +"meg", +"mega", +"meier", +"meir", +"mel", +"meld", +"melee", +"mellow", +"melon", +"melt", +"memo", +"memoir", +"men", +"mend", +"menlo", +"menu", +"merck", +"mercy", +"mere", +"merge", +"merit", +"merle", +"merry", +"mesa", +"mescal", +"mesh", +"meson", +"mess", +"messy", +"met", +"metal", +"mete", +"meter", +"metro", +"mew", +"meyer", +"meyers", +"mezzo", +"mf", +"mg", +"mh", +"mi", +"miami", +"mica", +"mice", +"mickey", +"micky", +"micro", +"mid", +"midas", +"midge", +"midst", +"mien", +"miff", +"mig", +"might", +"mike", +"mila", +"milan", +"milch", +"mild", +"mildew", +"mile", +"miles", +"milk", +"milky", +"mill", +"mills", +"milt", +"mimi", +"mimic", +"mince", +"mind", +"mine", +"mini", +"minim", +"mink", +"minnow", +"minor", +"minos", +"minot", +"minsk", +"mint", +"minus", +"mira", +"mirage", +"mire", +"mirth", +"miser", +"misery", +"miss", +"missy", +"mist", +"misty", +"mit", +"mite", +"mitre", +"mitt", +"mix", +"mixup", +"mizar", +"mj", +"mk", +"ml", +"mm", +"mmm", +"mmmm", +"mn", +"mno", +"mo", +"moan", +"moat", +"mob", +"mobil", +"mock", +"modal", +"mode", +"model", +"modem", +"modish", +"moe", +"moen", +"mohr", +"moire", +"moist", +"molal", +"molar", +"mold", +"mole", +"moll", +"mollie", +"molly", +"molt", +"molten", +"mommy", +"mona", +"monad", +"mondo", +"monel", +"money", +"monic", +"monk", +"mont", +"monte", +"month", +"monty", +"moo", +"mood", +"moody", +"moon", +"moor", +"moore", +"moose", +"moot", +"mop", +"moral", +"morale", +"moran", +"more", +"morel", +"morn", +"moron", +"morse", +"morsel", +"mort", +"mosaic", +"moser", +"moses", +"moss", +"mossy", +"most", +"mot", +"motel", +"motet", +"moth", +"mother", +"motif", +"motor", +"motto", +"mould", +"mound", +"mount", +"mourn", +"mouse", +"mousy", +"mouth", +"move", +"movie", +"mow", +"moyer", +"mp", +"mph", +"mq", +"mr", +"mrs", +"ms", +"mt", +"mu", +"much", +"muck", +"mucus", +"mud", +"mudd", +"muddy", +"muff", +"muffin", +"mug", +"muggy", +"mugho", +"muir", +"mulch", +"mulct", +"mule", +"mull", +"multi", +"mum", +"mummy", +"munch", +"mung", +"munson", +"muon", +"muong", +"mural", +"muriel", +"murk", +"murky", +"murre", +"muse", +"mush", +"mushy", +"music", +"musk", +"muslim", +"must", +"musty", +"mute", +"mutt", +"muzak", +"muzo", +"mv", +"mw", +"mx", +"my", +"myel", +"myers", +"mylar", +"mynah", +"myopia", +"myra", +"myron", +"myrrh", +"myself", +"myth", +"mz", +"n", +"n's", +"n2", +"n3", +"n4", +"n5", +"n6", +"n7", +"n8", +"n9", +"na", +"naacp", +"nab", +"nadir", +"nag", +"nagoya", +"nagy", +"naiad", +"nail", +"nair", +"naive", +"naked", +"name", +"nan", +"nancy", +"naomi", +"nap", +"nary", +"nasa", +"nasal", +"nash", +"nasty", +"nat", +"natal", +"nate", +"nato", +"natty", +"nature", +"naval", +"nave", +"navel", +"navy", +"nay", +"nazi", +"nb", +"nbc", +"nbs", +"nc", +"ncaa", +"ncr", +"nd", +"ne", +"neal", +"near", +"neat", +"neath", +"neck", +"ned", +"nee", +"need", +"needy", +"neff", +"negate", +"negro", +"nehru", +"neil", +"nell", +"nelsen", +"neon", +"nepal", +"nero", +"nerve", +"ness", +"nest", +"net", +"neuron", +"neva", +"neve", +"new", +"newel", +"newt", +"next", +"nf", +"ng", +"nh", +"ni", +"nib", +"nibs", +"nice", +"nicety", +"niche", +"nick", +"niece", +"niger", +"nigh", +"night", +"nih", +"nikko", +"nil", +"nile", +"nimbus", +"nimh", +"nina", +"nine", +"ninth", +"niobe", +"nip", +"nit", +"nitric", +"nitty", +"nixon", +"nj", +"nk", +"nl", +"nm", +"nn", +"nnn", +"nnnn", +"no", +"noaa", +"noah", +"nob", +"nobel", +"noble", +"nod", +"nodal", +"node", +"noel", +"noise", +"noisy", +"nolan", +"noll", +"nolo", +"nomad", +"non", +"nonce", +"none", +"nook", +"noon", +"noose", +"nop", +"nor", +"nora", +"norm", +"norma", +"north", +"norway", +"nose", +"not", +"notch", +"note", +"notre", +"noun", +"nov", +"nova", +"novak", +"novel", +"novo", +"now", +"np", +"nq", +"nr", +"nrc", +"ns", +"nsf", +"nt", +"ntis", +"nu", +"nuance", +"nubia", +"nuclei", +"nude", +"nudge", +"null", +"numb", +"nun", +"nurse", +"nut", +"nv", +"nw", +"nx", +"ny", +"nyc", +"nylon", +"nymph", +"nyu", +"nz", +"o", +"o'er", +"o's", +"o2", +"o3", +"o4", +"o5", +"o6", +"o7", +"o8", +"o9", +"oa", +"oaf", +"oak", +"oaken", +"oakley", +"oar", +"oases", +"oasis", +"oat", +"oath", +"ob", +"obese", +"obey", +"objet", +"oboe", +"oc", +"occur", +"ocean", +"oct", +"octal", +"octave", +"octet", +"od", +"odd", +"ode", +"odin", +"odium", +"oe", +"of", +"off", +"offal", +"offend", +"offer", +"oft", +"often", +"og", +"ogden", +"ogle", +"ogre", +"oh", +"ohio", +"ohm", +"ohmic", +"oi", +"oil", +"oily", +"oint", +"oj", +"ok", +"okay", +"ol", +"olaf", +"olav", +"old", +"olden", +"oldy", +"olga", +"olin", +"olive", +"olsen", +"olson", +"om", +"omaha", +"oman", +"omega", +"omen", +"omit", +"on", +"once", +"one", +"onion", +"only", +"onset", +"onto", +"onus", +"onward", +"onyx", +"oo", +"ooo", +"oooo", +"ooze", +"op", +"opal", +"opec", +"opel", +"open", +"opera", +"opium", +"opt", +"optic", +"opus", +"oq", +"or", +"oral", +"orate", +"orb", +"orbit", +"orchid", +"ordain", +"order", +"ore", +"organ", +"orgy", +"orin", +"orion", +"ornery", +"orono", +"orr", +"os", +"osaka", +"oscar", +"osier", +"oslo", +"ot", +"other", +"otis", +"ott", +"otter", +"otto", +"ou", +"ouch", +"ought", +"ounce", +"our", +"oust", +"out", +"ouvre", +"ouzel", +"ouzo", +"ov", +"ova", +"oval", +"ovary", +"ovate", +"oven", +"over", +"overt", +"ovid", +"ow", +"owe", +"owens", +"owing", +"owl", +"owly", +"own", +"ox", +"oxen", +"oxeye", +"oxide", +"oxnard", +"oy", +"oz", +"ozark", +"ozone", +"p", +"p's", +"p2", +"p3", +"p4", +"p5", +"p6", +"p7", +"p8", +"p9", +"pa", +"pablo", +"pabst", +"pace", +"pack", +"packet", +"pact", +"pad", +"paddy", +"padre", +"paean", +"pagan", +"page", +"paid", +"pail", +"pain", +"paine", +"paint", +"pair", +"pal", +"pale", +"pall", +"palm", +"palo", +"palsy", +"pam", +"pampa", +"pan", +"panama", +"panda", +"pane", +"panel", +"pang", +"panic", +"pansy", +"pant", +"panty", +"paoli", +"pap", +"papa", +"papal", +"papaw", +"paper", +"pappy", +"papua", +"par", +"parch", +"pardon", +"pare", +"pareto", +"paris", +"park", +"parke", +"parks", +"parr", +"parry", +"parse", +"part", +"party", +"pascal", +"pasha", +"paso", +"pass", +"passe", +"past", +"paste", +"pasty", +"pat", +"patch", +"pate", +"pater", +"path", +"patio", +"patsy", +"patti", +"patton", +"patty", +"paul", +"paula", +"pauli", +"paulo", +"pause", +"pave", +"paw", +"pawn", +"pax", +"pay", +"payday", +"payne", +"paz", +"pb", +"pbs", +"pc", +"pd", +"pe", +"pea", +"peace", +"peach", +"peak", +"peaky", +"peal", +"peale", +"pear", +"pearl", +"pease", +"peat", +"pebble", +"pecan", +"peck", +"pecos", +"pedal", +"pedro", +"pee", +"peed", +"peek", +"peel", +"peep", +"peepy", +"peer", +"peg", +"peggy", +"pelt", +"pen", +"penal", +"pence", +"pencil", +"pend", +"penh", +"penn", +"penna", +"penny", +"pent", +"peony", +"pep", +"peppy", +"pepsi", +"per", +"perch", +"percy", +"perez", +"peril", +"perk", +"perky", +"perle", +"perry", +"persia", +"pert", +"perth", +"peru", +"peruse", +"pest", +"peste", +"pet", +"petal", +"pete", +"peter", +"petit", +"petri", +"petty", +"pew", +"pewee", +"pf", +"pg", +"ph", +"ph.d", +"phage", +"phase", +"phd", +"phenol", +"phi", +"phil", +"phlox", +"phon", +"phone", +"phony", +"photo", +"phyla", +"physic", +"pi", +"piano", +"pica", +"pick", +"pickup", +"picky", +"pie", +"piece", +"pier", +"pierce", +"piety", +"pig", +"piggy", +"pike", +"pile", +"pill", +"pilot", +"pimp", +"pin", +"pinch", +"pine", +"ping", +"pinion", +"pink", +"pint", +"pinto", +"pion", +"piotr", +"pious", +"pip", +"pipe", +"piper", +"pique", +"pit", +"pitch", +"pith", +"pithy", +"pitney", +"pitt", +"pity", +"pius", +"pivot", +"pixel", +"pixy", +"pizza", +"pj", +"pk", +"pl", +"place", +"plague", +"plaid", +"plain", +"plan", +"plane", +"plank", +"plant", +"plasm", +"plat", +"plate", +"plato", +"play", +"playa", +"plaza", +"plea", +"plead", +"pleat", +"pledge", +"pliny", +"plod", +"plop", +"plot", +"plow", +"pluck", +"plug", +"plum", +"plumb", +"plume", +"plump", +"plunk", +"plus", +"plush", +"plushy", +"pluto", +"ply", +"pm", +"pn", +"po", +"poach", +"pobox", +"pod", +"podge", +"podia", +"poe", +"poem", +"poesy", +"poet", +"poetry", +"pogo", +"poi", +"point", +"poise", +"poke", +"pol", +"polar", +"pole", +"police", +"polio", +"polis", +"polk", +"polka", +"poll", +"polo", +"pomona", +"pomp", +"ponce", +"pond", +"pong", +"pont", +"pony", +"pooch", +"pooh", +"pool", +"poole", +"poop", +"poor", +"pop", +"pope", +"poppy", +"porch", +"pore", +"pork", +"porous", +"port", +"porte", +"portia", +"porto", +"pose", +"posey", +"posh", +"posit", +"posse", +"post", +"posy", +"pot", +"potts", +"pouch", +"pound", +"pour", +"pout", +"pow", +"powder", +"power", +"pp", +"ppm", +"ppp", +"pppp", +"pq", +"pqr", +"pr", +"prado", +"pram", +"prank", +"pratt", +"pray", +"preen", +"prefix", +"prep", +"press", +"prexy", +"prey", +"priam", +"price", +"prick", +"pride", +"prig", +"prim", +"prima", +"prime", +"primp", +"prince", +"print", +"prior", +"prism", +"prissy", +"privy", +"prize", +"pro", +"probe", +"prod", +"prof", +"prom", +"prone", +"prong", +"proof", +"prop", +"propyl", +"prose", +"proud", +"prove", +"prow", +"prowl", +"proxy", +"prune", +"pry", +"ps", +"psalm", +"psi", +"psych", +"pt", +"pta", +"pu", +"pub", +"puck", +"puddly", +"puerto", +"puff", +"puffy", +"pug", +"pugh", +"puke", +"pull", +"pulp", +"pulse", +"puma", +"pump", +"pun", +"punch", +"punic", +"punish", +"punk", +"punky", +"punt", +"puny", +"pup", +"pupal", +"pupil", +"puppy", +"pure", +"purge", +"purl", +"purr", +"purse", +"pus", +"pusan", +"pusey", +"push", +"pussy", +"put", +"putt", +"putty", +"pv", +"pvc", +"pw", +"px", +"py", +"pygmy", +"pyle", +"pyre", +"pyrex", +"pyrite", +"pz", +"q", +"q's", +"q2", +"q3", +"q4", +"q5", +"q6", +"q7", +"q8", +"q9", +"qa", +"qatar", +"qb", +"qc", +"qd", +"qe", +"qed", +"qf", +"qg", +"qh", +"qi", +"qj", +"qk", +"ql", +"qm", +"qn", +"qo", +"qp", +"qq", +"qqq", +"qqqq", +"qr", +"qrs", +"qs", +"qt", +"qu", +"qua", +"quack", +"quad", +"quaff", +"quail", +"quake", +"qualm", +"quark", +"quarry", +"quart", +"quash", +"quasi", +"quay", +"queasy", +"queen", +"queer", +"quell", +"query", +"quest", +"queue", +"quick", +"quid", +"quiet", +"quill", +"quilt", +"quinn", +"quint", +"quip", +"quirk", +"quirt", +"quit", +"quite", +"quito", +"quiz", +"quo", +"quod", +"quota", +"quote", +"qv", +"qw", +"qx", +"qy", +"qz", +"r", +"r&d", +"r's", +"r2", +"r3", +"r4", +"r5", +"r6", +"r7", +"r8", +"r9", +"ra", +"rabat", +"rabbi", +"rabbit", +"rabid", +"rabin", +"race", +"rack", +"racy", +"radar", +"radii", +"radio", +"radium", +"radix", +"radon", +"rae", +"rafael", +"raft", +"rag", +"rage", +"raid", +"rail", +"rain", +"rainy", +"raise", +"raj", +"rajah", +"rake", +"rally", +"ralph", +"ram", +"raman", +"ramo", +"ramp", +"ramsey", +"ran", +"ranch", +"rand", +"randy", +"rang", +"range", +"rangy", +"rank", +"rant", +"raoul", +"rap", +"rape", +"rapid", +"rapt", +"rare", +"rasa", +"rascal", +"rash", +"rasp", +"rat", +"rata", +"rate", +"rater", +"ratio", +"rattle", +"raul", +"rave", +"ravel", +"raven", +"raw", +"ray", +"raze", +"razor", +"rb", +"rc", +"rca", +"rd", +"re", +"reach", +"read", +"ready", +"reagan", +"real", +"realm", +"ream", +"reap", +"rear", +"reave", +"reb", +"rebel", +"rebut", +"recipe", +"reck", +"recur", +"red", +"redeem", +"reduce", +"reed", +"reedy", +"reef", +"reek", +"reel", +"reese", +"reeve", +"refer", +"regal", +"regina", +"regis", +"reich", +"reid", +"reign", +"rein", +"relax", +"relay", +"relic", +"reman", +"remedy", +"remit", +"remus", +"rena", +"renal", +"rend", +"rene", +"renown", +"rent", +"rep", +"repel", +"repent", +"resin", +"resort", +"rest", +"ret", +"retch", +"return", +"reub", +"rev", +"reveal", +"revel", +"rever", +"revet", +"revved", +"rex", +"rf", +"rg", +"rh", +"rhea", +"rheum", +"rhine", +"rhino", +"rho", +"rhoda", +"rhode", +"rhyme", +"ri", +"rib", +"rica", +"rice", +"rich", +"rick", +"rico", +"rid", +"ride", +"ridge", +"rifle", +"rift", +"rig", +"riga", +"rigel", +"riggs", +"right", +"rigid", +"riley", +"rill", +"rilly", +"rim", +"rime", +"rimy", +"ring", +"rink", +"rinse", +"rio", +"riot", +"rip", +"ripe", +"ripen", +"ripley", +"rise", +"risen", +"risk", +"risky", +"rite", +"ritz", +"rival", +"riven", +"river", +"rivet", +"riyadh", +"rj", +"rk", +"rl", +"rm", +"rn", +"ro", +"roach", +"road", +"roam", +"roar", +"roast", +"rob", +"robe", +"robin", +"robot", +"rock", +"rocket", +"rocky", +"rod", +"rode", +"rodeo", +"roe", +"roger", +"rogue", +"roil", +"role", +"roll", +"roman", +"rome", +"romeo", +"romp", +"ron", +"rondo", +"rood", +"roof", +"rook", +"rookie", +"rooky", +"room", +"roomy", +"roost", +"root", +"rope", +"rosa", +"rose", +"rosen", +"ross", +"rosy", +"rot", +"rotc", +"roth", +"rotor", +"rouge", +"rough", +"round", +"rouse", +"rout", +"route", +"rove", +"row", +"rowdy", +"rowe", +"roy", +"royal", +"royce", +"rp", +"rpm", +"rq", +"rr", +"rrr", +"rrrr", +"rs", +"rst", +"rsvp", +"rt", +"ru", +"ruanda", +"rub", +"rube", +"ruben", +"rubin", +"rubric", +"ruby", +"ruddy", +"rude", +"rudy", +"rue", +"rufus", +"rug", +"ruin", +"rule", +"rum", +"rumen", +"rummy", +"rump", +"rumpus", +"run", +"rune", +"rung", +"runge", +"runic", +"runt", +"runty", +"rupee", +"rural", +"ruse", +"rush", +"rusk", +"russ", +"russo", +"rust", +"rusty", +"rut", +"ruth", +"rutty", +"rv", +"rw", +"rx", +"ry", +"ryan", +"ryder", +"rye", +"rz", +"s", +"s's", +"s2", +"s3", +"s4", +"s5", +"s6", +"s7", +"s8", +"s9", +"sa", +"sabine", +"sable", +"sabra", +"sac", +"sachs", +"sack", +"sad", +"saddle", +"sadie", +"safari", +"safe", +"sag", +"saga", +"sage", +"sago", +"said", +"sail", +"saint", +"sake", +"sal", +"salad", +"sale", +"salem", +"saline", +"salk", +"salle", +"sally", +"salon", +"salt", +"salty", +"salve", +"salvo", +"sam", +"samba", +"same", +"sammy", +"samoa", +"samuel", +"san", +"sana", +"sand", +"sandal", +"sandy", +"sane", +"sang", +"sank", +"sans", +"santa", +"santo", +"sao", +"sap", +"sappy", +"sara", +"sarah", +"saran", +"sari", +"sash", +"sat", +"satan", +"satin", +"satyr", +"sauce", +"saucy", +"saud", +"saudi", +"saul", +"sault", +"saute", +"save", +"savoy", +"savvy", +"saw", +"sawyer", +"sax", +"saxon", +"say", +"sb", +"sc", +"scab", +"scala", +"scald", +"scale", +"scalp", +"scam", +"scamp", +"scan", +"scant", +"scar", +"scare", +"scarf", +"scary", +"scat", +"scaup", +"scene", +"scent", +"school", +"scion", +"scm", +"scoff", +"scold", +"scoop", +"scoot", +"scope", +"scops", +"score", +"scoria", +"scorn", +"scot", +"scott", +"scour", +"scout", +"scowl", +"scram", +"scrap", +"scrape", +"screw", +"scrim", +"scrub", +"scuba", +"scud", +"scuff", +"scull", +"scum", +"scurry", +"sd", +"se", +"sea", +"seal", +"seam", +"seamy", +"sean", +"sear", +"sears", +"season", +"seat", +"sec", +"secant", +"sect", +"sedan", +"seder", +"sedge", +"see", +"seed", +"seedy", +"seek", +"seem", +"seen", +"seep", +"seethe", +"seize", +"self", +"sell", +"selma", +"semi", +"sen", +"send", +"seneca", +"senor", +"sense", +"sent", +"sentry", +"seoul", +"sepal", +"sepia", +"sepoy", +"sept", +"septa", +"sequin", +"sera", +"serf", +"serge", +"serif", +"serum", +"serve", +"servo", +"set", +"seth", +"seton", +"setup", +"seven", +"sever", +"severe", +"sew", +"sewn", +"sex", +"sexy", +"sf", +"sg", +"sh", +"shack", +"shad", +"shade", +"shady", +"shafer", +"shaft", +"shag", +"shah", +"shake", +"shaken", +"shako", +"shaky", +"shale", +"shall", +"sham", +"shame", +"shank", +"shape", +"shard", +"share", +"shari", +"shark", +"sharp", +"shave", +"shaw", +"shawl", +"shay", +"she", +"she'd", +"shea", +"sheaf", +"shear", +"sheath", +"shed", +"sheen", +"sheep", +"sheer", +"sheet", +"sheik", +"shelf", +"shell", +"shied", +"shift", +"shill", +"shim", +"shin", +"shine", +"shinto", +"shiny", +"ship", +"shire", +"shirk", +"shirt", +"shish", +"shiv", +"shoal", +"shock", +"shod", +"shoe", +"shoji", +"shone", +"shoo", +"shook", +"shoot", +"shop", +"shore", +"short", +"shot", +"shout", +"shove", +"show", +"shown", +"showy", +"shrank", +"shred", +"shrew", +"shrike", +"shrub", +"shrug", +"shu", +"shuck", +"shun", +"shunt", +"shut", +"shy", +"si", +"sial", +"siam", +"sian", +"sib", +"sibley", +"sibyl", +"sic", +"sick", +"side", +"sidle", +"siege", +"siena", +"sieve", +"sift", +"sigh", +"sight", +"sigma", +"sign", +"signal", +"signor", +"silas", +"silk", +"silky", +"sill", +"silly", +"silo", +"silt", +"silty", +"sima", +"simon", +"simons", +"sims", +"sin", +"sinai", +"since", +"sine", +"sinew", +"sing", +"singe", +"sinh", +"sink", +"sinus", +"sioux", +"sip", +"sir", +"sire", +"siren", +"sis", +"sisal", +"sit", +"site", +"situ", +"situs", +"siva", +"six", +"sixgun", +"sixth", +"sixty", +"size", +"sj", +"sk", +"skat", +"skate", +"skeet", +"skew", +"ski", +"skid", +"skied", +"skiff", +"skill", +"skim", +"skimp", +"skimpy", +"skin", +"skip", +"skirt", +"skit", +"skulk", +"skull", +"skunk", +"sky", +"skye", +"sl", +"slab", +"slack", +"slag", +"slain", +"slake", +"slam", +"slang", +"slant", +"slap", +"slash", +"slat", +"slate", +"slater", +"slav", +"slave", +"slay", +"sled", +"sleek", +"sleep", +"sleet", +"slept", +"slew", +"slice", +"slick", +"slid", +"slide", +"slim", +"slime", +"slimy", +"sling", +"slip", +"slit", +"sliver", +"sloan", +"slob", +"sloe", +"slog", +"sloop", +"slop", +"slope", +"slosh", +"slot", +"sloth", +"slow", +"slug", +"sluice", +"slum", +"slump", +"slung", +"slur", +"slurp", +"sly", +"sm", +"smack", +"small", +"smart", +"smash", +"smear", +"smell", +"smelt", +"smile", +"smirk", +"smith", +"smithy", +"smog", +"smoke", +"smoky", +"smug", +"smut", +"sn", +"snack", +"snafu", +"snag", +"snail", +"snake", +"snap", +"snare", +"snark", +"snarl", +"snatch", +"sneak", +"sneer", +"snell", +"snick", +"sniff", +"snip", +"snipe", +"snob", +"snook", +"snoop", +"snore", +"snort", +"snout", +"snow", +"snowy", +"snub", +"snuff", +"snug", +"so", +"soak", +"soap", +"soapy", +"soar", +"sob", +"sober", +"social", +"sock", +"sod", +"soda", +"sofa", +"sofia", +"soft", +"soften", +"soggy", +"soil", +"sol", +"solar", +"sold", +"sole", +"solemn", +"solid", +"solo", +"solon", +"solve", +"soma", +"somal", +"some", +"son", +"sonar", +"song", +"sonic", +"sonny", +"sonora", +"sony", +"soon", +"soot", +"sooth", +"sop", +"sora", +"sorb", +"sore", +"sorry", +"sort", +"sos", +"sou", +"sough", +"soul", +"sound", +"soup", +"sour", +"source", +"sousa", +"south", +"sow", +"sown", +"soy", +"soya", +"sp", +"spa", +"space", +"spade", +"spain", +"span", +"spar", +"spare", +"sparge", +"spark", +"spasm", +"spat", +"spate", +"spawn", +"spay", +"speak", +"spear", +"spec", +"speck", +"sped", +"speed", +"spell", +"spend", +"spent", +"sperm", +"sperry", +"spew", +"spica", +"spice", +"spicy", +"spike", +"spiky", +"spill", +"spilt", +"spin", +"spine", +"spiny", +"spire", +"spiro", +"spit", +"spite", +"spitz", +"splat", +"splay", +"spline", +"split", +"spoil", +"spoke", +"spoof", +"spook", +"spooky", +"spool", +"spoon", +"spore", +"sport", +"spot", +"spout", +"sprain", +"spray", +"spree", +"sprig", +"spruce", +"sprue", +"spud", +"spume", +"spun", +"spunk", +"spur", +"spurn", +"spurt", +"spy", +"sq", +"squad", +"squat", +"squaw", +"squibb", +"squid", +"squint", +"sr", +"sri", +"ss", +"sss", +"ssss", +"sst", +"st", +"st.", +"stab", +"stack", +"stacy", +"staff", +"stag", +"stage", +"stagy", +"stahl", +"staid", +"stain", +"stair", +"stake", +"stale", +"stalk", +"stall", +"stamp", +"stan", +"stance", +"stand", +"stank", +"staph", +"star", +"stare", +"stark", +"starr", +"start", +"stash", +"state", +"statue", +"stave", +"stay", +"stead", +"steak", +"steal", +"steam", +"steed", +"steel", +"steele", +"steen", +"steep", +"steer", +"stein", +"stella", +"stem", +"step", +"stern", +"steve", +"stew", +"stick", +"stiff", +"stile", +"still", +"stilt", +"sting", +"stingy", +"stink", +"stint", +"stir", +"stock", +"stoic", +"stoke", +"stole", +"stomp", +"stone", +"stony", +"stood", +"stool", +"stoop", +"stop", +"store", +"storey", +"stork", +"storm", +"story", +"stout", +"stove", +"stow", +"strafe", +"strap", +"straw", +"stray", +"strewn", +"strip", +"stroll", +"strom", +"strop", +"strum", +"strut", +"stu", +"stuart", +"stub", +"stuck", +"stud", +"study", +"stuff", +"stuffy", +"stump", +"stun", +"stung", +"stunk", +"stunt", +"sturm", +"style", +"styli", +"styx", +"su", +"suave", +"sub", +"subtly", +"such", +"suck", +"sud", +"sudan", +"suds", +"sue", +"suey", +"suez", +"sugar", +"suit", +"suite", +"sulfa", +"sulk", +"sulky", +"sully", +"sultry", +"sum", +"sumac", +"summon", +"sun", +"sung", +"sunk", +"sunny", +"sunset", +"suny", +"sup", +"super", +"supra", +"sure", +"surf", +"surge", +"sus", +"susan", +"sushi", +"susie", +"sutton", +"sv", +"sw", +"swab", +"swag", +"swain", +"swam", +"swami", +"swamp", +"swampy", +"swan", +"swank", +"swap", +"swarm", +"swart", +"swat", +"swath", +"sway", +"swear", +"sweat", +"sweaty", +"swede", +"sweep", +"sweet", +"swell", +"swelt", +"swept", +"swift", +"swig", +"swim", +"swine", +"swing", +"swipe", +"swirl", +"swish", +"swiss", +"swoop", +"sword", +"swore", +"sworn", +"swum", +"swung", +"sx", +"sy", +"sybil", +"sykes", +"sylow", +"sylvan", +"synge", +"synod", +"syria", +"syrup", +"sz", +"t", +"t's", +"t2", +"t3", +"t4", +"t5", +"t6", +"t7", +"t8", +"t9", +"ta", +"tab", +"table", +"taboo", +"tabu", +"tabula", +"tacit", +"tack", +"tacky", +"tacoma", +"tact", +"tad", +"taffy", +"taft", +"tag", +"tahoe", +"tail", +"taint", +"take", +"taken", +"talc", +"tale", +"talk", +"talky", +"tall", +"tallow", +"tally", +"talon", +"talus", +"tam", +"tame", +"tamp", +"tampa", +"tan", +"tang", +"tango", +"tangy", +"tanh", +"tank", +"tansy", +"tanya", +"tao", +"taos", +"tap", +"tapa", +"tape", +"taper", +"tapir", +"tapis", +"tappa", +"tar", +"tara", +"tardy", +"tariff", +"tarry", +"tart", +"task", +"tass", +"taste", +"tasty", +"tat", +"tate", +"tater", +"tattle", +"tatty", +"tau", +"taunt", +"taut", +"tavern", +"tawny", +"tax", +"taxi", +"tb", +"tc", +"td", +"te", +"tea", +"teach", +"teal", +"team", +"tear", +"tease", +"teat", +"tech", +"tecum", +"ted", +"teddy", +"tee", +"teem", +"teen", +"teensy", +"teet", +"teeth", +"telex", +"tell", +"tempo", +"tempt", +"ten", +"tend", +"tenet", +"tenney", +"tenon", +"tenor", +"tense", +"tensor", +"tent", +"tenth", +"tepee", +"tepid", +"term", +"tern", +"terra", +"terre", +"terry", +"terse", +"tess", +"test", +"testy", +"tete", +"texan", +"texas", +"text", +"tf", +"tg", +"th", +"thai", +"than", +"thank", +"that", +"thaw", +"the", +"thea", +"thee", +"theft", +"their", +"them", +"theme", +"then", +"there", +"these", +"theta", +"they", +"thick", +"thief", +"thigh", +"thin", +"thine", +"thing", +"think", +"third", +"this", +"thong", +"thor", +"thorn", +"thorny", +"those", +"thou", +"thread", +"three", +"threw", +"throb", +"throes", +"throw", +"thrum", +"thud", +"thug", +"thule", +"thumb", +"thump", +"thus", +"thy", +"thyme", +"ti", +"tiber", +"tibet", +"tibia", +"tic", +"tick", +"ticket", +"tid", +"tidal", +"tidbit", +"tide", +"tidy", +"tie", +"tied", +"tier", +"tift", +"tiger", +"tight", +"til", +"tilde", +"tile", +"till", +"tilt", +"tilth", +"tim", +"time", +"timex", +"timid", +"timon", +"tin", +"tina", +"tine", +"tinge", +"tint", +"tiny", +"tioga", +"tip", +"tipoff", +"tippy", +"tipsy", +"tire", +"tit", +"titan", +"tithe", +"title", +"titus", +"tj", +"tk", +"tl", +"tm", +"tn", +"tnt", +"to", +"toad", +"toady", +"toast", +"toby", +"today", +"todd", +"toe", +"tofu", +"tog", +"togo", +"togs", +"toil", +"toilet", +"token", +"tokyo", +"told", +"toll", +"tom", +"tomb", +"tome", +"tommy", +"ton", +"tonal", +"tone", +"tong", +"toni", +"tonic", +"tonk", +"tonsil", +"tony", +"too", +"took", +"tool", +"toot", +"tooth", +"top", +"topaz", +"topic", +"topple", +"topsy", +"tor", +"torah", +"torch", +"tore", +"tori", +"torn", +"torr", +"torso", +"tort", +"torus", +"tory", +"toss", +"tot", +"total", +"tote", +"totem", +"touch", +"tough", +"tour", +"tout", +"tow", +"towel", +"tower", +"town", +"toxic", +"toxin", +"toy", +"tp", +"tq", +"tr", +"trace", +"track", +"tract", +"tracy", +"trade", +"trag", +"trail", +"train", +"trait", +"tram", +"tramp", +"trap", +"trash", +"trawl", +"tray", +"tread", +"treat", +"treble", +"tree", +"trek", +"trench", +"trend", +"tress", +"triad", +"trial", +"tribe", +"trick", +"tried", +"trig", +"trill", +"trim", +"trio", +"trip", +"tripe", +"trite", +"triton", +"trod", +"troll", +"troop", +"trot", +"trout", +"troy", +"truce", +"truck", +"trudge", +"trudy", +"TRUE", +"truly", +"trump", +"trunk", +"truss", +"trust", +"truth", +"trw", +"try", +"ts", +"tsar", +"tt", +"ttl", +"ttt", +"tttt", +"tty", +"tu", +"tub", +"tuba", +"tube", +"tuck", +"tudor", +"tuff", +"tuft", +"tug", +"tulane", +"tulip", +"tulle", +"tulsa", +"tum", +"tun", +"tuna", +"tune", +"tung", +"tunic", +"tunis", +"tunnel", +"tuple", +"turf", +"turin", +"turk", +"turn", +"turvy", +"tusk", +"tussle", +"tutor", +"tutu", +"tuv", +"tv", +"tva", +"tw", +"twa", +"twain", +"tweak", +"tweed", +"twice", +"twig", +"twill", +"twin", +"twine", +"twirl", +"twist", +"twisty", +"twit", +"two", +"twx", +"tx", +"ty", +"tyburn", +"tying", +"tyler", +"type", +"typic", +"typo", +"tyson", +"tz", +"u", +"u's", +"u2", +"u3", +"u4", +"u5", +"u6", +"u7", +"u8", +"u9", +"ua", +"ub", +"uc", +"ucla", +"ud", +"ue", +"uf", +"ug", +"ugh", +"ugly", +"uh", +"ui", +"uj", +"uk", +"ul", +"ulan", +"ulcer", +"ultra", +"um", +"umber", +"umbra", +"umpire", +"un", +"unary", +"uncle", +"under", +"unify", +"union", +"unit", +"unite", +"unity", +"unix", +"until", +"uo", +"up", +"upend", +"uphold", +"upon", +"upper", +"uproar", +"upset", +"uptake", +"upton", +"uq", +"ur", +"urban", +"urbane", +"urea", +"urge", +"uri", +"urine", +"uris", +"urn", +"ursa", +"us", +"usa", +"usaf", +"usage", +"usc", +"usda", +"use", +"useful", +"usgs", +"usher", +"usia", +"usn", +"usps", +"ussr", +"usual", +"usurp", +"usury", +"ut", +"utah", +"utica", +"utile", +"utmost", +"utter", +"uu", +"uuu", +"uuuu", +"uv", +"uvw", +"uw", +"ux", +"uy", +"uz", +"v", +"v's", +"v2", +"v3", +"v4", +"v5", +"v6", +"v7", +"v8", +"v9", +"va", +"vacua", +"vacuo", +"vade", +"vaduz", +"vague", +"vail", +"vain", +"vale", +"valet", +"valeur", +"valid", +"value", +"valve", +"vamp", +"van", +"vance", +"vane", +"vary", +"vase", +"vast", +"vat", +"vault", +"vb", +"vc", +"vd", +"ve", +"veal", +"veda", +"vee", +"veer", +"veery", +"vega", +"veil", +"vein", +"velar", +"veldt", +"vella", +"vellum", +"venal", +"vend", +"venial", +"venom", +"vent", +"venus", +"vera", +"verb", +"verde", +"verdi", +"verge", +"verity", +"verna", +"verne", +"versa", +"verse", +"verve", +"very", +"vessel", +"vest", +"vet", +"vetch", +"veto", +"vex", +"vf", +"vg", +"vh", +"vi", +"via", +"vial", +"vicar", +"vice", +"vichy", +"vicky", +"vida", +"video", +"vie", +"viet", +"view", +"vigil", +"vii", +"viii", +"vile", +"villa", +"vine", +"vinyl", +"viola", +"violet", +"virgil", +"virgo", +"virus", +"vis", +"visa", +"vise", +"visit", +"visor", +"vista", +"vita", +"vitae", +"vital", +"vito", +"vitro", +"viva", +"vivian", +"vivid", +"vivo", +"vixen", +"viz", +"vj", +"vk", +"vl", +"vm", +"vn", +"vo", +"vocal", +"vogel", +"vogue", +"voice", +"void", +"volt", +"volta", +"volvo", +"vomit", +"von", +"voss", +"vote", +"vouch", +"vow", +"vowel", +"vp", +"vq", +"vr", +"vs", +"vt", +"vu", +"vulcan", +"vv", +"vvv", +"vvvv", +"vw", +"vx", +"vy", +"vying", +"vz", +"w", +"w's", +"w2", +"w3", +"w4", +"w5", +"w6", +"w7", +"w8", +"w9", +"wa", +"waals", +"wac", +"wack", +"wacke", +"wacky", +"waco", +"wad", +"wade", +"wadi", +"wafer", +"wag", +"wage", +"waggle", +"wah", +"wahl", +"wail", +"waist", +"wait", +"waite", +"waive", +"wake", +"waken", +"waldo", +"wale", +"walk", +"walkie", +"wall", +"walls", +"wally", +"walsh", +"walt", +"walton", +"waltz", +"wan", +"wand", +"wane", +"wang", +"want", +"war", +"ward", +"ware", +"warm", +"warmth", +"warn", +"warp", +"warren", +"wart", +"warty", +"wary", +"was", +"wash", +"washy", +"wasp", +"wast", +"waste", +"watch", +"water", +"watt", +"watts", +"wave", +"wavy", +"wax", +"waxen", +"waxy", +"way", +"wayne", +"wb", +"wc", +"wd", +"we", +"we'd", +"we'll", +"we're", +"we've", +"weak", +"weal", +"wealth", +"wean", +"wear", +"weary", +"weave", +"web", +"webb", +"weber", +"weco", +"wed", +"wedge", +"wee", +"weed", +"weedy", +"week", +"weeks", +"weep", +"wehr", +"wei", +"weigh", +"weir", +"weird", +"weiss", +"welch", +"weld", +"well", +"wells", +"welsh", +"welt", +"wendy", +"went", +"wept", +"were", +"wert", +"west", +"wet", +"wf", +"wg", +"wh", +"whack", +"whale", +"wham", +"wharf", +"what", +"wheat", +"whee", +"wheel", +"whelk", +"whelm", +"whelp", +"when", +"where", +"whet", +"which", +"whiff", +"whig", +"while", +"whim", +"whine", +"whinny", +"whip", +"whir", +"whirl", +"whisk", +"whit", +"white", +"whiz", +"who", +"who'd", +"whoa", +"whole", +"whom", +"whoop", +"whoosh", +"whop", +"whose", +"whup", +"why", +"wi", +"wick", +"wide", +"widen", +"widow", +"width", +"wield", +"wier", +"wife", +"wig", +"wild", +"wile", +"wiley", +"wilkes", +"will", +"willa", +"wills", +"wilma", +"wilt", +"wily", +"win", +"wince", +"winch", +"wind", +"windy", +"wine", +"wing", +"wink", +"winnie", +"wino", +"winter", +"winy", +"wipe", +"wire", +"wiry", +"wise", +"wish", +"wishy", +"wisp", +"wispy", +"wit", +"witch", +"with", +"withe", +"withy", +"witt", +"witty", +"wive", +"wj", +"wk", +"wl", +"wm", +"wn", +"wo", +"woe", +"wok", +"woke", +"wold", +"wolf", +"wolfe", +"wolff", +"wolve", +"woman", +"womb", +"women", +"won", +"won't", +"wonder", +"wong", +"wont", +"woo", +"wood", +"woods", +"woody", +"wool", +"woozy", +"word", +"wordy", +"wore", +"work", +"world", +"worm", +"wormy", +"worn", +"worry", +"worse", +"worst", +"worth", +"wotan", +"would", +"wound", +"wove", +"woven", +"wow", +"wp", +"wq", +"wr", +"wrack", +"wrap", +"wrath", +"wreak", +"wreck", +"wrest", +"wring", +"wrist", +"writ", +"write", +"writhe", +"wrong", +"wrote", +"wry", +"ws", +"wt", +"wu", +"wuhan", +"wv", +"ww", +"www", +"wwww", +"wx", +"wxy", +"wy", +"wyatt", +"wyeth", +"wylie", +"wyman", +"wyner", +"wynn", +"wz", +"x", +"x's", +"x2", +"x3", +"x4", +"x5", +"x6", +"x7", +"x8", +"x9", +"xa", +"xb", +"xc", +"xd", +"xe", +"xenon", +"xerox", +"xf", +"xg", +"xh", +"xi", +"xj", +"xk", +"xl", +"xm", +"xn", +"xo", +"xp", +"xq", +"xr", +"xs", +"xt", +"xu", +"xv", +"xw", +"xx", +"xxx", +"xxxx", +"xy", +"xylem", +"xyz", +"xz", +"y", +"y's", +"y2", +"y3", +"y4", +"y5", +"y6", +"y7", +"y8", +"y9", +"ya", +"yacht", +"yah", +"yak", +"yale", +"yalta", +"yam", +"yamaha", +"yang", +"yank", +"yap", +"yaqui", +"yard", +"yarn", +"yates", +"yaw", +"yawl", +"yawn", +"yb", +"yc", +"yd", +"ye", +"yea", +"yeah", +"year", +"yearn", +"yeast", +"yeasty", +"yeats", +"yell", +"yelp", +"yemen", +"yen", +"yet", +"yf", +"yg", +"yh", +"yi", +"yield", +"yin", +"yip", +"yj", +"yk", +"yl", +"ym", +"ymca", +"yn", +"yo", +"yodel", +"yoder", +"yoga", +"yogi", +"yoke", +"yokel", +"yolk", +"yon", +"yond", +"yore", +"york", +"yost", +"you", +"you'd", +"young", +"your", +"youth", +"yow", +"yp", +"yq", +"yr", +"ys", +"yt", +"yu", +"yucca", +"yuck", +"yuh", +"yuki", +"yukon", +"yule", +"yv", +"yves", +"yw", +"ywca", +"yx", +"yy", +"yyy", +"yyyy", +"yz", +"z", +"z's", +"z2", +"z3", +"z4", +"z5", +"z6", +"z7", +"z8", +"z9", +"za", +"zag", +"zaire", +"zan", +"zap", +"zazen", +"zb", +"zc", +"zd", +"ze", +"zeal", +"zealot", +"zebra", +"zeiss", +"zen", +"zero", +"zest", +"zesty", +"zeta", +"zeus", +"zf", +"zg", +"zh", +"zi", +"zig", +"zilch", +"zinc", +"zing", +"zion", +"zip", +"zj", +"zk", +"zl", +"zloty", +"zm", +"zn", +"zo", +"zoe", +"zomba", +"zone", +"zoo", +"zoom", +"zorn", +"zp", +"zq", +"zr", +"zs", +"zt", +"zu", +"zurich", +"zv", +"zw", +"zx", +"zy", +"zz", +"zzz", +"zzzz", +"!", +"!!", +"""""", +"#", +"##", +"$", +"$$", +"%", +"%%", +"&", +"(", +"()", +")", +"*", +"**", +"+", +"-", +"0", +"1", +"10", +"100", +"1000", +"100th", +"101", +"101st", +"10th", +"11", +"111", +"1111", +"11th", +"12", +"123", +"1234", +"12th", +"13", +"13th", +"14", +"1492", +"14th", +"15", +"1500", +"15th", +"16", +"1600", +"16th", +"17", +"1700", +"1776", +"17th", +"18", +"1800", +"1812", +"18th", +"19", +"1900", +"1910", +"1920", +"1925", +"1930", +"1935", +"1940", +"1945", +"1950", +"1955", +"1960", +"1965", +"1970", +"1975", +"1980", +"1985", +"1990", +"1991", +"1992", +"1993", +"1994", +"1995", +"1996", +"1997", +"19th", +"1st", +"2", +"20", +"200", +"2000", +"2001", +"2020", +"20th", +"21", +"21st", +"22", +"222", +"2222", +"22nd", +"23", +"234", +"2345", +"23rd", +"24", +"2468", +"24th", +"25", +"25th", +"26", +"26th", +"27", +"27th", +"28", +"28th", +"29", +"29th", +"2a", +"2b", +"2c", +"2d", +"2e", +"2f", +"2g", +"2h", +"2i", +"2j", +"2k", +"2l", +"2m", +"2n", +"2nd", +"2o", +"2p", +"2q", +"2r", +"2s", +"2t", +"2u", +"2v", +"2w", +"2x", +"2y", +"2z", +"3", +"30", +"300", +"3000", +"30th", +"31", +"31st", +"32", +"32nd", +"33", +"333", +"3333", +"33rd", +"34", +"345", +"3456", +"34th", +"35", +"35th", +"36", +"36th", +"37", +"37th", +"38", +"38th", +"39", +"39th", +"3a", +"3b", +"3c", +"3d", +"3e", +"3f", +"3g", +"3h", +"3i", +"3j", +"3k", +"3l", +"3m", +"3n", +"3o", +"3p", +"3q", +"3r", +"3rd", +"3s", +"3t", +"3u", +"3v", +"3w", +"3x", +"3y", +"3z", +"4", +"40", +"400", +"4000", +"40th", +"41", +"41st", +"42", +"42nd", +"43", +"4321", +"43rd", +"44", +"444", +"4444", +"44th", +"45", +"456", +"4567", +"45th", +"46", +"46th", +"47", +"47th", +"48", +"48th", +"49", +"49th", +"4a", +"4b", +"4c", +"4d", +"4e", +"4f", +"4g", +"4h", +"4i", +"4j", +"4k", +"4l", +"4m", +"4n", +"4o", +"4p", +"4q", +"4r", +"4s", +"4t", +"4th", +"4u", +"4v", +"4w", +"4x", +"4y", +"4z", +"5", +"50", +"500", +"5000", +"50th", +"51", +"51st", +"52", +"52nd", +"53", +"53rd", +"54", +"54th", +"55", +"555", +"5555", +"55th", +"56", +"567", +"5678", +"56th", +"57", +"57th", +"58", +"58th", +"59", +"59th", +"5a", +"5b", +"5c", +"5d", +"5e", +"5f", +"5g", +"5h", +"5i", +"5j", +"5k", +"5l", +"5m", +"5n", +"5o", +"5p", +"5q", +"5r", +"5s", +"5t", +"5th", +"5u", +"5v", +"5w", +"5x", +"5y", +"5z", +"6", +"60", +"600", +"6000", +"60th", +"61", +"61st", +"62", +"62nd", +"63", +"63rd", +"64", +"65", +"65th", +"66", +"666", +"6666", +"66th", +"67", +"678", +"6789", +"67th", +"68", +"68th", +"69", +"69th", +"6a", +"6b", +"6c", +"6d", +"6e", +"6f", +"6g", +"6h", +"6i", +"6j", +"6k", +"6l", +"6m", +"6n", +"6o", +"6p", +"6q", +"6r", +"6s", +"6t", +"6th", +"6u", +"6v", +"6w", +"6x", +"6y", +"6z", +"7", +"70", +"700", +"7000", +"70th", +"71", +"71st", +"72", +"72nd", +"73", +"73rd", +"74", +"74th", +"75", +"75th", +"76", +"76th", +"77", +"777", +"7777", +"77th", +"78", +"789", +"78th", +"79", +"79th", +"7a", +"7b", +"7c", +"7d", +"7e", +"7f", +"7g", +"7h", +"7i", +"7j", +"7k", +"7l", +"7m", +"7n", +"7o", +"7p", +"7q", +"7r", +"7s", +"7t", +"7th", +"7u", +"7v", +"7w", +"7x", +"7y", +"7z", +"8", +"80", +"800", +"8000", +"80th", +"81", +"81st", +"82", +"82nd", +"83", +"83rd", +"84", +"84th", +"85", +"85th", +"86", +"86th", +"87", +"87th", +"88", +"888", +"8888", +"88th", +"89", +"89th", +"8a", +"8b", +"8c", +"8d", +"8e", +"8f", +"8g", +"8h", +"8i", +"8j", +"8k", +"8l", +"8m", +"8n", +"8o", +"8p", +"8q", +"8r", +"8s", +"8t", +"8th", +"8u", +"8v", +"8w", +"8x", +"8y", +"8z", +"9", +"90", +"900", +"9000", +"90th", +"91", +"91st", +"92", +"92nd", +"93", +"93rd", +"94", +"94th", +"95", +"95th", +"96", +"96th", +"97", +"97th", +"98", +"9876", +"98th", +"99", +"999", +"9999", +"99th", +"9a", +"9b", +"9c", +"9d", +"9e", +"9f", +"9g", +"9h", +"9i", +"9j", +"9k", +"9l", +"9m", +"9n", +"9o", +"9p", +"9q", +"9r", +"9s", +"9t", +"9th", +"9u", +"9v", +"9w", +"9x", +"9y", +"9z", +":", +";", +"=", +"?", +"??", +"@" }; + +const char *getDiceWd(unsigned int n) { + return Dicewds8k[n & 0X1fff]; +} diff --git a/exceptions.h b/exceptions.h new file mode 100644 index 0000000..773c574 --- /dev/null +++ b/exceptions.h @@ -0,0 +1,43 @@ +/* + exceptions.h - exception declarations for cexcept.h + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef EXCEPTIONS_H__ +#define EXCEPTIONS_H__ + +#include "cexcept.h" + +/* The simplest approach is to have all exceptions defined in one place. */ +enum exception_code { + /* general exceptions */ + no_exception = 0, /* used to exit the Try block */ + out_of_memory_exception, + system_call_failed_exception, + + /* library exceptions */ + lib_crypto_exception +}; + +define_exception_type(enum exception_code); +extern struct exception_context *the_exception_context; + +#endif /* EXCEPTIONS_H__ */ diff --git a/main.c b/main.c new file mode 100644 index 0000000..cb3b0e0 --- /dev/null +++ b/main.c @@ -0,0 +1,222 @@ +/* + main.c - main program + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include +#include +#include +#include "secure_memory.h" +#include "secure_random.h" +#include "pwgen.h" +#include "exceptions.h" + +static char rcsid[] = "$Id: main.c 1 2005-11-13 20:23:40Z zvrba $"; + +static struct exception_context exception_context; +struct exception_context *the_exception_context = &exception_context; + +static void exit_cleanup(void) +{ + SRNG_destroy((struct SRNG_st*)G_secure_memory->random_state); + secure_memory_destroy(); +} + +static void usage(const char *argv0) +{ + fprintf(stderr, "USAGE: %s <-p[e] | -A[adhsy] | -r | -s[e]> N\n", argv0); + fprintf(stderr, + "\nPASSPHRASE of N words from Diceware dictionary\n" + " -p generate passphrase\n" + " -pe generate enhanced (with symbols) passphrase\n" + "\nSKEY PASSWORD of N words from S/Key dictionary\n" + " -s generate passphrase\n" + " -se generate enhanced (with symbols) passphrase\n" + "\nASCII RANDOM of N elements (at least one option MUST be present)\n" + " -A Each letter adds the following random elements in output:\n" + " a alphanumeric characters\n" + " d decimal digits\n" + " h hexadecimal digits\n" + " s special characters\n" + " y 3-4 letter syllables\n" + "\nRAW RANDOM\n" + " -r output BASE64 encoded string of N random BITS\n" + " -k output koremutake encoding of N random BITS\n"); + exit(1); +} + +static unsigned int get_allowed_characters(const char *p) +{ + unsigned int characters = 0; + + while(*p) { + switch(*p) { + case 'a': + characters |= chr_alphanumeric; + break; + case 'd': + characters |= chr_dec_digits; + break; + case 'h': + characters |= chr_hex_digits; + break; + case 's': + characters |= chr_special; + break; + case 'y': + characters |= chr_syllables; + break; + default: + return 0; + } + ++p; + } + + /* filter out some combinations for correct entropy estimation */ + if(characters & chr_alphanumeric) + characters &= ~(chr_dec_digits | chr_hex_digits); + if(characters & chr_hex_digits) + characters &= ~chr_dec_digits; + if((characters & chr_syllables) + && (characters & (chr_alphanumeric | chr_dec_digits | chr_hex_digits))) { + characters &= ~(chr_alphanumeric | chr_dec_digits | chr_hex_digits); + characters |= chr_dec_digits; + } + + return characters; +} + +int main(int argc, char **argv) +{ + const char *getDiceWd(unsigned int); + const char *getSkeyWd(unsigned int); + unsigned int n; + unsigned int srng_state_len; + float entropy; + enum exception_code exception; + int retval = 0; + + init_exception_context(&exception_context); + + if(argc != 3) + usage(argv[0]); + + n = atoi(argv[2]); + if(n < 1) { + fprintf(stderr, "ERROR: N must be an integer > 0\n"); + usage(argv[0]); + } + + srng_state_len = SRNG_init(NULL); + if(srng_state_len > MAX_RANDOM_STATE_SIZE) { + fprintf(stderr, + "FATAL: too small MAX_RANDOM_STATE_SIZE " + "(must be at least %u)\n", srng_state_len); + return 1; + } + + Try { + secure_memory_init(); + SRNG_init((struct SRNG_st*)G_secure_memory->random_state); + + if(atexit(exit_cleanup) < 0) { + fprintf(stderr, "FATAL: can't register cleanup handlers: \n"); + perror("atexit"); + return 1; + } + + if(!strcmp(argv[1], "-p")) + entropy = pwgen_diceware( + (struct SRNG_st*)G_secure_memory->random_state, n, 0, + getDiceWd, 8192, G_secure_memory->random_numbers, + G_secure_memory->passphrase); + else if(!strcmp(argv[1], "-pe")) + entropy = pwgen_diceware( + (struct SRNG_st*)G_secure_memory->random_state, n, 1, + getDiceWd, 8192, G_secure_memory->random_numbers, + G_secure_memory->passphrase); + else if(!strcmp(argv[1], "-r")) + entropy = pwgen_raw( + (struct SRNG_st*)G_secure_memory->random_state, n, + G_secure_memory->random_numbers, + G_secure_memory->passphrase); + else if(!strcmp(argv[1], "-k")) + entropy = pwgen_koremutake( + (struct SRNG_st*)G_secure_memory->random_state, n, + G_secure_memory->random_numbers, + G_secure_memory->passphrase); + else if(!strcmp(argv[1], "-s")) + entropy = pwgen_diceware( + (struct SRNG_st*)G_secure_memory->random_state, n, 0, + getSkeyWd, 2048, G_secure_memory->random_numbers, + G_secure_memory->passphrase); + else if(!strcmp(argv[1], "-se")) + entropy = pwgen_diceware( + (struct SRNG_st*)G_secure_memory->random_state, n, 1, + getSkeyWd, 2048, G_secure_memory->random_numbers, + G_secure_memory->passphrase); + else if(!strncmp(argv[1], "-A", 2)) { + unsigned int characters = get_allowed_characters(argv[1]+2); + + if(!characters) + usage(argv[0]); + entropy = pwgen_ascii( + (struct SRNG_st*)G_secure_memory->random_state, n, + characters, G_secure_memory->random_numbers, + G_secure_memory->passphrase); + } else { + usage(argv[0]); + } + } Catch(exception) { + switch(exception) { + case out_of_memory_exception: + fprintf(stderr, "FATAL: out of memory.\n"); + retval = 1; + break; + case lib_crypto_exception: + fprintf(stderr, "FATAL: crypto library error.\n"); + retval = 1; + break; + case system_call_failed_exception: + fprintf(stderr, "FATAL: system call failed.\n"); + retval = 1; + break; + default: + fprintf(stderr, "FATAL: unhandled exception %u.\n", exception); + retval = 1; + } + } + + if(!retval) { + printf("----------------\n"); + /* + * SECURITY NOTE + * I have no idea how printf(3) is implemented and it just MIGHT copy + * some sensitive data to its own stack. + */ + printf("%s ;ENTROPY=%.2f bits\n", G_secure_memory->passphrase, + entropy); + printf("----------------\n"); + } + return retval; +} diff --git a/pwgen.c b/pwgen.c new file mode 100644 index 0000000..64cc180 --- /dev/null +++ b/pwgen.c @@ -0,0 +1,313 @@ +/* + pwgen.c - actual password generation + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include +#include "secure_random.h" +#include "pwgen.h" +#include "exceptions.h" + +static char rcsid[] = "$Id: pwgen.c 1 2005-11-13 20:23:40Z zvrba $"; + +/** + * @file + * This is intended to be the UI-independent part of password generation. + * + * @note On the programming style in this code: I'm aware that strcat() + * in a loop has quadratic performance, but here I just don't care and it + * makes my life easier. + */ + +/****************************************************************************** + * Tables and entropy constants. + *****************************************************************************/ +static const char *t_alphanumeric[36] = { + "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", + "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", + "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" +}; + +static const char *t_dec_digits[36] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", + NULL, NULL, NULL, NULL, NULL, NULL +}; + +static const char *t_hex_digits[36] = { + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", + "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", + NULL, NULL, NULL, NULL +}; + +static const char *t_special[36] = { + "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", + "+", "=", "[", "]", "{", "}", ";", ":", "'", "\"", ",", ".", + "<", ">", "/", "?", "`", "~", "|", "\\", "--", "==", "..", "//" +}; + +static const char *t_syllables_lm[36] = { + "B", "C", "D", "F", "G", "H", + "J", "K", "L", "M", "N", "P", + "QU", "R", "S", "T", "V", "W", + "X", "Z", "CH", "CR", "FR", "ND", + "NG", "NK", "NT", "PH", "PR", "RD", + "SH", "SL", "SP", "ST", "TH", "TR" +}; + +static const char *t_syllables_r[6] = { + "A", "E", "I", "O", "U", "Y" +}; + +static const char *koremutake_syllables[128] = { + "BA", "BE", "BI", "BO", "BU", "BY", "DA", "DE", + "DI", "DO", "DU", "DY", "FA", "FE", "FI", "FO", + "FU", "FY", "GA", "GE", "GI", "GO", "GU", "GY", + "HA", "HE", "HI", "HO", "HU", "HY", "JA", "JE", + "JI", "JO", "JU", "JY", "KA", "KE", "KI", "KO", + "KU", "KY", "LA", "LE", "LI", "LO", "LU", "LY", + "MA", "ME", "MI", "MO", "MU", "MY", "NA", "NE", + "NI", "NO", "NU", "NY", "PA", "PE", "PI", "PO", + "PU", "PY", "RA", "RE", "RI", "RO", "RU", "RY", + "SA", "SE", "SI", "SO", "SU", "SY", "TA", "TE", + "TI", "TO", "TU", "TY", "VA", "VE", "VI", "VO", + "VU", "VY", "BRA", "BRE", "BRI", "BRO", "BRU", "BRY", + "DRA", "DRE", "DRI", "DRO", "DRU", "DRY", "FRA", "FRE", + "FRI", "FRO", "FRU", "FRY", "GRA", "GRE", "GRI", "GRO", + "GRU", "GRY", "PRA", "PRE", "PRI", "PRO", "PRU", "PRY", + "STA", "STE", "STI", "STO", "STU", "STY", "TRA", "TRE" +}; + +#define N_CHARACTER_CLASSES 5 +static struct { + enum character_classes chr; /* character class */ + const char **dice12; /* first two dice throws */ + const char **dice3; /* possibly 3rd dice or NULL */ + float entropy; /* entropy per element */ +} character_classes[N_CHARACTER_CLASSES] = { + { chr_alphanumeric, t_alphanumeric, NULL, 5.17 }, + { chr_dec_digits, t_dec_digits, NULL, 3.32 }, + { chr_hex_digits, t_hex_digits, NULL, 4 }, + { chr_special, t_special, NULL, 5.17 }, + { chr_syllables, t_syllables_lm, t_syllables_r, 7.75 } +}; + +/* This is ONLY for passphrase enhancement. */ +static const char t_passphrase_enh[36] = { + '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', + '+', '=', '[', ']', '{', '}', ';', ':', '\'', '\'', ',', '.', + '<', '>', '/', '?', '`', '~', '|', '\\', 'U', 'O', 'E', 'Y' +}; + +/****************************************************************************** + * Methods for password generation. + *****************************************************************************/ + +float pwgen_diceware( + struct SRNG_st *random_state, + unsigned int number_of_words, + int is_enhanced, + const char * (*get_word)(unsigned int), + unsigned int dictionary_size, + unsigned int *random_buffer, + char *password_buffer) +{ + unsigned int i, word_length, output_index = 0; + const char *word; + float entropy = 0; + + *password_buffer = 0; + for(i = 0; i < number_of_words; i++) { + SRNG_bytes(random_state, random_buffer, sizeof(*random_buffer)); + word = get_word(*random_buffer); + word_length = strlen(word); + + sprintf(password_buffer + output_index, "%s ", word); + entropy += log(dictionary_size) / log(2); + + if(is_enhanced) { + unsigned int char_pos, char_idx; + + /* add a random symbol at random position into each word */ + SRNG_bytes(random_state, random_buffer, 2*sizeof(*random_buffer)); + char_pos = random_buffer[0] % word_length; + char_idx = random_buffer[1] % sizeof(t_passphrase_enh); + password_buffer[output_index+char_pos] = + t_passphrase_enh[char_idx]; + + /* 5.17 = log2(36) for each symbol plus the position randomness */ + entropy += 5.17 + log(word_length) / log(2); + } + output_index += word_length+1; + } + + return entropy; +} + +//********************************************************************* +//* Base64 - a simple base64 encoder and decoder. +//* +//* Copyright (c) 1999, Bob Withers - bwit@pobox.com +//* +//* This code may be freely used for any purpose, either personal +//* or commercial, provided the authors copyright notice remains +//* intact. +//* +//* Converted to C in 2005 by Zeljko Vrba +//********************************************************************* +static void base64_encode( + const unsigned char *in, + unsigned int len, + char *out) +{ + static const char fillchar = '='; + static const char *cvt = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + unsigned int i; + unsigned char c; + + /* + * SECURITY NOTE: single byte from the in string gets copied to the + * local stack in each iteration of the loop. + */ + + for (i = 0; i < len; ++i) { + c = (in[i] >> 2) & 0x3f; + *out++ = cvt[c]; + c = (in[i] << 4) & 0x3f; + if(++i < len) + c |= (in[i] >> 4) & 0x0f; + *out++ = cvt[c]; + if(i < len) { + c = (in[i] << 2) & 0x3f; + if(++i < len) + c |= (in[i] >> 6) & 0x03; + *out++ = cvt[c]; + } else { + ++i; + *out++ = fillchar; + } + + if(i < len) { + c = in[i] & 0x3f; + *out++ = cvt[c]; + } else { + *out++ = fillchar; + } + } + *out++ = 0; +} + +float pwgen_raw( + struct SRNG_st *random_state, + unsigned int number_of_bits, + unsigned int *random_buffer, + char *password_buffer) +{ + unsigned int number_of_bytes = ((number_of_bits-1)>>3)+1; + + SRNG_bytes(random_state, random_buffer, number_of_bytes); + base64_encode((unsigned char*)random_buffer, number_of_bytes, + password_buffer); + return number_of_bytes << 3; +} + +/* + * This rounds the number of bits to the next higher multiple of 7 (since + * there are 128=2^7 syllables in the koremutake list). + */ +float pwgen_koremutake( + struct SRNG_st *random_state, + unsigned int number_of_bits, + unsigned int *random_buffer, + char *password_buffer) +{ + unsigned int i, number_of_bytes = ((number_of_bits-1)/7)+1; + unsigned char *u8buf = (unsigned char*)random_buffer; + + SRNG_bytes(random_state, random_buffer, number_of_bytes); + *password_buffer = 0; + for(i = 0; i < number_of_bytes; i++) + strcat(password_buffer, koremutake_syllables[u8buf[i] & 127]); + return number_of_bytes * 7; +} + +static void select_class( + struct SRNG_st *random_state, + unsigned int allowed_classes, + unsigned int *random_buffer) +{ + do { + SRNG_bytes(random_state, random_buffer, sizeof(*random_buffer)); + *random_buffer %= N_CHARACTER_CLASSES; /* not a LCG, so % is OK */ + } while(!(allowed_classes & character_classes[*random_buffer].chr)); +} + +float pwgen_ascii( + struct SRNG_st *random_state, + unsigned int number_of_components, + unsigned int allowed_classes, + unsigned int *random_buffer, + char *password_buffer) +{ + unsigned int i; + unsigned int *character_class = random_buffer; + unsigned int *dice12 = character_class + 1; + unsigned int *dice3 = character_class + 2; + float entropy = 0; + + password_buffer[0] = 0; + for(i = 0; i < number_of_components; i++) { +retry: + /* select character class and throw 3 dice */ + select_class(random_state, allowed_classes, character_class); + SRNG_bytes(random_state, dice12, 2); + *dice12 %= 36; /* 1st and 2nd dice */ + *dice3 %= 6; /* 3rd dice */ + + if(character_classes[*character_class].dice12[*dice12]) { + strcat(password_buffer, + character_classes[*character_class].dice12[*dice12]); + if(!character_classes[*character_class].dice3) + entropy += character_classes[*character_class].entropy; + } else { + goto retry; + } + + if(character_classes[*character_class].dice3) { + if(character_classes[*character_class].dice3[*dice3]) { + strcat(password_buffer, + character_classes[*character_class].dice3[*dice3]); + entropy += character_classes[*character_class].entropy; + } else { + goto retry; + } + } + } + + return entropy; +} + diff --git a/pwgen.h b/pwgen.h new file mode 100644 index 0000000..26211fb --- /dev/null +++ b/pwgen.h @@ -0,0 +1,130 @@ +/* + pwgen.h - interface to platform-independent password generation + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef PWGEN_H__ +#define PWGEN_H__ + +/** + * @file + * This defines the interface to platform-independent secure password + * generation routines. + */ + +/** + * Generate passphrase by the 'diceware' method: a number of words selected + * from a fixed list. + * + * @param random_state + * @param number_of_words + * @param is_enhanced If non-0, generates an enhanced passhprase. + * @param get_word Pointer to the 'get word' function. + * @param dictionary_size Number of words in the dictionary. + * @param random_buffer Buffer into which to generate random numbers. + * @param password_buffer Buffer to output passphrase to. + * + * @note rndbuf and pwbuf are provided so that all sensitive output can + * be put into the secure memory, if available. There are no sizes + * specified, but generally rndbuf should have at least 64 bytes, + * and pwbuf at least 512 bytes. + * + * @return Estimated password entropy. + */ +float pwgen_diceware( + struct SRNG_st *random_state, + unsigned int number_of_words, + int is_enhanced, + const char * (*get_word)(unsigned int), + unsigned int dictionary_size, + unsigned int *random_buffer, + char *password_buffer); + +/** + * Generate a raw random passphrase of n bits encoded into base64. + * + * @param random_state Random state. + * @param number_of_bits Number of bits. + * @param random_buffer Buffer into which to generate random numbers. + * @param password_buffer Buffer to output passphrase to. + * + * @todo Use our own base64 encoder so we don't have to use mlockall() + * and OpenSSL. + * + * @return Estimated password entropy. + */ +float pwgen_raw( + struct SRNG_st *random_state, + unsigned int number_of_bits, + unsigned int *random_buffer, + char *password_buffer); + +/** + * Generate a raw random passphrase of n bits encoded by koremutake encoding + * into a pronouncable word. + * + * @param random_state Random state. + * @param number_of_bits Number of bits. + * @param random_buffer Buffer into which to generate random numbers. + * @param password_buffer Buffer to output passphrase to. + * + * @todo Use our own base64 encoder so we don't have to use mlockall() + * and OpenSSL. + * + * @return Estimated password entropy. + */ +float pwgen_koremutake( + struct SRNG_st *random_state, + unsigned int number_of_bits, + unsigned int *random_buffer, + char *password_buffer); + +/** Allowable character classes for pwgen_ascii. */ +enum character_classes { + chr_alphanumeric = 1, + chr_dec_digits = 2, + chr_hex_digits = 4, + chr_special = 8, + chr_syllables = 16 +}; + +/** + * Generate alphanumeric password generated from various 'classes'. + * + * @param random_state Random state. + * @param number_of_components Number of components. + * @param character_classes Bit-set of allowed character classes. + * @param random_buffer Buffer into which to generate random + * numbers. + * @param password_buffer Buffer to output passphrase to. + * + * @see character_classes. + * + * @return Estimated password entropy. + */ +float pwgen_ascii( + struct SRNG_st *random_state, + unsigned int number_of_components, + unsigned int character_classes, + unsigned int *random_buffer, + char *password_buffer); + +#endif /* PWGEN_H__ */ diff --git a/secpwgen.1 b/secpwgen.1 new file mode 100644 index 0000000..5d6761f --- /dev/null +++ b/secpwgen.1 @@ -0,0 +1,293 @@ +.\" (c) 2004-2005 Zeljko Vrba +.\" +.\" Permission is hereby granted, free of charge, to any person obtaining +.\" a copy of this software and associated documentation files (the +.\" "Software"), to deal in the Software without restriction, including +.\" without limitation the rights to use, copy, modify, merge, publish, +.\" distribute, sublicense, and/or sell copies of the Software, and to +.\" permit persons to whom the Software is furnished to do so, subject to +.\" the following conditions: +.\" +.\" The above copyright notice and this permission notice shall be +.\" included in all copies or substantial portions of the Software. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +.\" EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +.\" IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +.\" CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +.\" TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +.\" SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +.Dd April 4, 2005 +.Dt secpwgen 1 +.Os +.Sh NAME +.Nm secpwgen +.Nd "secure password generator" +.Sh SYNOPSIS +.Nm +.Fl p[e] +.Ar n +.Nm +.Fl s[e] +.Ar n +.Nm +.Fl A[adhsy] +.Ar n +.Nm +.Fl r +.Ar n +.Nm +.Fl k +.Ar n +.Sh DESCRIPTION +The +.Nm +command is used to generate secure, high-entropy passwords by +several methods. It aims to generate passwords that are strong and secure +enough for cryptographic purposes (e.g. for protecting keys). The exact +method is chosen by the options listed below: +.Bl -tag -width ".Fl d" +.It Fl p +Diceware method with the diceware dictionary. +.Ar n +is the number of words in the password. If the method is specified as +.Fl pe +then an enhanced password is generated. +.It Fl s +Same as +.Fl p +and +.Fl pe +but with the S/Key dictionary. +.It Fl A +Generates an ASCII password of +.Ar n +parts. At least one letter after A is mandatory. Each letter incorporates +additional set of components from which random elements are drawn. See the +exact method description below. +.It Fl r +Generates a random password and outputs it as base-64 encoded string. +.Ar n +is the desired number of bits of entropy. It will be rounded up to the +next higher multiple of 8. +.It Fl k +Same as +.Fl r +but uses the "koremutake" encoding instead of base 64 encoding. Koremutake +is yet another way of producing pronouncible phrases from long bit strings. +.It Ar n +Specifies the size of the password. The exact meaning depends on the +method and is described above in options. +.El +.Pp +The program outputs the generated passphrase and a calculated entropy +of the passphrase. +.Sh METHOD DESCRIPTIONS +The following subsections give detailed explanations of the password +generation methods. +.Ss DICEWARE METHOD +This method selects +.Ar n +random words from the given dictionary. The diceware dictionary contains +8192 words, and the S/Key dictionary contains 2048 words. Both dictionaries +have been taken from the internet (see references). +.Ss ENHANCED DICEWARE METHOD +Extends the diceware method by chosing a random letter in each word +and replacing that letter with one of 32 special symbols and 4 upper-case +letters (all words in the dictionary are lower-case). +.Ss ASCII METHOD +Draws +.Ar n +random elements from randomly chosen allowed sets and concatenates +them in a single string. The allowed sets are specified by the letters +following the +.Fl A +flag and have these meanings: +.Pp +.Bl -tag -width "X" -compact +.It a +alphanumeric characters +.It d +decimal digits +.It h +hexadecimal digits +.It s +special characters +.It y +3- and 4-letter syllables +.El +.Pp +Note that these sets are not all mutually exclusive. Such combinations +will have the same effect as specifying a single "larger" set. +.Ss RANDOM METHODS +Rounds +.Ar n +up to the next higher multiple of 8 (7 in case of koremutake) bits (does +nothing if it is already a multiple) and generates +.Ar n/8 +( +.Ar n/7 +) +random bytes. The resulting passphrase is output as a base-64 or koremutake +encoded string. +.Pp +In case of koremutake, for programming simplicity, each random byte is taken +mod 128 and looked up in the syllable dictionary. Since the random number +generator is assumed to be secure, i.e. generates uniformly distributed +radnom numbers, there is no weakness by using the mod operation. +.Sh SECURITY +First of all, a +.Sy warning: +as recommended on the diceware site, NEVER actually put spaces between +individual words of the generated passphrase. On many keyboards the space +key has very distinctive sound which makes possible for the attacker to +learn the number of words and possibly the number of letters in each word +(in correct order). These facts divulge much information and make passphrase +easier to guess. +.Pp +In the author's opinion the program is written very carefully so that the +generated passphrase can't end up accidentaly on the swap or core file. The +steps taken in securing the program: +.Bl -bullet +.It +Dedicating a separate block of memory for all confidential data. +.It +Zeroing that block of memory upon program exit (by registering the atexit() +function). +.It +Locking all programs' memory with mlockall(MCL_FUTURE), if possible (the +program must be run with root privileges or installed setuid root to be +able to do that). +.Pp +On some systems, locking memory with mlockall causes the program to fail +(because some library routines try to allocate too much memory). In that +case mlock is used with reduced security: the stack is not locked in memory. +.It +Disabling core-dumps in the event of crash. +.It +Cryptographically strong random number generator (using OpenSSL or cryptlib). +The exact method for generation is described in its respective source file. +.El +.Pp +The strength of the chain equals the strength of its weakest link. You should +put as much trust in this program as you trust the implementation of any of +the following used components: C library, the cryptographic toolkit used for +random number generation, the kernel, and, ultimately, the system +administrator (although not a SW component :), a malicious sysadmin can modify +the kernel or system libraries to log somewhere all output of a program). +.Pp +You should build the program as statically linked, if at all possible. There +are numerous ways in which dynamic linking can be used to subvert this +programs' security. Unfortunately, there is no reliable nor portable way to +discover at run-time if the program is statically or dynamically linked. +.Ss OPENSSL NOTES +This program does not take any steps to initialize the entropy pool. OpenSSL +uses the system-provided /dev/[u]random as the source of randomness. +OpenSSL should report an error on systems that do not provide the /dev/random +device. If you are sure that your system does not support these +devices (most notably, WIN32 systems) and the program does not report an +error then +.Sy do not use it +if you want really secure and unguessable passwords. There are many real-life +examples where the system security was compromised because of poor random +number generators. +.Ss CRYPTLIB NOTES +For maximum security, it is recommended to use cryptlib if at all possible. +Citing its manual, it is designed around a B3 kernel and tries very hard to +protect and sanitize all sensitive data (including locking it in memory if +possible). Also, there are no issues about initializing the entropy pool. +.Sh EXAMPLES +Generate an 4-word enhanced passphrase from the diceware dictionary: +.Nm +command: +.Pp +.Dl "secpwgen -pe 4" +.Pp +gives the following typical output when run without root privileges: +.Pp +.Bd -literal -unfilled -offset indent +mlockall: Operation not permitted +WARNING: using insecure memory. +---------------- +ha'e ap.x ro|ue si+th ;ENTROPY=81.32 bits +---------------- +INFO: zeroing memory. +.Ed +.Sh DIAGNOSTICS +Exit status is 0 on success, and 1 if the command +encounters a fatal error. Informational messages are omitted from this +listing. Their meaning can be deduced from the source. +.Bl -diag +.It "WARNING: using insecure memory." +This message is not only pertained to memory; for example it can happen that +the program can't turn off core file generation. The exact cause is seen +in system error messages preceding the warning. +.Pp +If this message is printed, you must assume that the generated password can +end up in plain text on the swap device, core file or other from where it +could be retrieved by an adversary. +.It "FATAL: out of memory." +Cannot allocate enough memory. +.It "FATAL: system call failed. There is no way..." +The program, if installed as SUID root, drops its root privileges +as soon as it obtains secure memory. This didn't succeed, and +because of documented buffer overflows (see the +.Sx BUGS +section below) the program refuses to execute. Executing a SUID +program with the potential of buffer overflows is an extreme +security risk. +.It "FATAL: too small MAX_RANDOM_STATE_SIZE..." +The MAX_RANDOM_STATE_SIZE macro in secure_memory.h should be enlarged +to at least the size displayed after the message and the program +recompiled. +.It "FATAL: unhandled exception" +This is a real bug in the program. Report this to the author +along with the exact command-line arguments, the compiler used, +operating system, etc. +.It "ERROR: some garbage left to cryptlib." +This is an indication of the bug in the program. Report this to the author +along with other data described above. Nothing "bad" happened; everything +was properly cleaned by cryptlib on exit. It is just an indication that +some objects were not freed by the program before shutting down cryptlib. +.El +.Sh SEE ALSO +.Xr pwgen 1 , +.Xr mlockall 2 +.Rs +.%T "Diceware Passphrase Home Page" +.%O http://www.diceware.com +.Re +.Rs +.%T "Koremutake encoding" +.%O http://shorl.com/koremutake.php +.Re +.Rs +.%T "RFC1760: The S/KEY One-Time Password System" +.Re +.Rs +.%T "RFC2289: A One-Time Password System" +.Re +.Rs +.%A Peter Gutmann +.%T cryptlib +.%O http://www.cs.auckland.ac.nz/~pgut001/cryptlib/ +.Re +.Rs +.%T OpenSSL +.%O http://www.openssl.org +.Re +.Sh AUTHORS +The secpwgen program and this manual page were written by +.An Zeljko Vrba Aq zvrba@globalnet.hr . +.Sh BUGS +The program +.Sy will crash +if +.Ar n +is too big. No checks are made for the internal buffer sizes. However, since +this program is intended to be used by humans who must memorize their +passphrases, this is not an issue. The program works correctly for "reasonable" +sizes of +.Ar n +(e.g. less than 256). diff --git a/secure_memory.h b/secure_memory.h new file mode 100644 index 0000000..d48d6d6 --- /dev/null +++ b/secure_memory.h @@ -0,0 +1,57 @@ +/* + secure_memory.h - definitions of data structures residing in secure memory + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef SECURE_MEMORY_H__ +#define SECURE_MEMORY_H__ + +/** + * @file + * This defines the contents of the secure memory. + */ + +/** Maximum size of random state. */ +#define MAX_RANDOM_STATE_SIZE 8192 + +struct secure_memory { + unsigned char random_state[MAX_RANDOM_STATE_SIZE]; + unsigned int random_numbers[64]; + char passphrase[1]; +}; + +extern struct secure_memory *G_secure_memory; +extern unsigned int G_secure_memory_size; + +/** + * Set up a chunk of secure memory. + * + * @return 0 if at least one operation failed, 1 otherwise. In either case + * the program execution can continue. There may be other side-effects such + * as printing warnings. If there was a fatal error, this function will + * terminate the program. + */ +int secure_memory_init(void); + +/** Destroy secure memory. Zeroes it before destruction. */ +void secure_memory_destroy(void); + +#endif /* SECURE_MEMORY_H__ */ diff --git a/secure_memory_unix.c b/secure_memory_unix.c new file mode 100644 index 0000000..1ccf855 --- /dev/null +++ b/secure_memory_unix.c @@ -0,0 +1,135 @@ +/* + secure_memory_unix.c - secure memory implementation for UNIX systems + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "secure_random.h" +#include "secure_memory.h" +#include "exceptions.h" + +static char rcsid[] = "$Id: secure_memory_unix.c 1 2005-11-13 20:23:40Z zvrba $"; + +#ifndef MAP_ANON +#define MAP_ANON MAP_ANONYMOUS +#endif + +struct secure_memory *G_secure_memory; +unsigned int G_secure_memory_size; +static long G_pagesize; + +static int allocate_secure_memory(void) +{ + int retval = 1; + + if((G_pagesize = sysconf(_SC_PAGESIZE)) < 0) { + perror("sysconf"); + Throw(system_call_failed_exception); + } + + G_secure_memory_size = 16*G_pagesize; + G_secure_memory = mmap(NULL, G_secure_memory_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if(G_secure_memory == MAP_FAILED) { + perror("mmap"); + Throw(out_of_memory_exception); + } + + /* This is to guarantee segfault on buffer overrun. */ + if(mprotect((char*)G_secure_memory + 15*G_pagesize, G_pagesize, + PROT_NONE) < 0) { + perror("mprotect"); + Throw(system_call_failed_exception); + } + +#ifdef DISABLE_MLOCKALL + /* + * On some OSes (most notably some Linux 2.6 kernels versions), some + * libraries try to allocate too much space and then crash (because + * the allocation would exceed the maximum allowed number of locked + * pages). Which results in a crash. + * + * However, this gives lower security since the stack pages are not + * locked in memory. + */ + if(mlock(G_secure_memory, G_secure_memory_size) < 0) { + perror("mlock"); + retval = 0; + } +#else + if(mlockall(MCL_FUTURE) < 0) { + perror("mlockall"); + retval = 0; + } +#endif + + return retval; +} + +static void drop_privileges(void) +{ + if(seteuid(getuid()) < 0) { + perror("seteuid"); + Throw(system_call_failed_exception); + } +} + +static int disable_core_file(void) +{ + int retval = 1; + struct rlimit rlim = { 0, 0 }; + + if(setrlimit(RLIMIT_CORE, &rlim) < 0) { + perror("setrlimit"); + retval = 0; + } + + return retval; +} + +int secure_memory_init(void) +{ + int success; + + success = allocate_secure_memory(); + drop_privileges(); + success &= disable_core_file(); + + if(!success) + fprintf(stderr, "WARNING: using insecure memory.\n"); + + return success; +} + +void secure_memory_destroy(void) +{ + printf("INFO: zeroing memory.\n"); + memset(G_secure_memory, 0, G_secure_memory_size - G_pagesize); +} + diff --git a/secure_random.h b/secure_random.h new file mode 100644 index 0000000..d0eb42a --- /dev/null +++ b/secure_random.h @@ -0,0 +1,69 @@ +/* + secure_random.h - interface for secure random number generator + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#ifndef SECURE_RANDOM_H__ +#define SECURE_RANDOM_H__ + +/** + @file + This file defines the SRNG interface. +*/ + +/** Opaque structure used to hold secure random generator state. */ +struct SRNG_st; + +/** + Initialize the secure random number generator. + @param st The state variable which should be initialized. The behaviour + depends whether this is NULL or not. + @return The size of the initialized state. + + An exception is thrown on error. + + @note The interface is designed such that it is possible to provide a + secure (e.g. memory-locked) buffer for the state. If \e st is + NULL, the function does nothing, but still returns the size that + needs to be reserved for the state. +*/ +unsigned int SRNG_init(struct SRNG_st *st); + +/** + Obtain \e n bytes of randomness from the generator. + + @param st Pointer to generator state. + @param buf Buffer to store random bytes. + @param n Number of random bytes to retrieve. + + An exception is thrown on error. +*/ +void SRNG_bytes( + struct SRNG_st *st, + void *buf, + unsigned int n); + +/** + * Destroy the RNG state. \e st is pointer returned by SRNG_init(). + */ +void SRNG_destroy(struct SRNG_st *st); + +#endif /* SECURE_RANDOM_H__ */ diff --git a/secure_random_cryptlib.c b/secure_random_cryptlib.c new file mode 100644 index 0000000..ba0fbe8 --- /dev/null +++ b/secure_random_cryptlib.c @@ -0,0 +1,84 @@ +/* + secure_random_openssl.c - secure random number generator using OpenSSL + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include +#include +#include +#include "exceptions.h" + +static char rcsid[] = "$Id: secure_random_cryptlib.c 1 2005-11-13 20:23:40Z zvrba $"; + +/** + @file + Cryptlib random number generator. +*/ + +struct SRNG_st { + CRYPT_CONTEXT ctx; + char rnd[64]; +}; + +#define CALL_CL(func, ...) do { \ + int ret__ = func(__VA_ARGS__); \ + if(ret__ != CRYPT_OK) { \ + fprintf(stderr, "cryptlib error: %d\n", ret__); \ + Throw(lib_crypto_exception); \ + } \ +} while(0) + +unsigned int SRNG_init(struct SRNG_st *st) +{ + if(!st) + goto end; + + CALL_CL(cryptInit); + CALL_CL(cryptAddRandom, NULL, CRYPT_RANDOM_SLOWPOLL); + CALL_CL(cryptCreateContext, &st->ctx, CRYPT_UNUSED, CRYPT_ALGO_RC4); + CALL_CL(cryptGenerateKey, st->ctx); + +end: + return sizeof(struct SRNG_st); +} + +void SRNG_bytes( + struct SRNG_st *st, + void *buf, + unsigned int n) +{ + assert(n < sizeof(st->rnd)); + CALL_CL(cryptEncrypt, st->ctx, st->rnd, sizeof(st->rnd)); + memcpy(buf, st->rnd, n); +} + +void SRNG_destroy(struct SRNG_st *st) +{ + printf("INFO: destroying random number generator.\n"); + CALL_CL(cryptDestroyContext, st->ctx); + if(cryptEnd() != CRYPT_OK) { + fprintf(stderr, "ERROR: some garbage left to cryptlib."); + } + memset(st, 0, sizeof(*st)); +} + diff --git a/secure_random_openssl.c b/secure_random_openssl.c new file mode 100644 index 0000000..fe29165 --- /dev/null +++ b/secure_random_openssl.c @@ -0,0 +1,108 @@ +/* + secure_random_openssl.c - secure random number generator using OpenSSL + (c) 2004-2005 Zeljko Vrba + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ +#include +#include +#include +#include +#include +#include "exceptions.h" + +static char rcsid[] = "$Id: secure_random_openssl.c 1 2005-11-13 20:23:40Z zvrba $"; + +/** + @file + This implementation uses the Blowfish cipher and low-level interfaces + usable both in SSLEay and OpenSSL (the latter is interesting in porting + to e.g. PalmOS). + + The generator gathers a small amount of true randomness from the system and + uses it to initialize the blowfish key and the randomness buffer. Further + random bytes are obtained by encrypting the previous contents of the + random buffer. +*/ + +/* Blowfish parameters. */ +#define KEY_SIZE 16 /* 128-bit key size */ +#define BLOCK_SIZE 8 /* 64-bit block size */ + +struct SRNG_st { + BF_KEY key; + unsigned char rnd[2*BLOCK_SIZE]; + unsigned int idx; + unsigned char keydata[KEY_SIZE]; +}; + +unsigned int SRNG_init(struct SRNG_st *st) +{ + if(!st) + goto end; + + if(!RAND_bytes(st->keydata, sizeof(st->keydata)) + || !RAND_bytes(st->rnd, sizeof(st->rnd))) { + ERR_print_errors_fp(stderr); + Throw(lib_crypto_exception); + } + + BF_set_key(&st->key, sizeof(st->keydata), st->keydata); + st->idx = 0; + +end: + return sizeof(struct SRNG_st); +} + +void SRNG_bytes( + struct SRNG_st *st, + void *buf, + unsigned int n) +{ + unsigned char *out = buf, *src, *dst; + + while(1) { + /* + * this swaps src and dst to point to differenct halves of st->rnd on + * each iteration. st->idx is either 0 or BLOCK_SIZE. it is initialized + * to 0 in SRNG_init. + */ + src = st->rnd + st->idx; + dst = st->rnd + (BLOCK_SIZE - st->idx); + st->idx = BLOCK_SIZE - st->idx; + + BF_ecb_encrypt(src, dst, &st->key, BF_ENCRYPT); + + if(n < BLOCK_SIZE) { + memcpy(out, dst, n); + break; + } + + memcpy(out, dst, BLOCK_SIZE); + n -= BLOCK_SIZE; out += BLOCK_SIZE; + } +} + +void SRNG_destroy(struct SRNG_st *st) +{ + printf("INFO: destroying random number generator.\n"); + memset(st, 0, sizeof(*st)); +} + diff --git a/skeylist.c b/skeylist.c new file mode 100644 index 0000000..4e36a51 --- /dev/null +++ b/skeylist.c @@ -0,0 +1,263 @@ +static const char *skeylist[2048] = +{ "a", "abe", "ace", "act", "ad", "ada", "add", +"ago", "aid", "aim", "air", "all", "alp", "am", "amy", +"an", "ana", "and", "ann", "ant", "any", "ape", "aps", +"apt", "arc", "are", "ark", "arm", "art", "as", "ash", +"ask", "at", "ate", "aug", "auk", "ave", "awe", "awk", +"awl", "awn", "ax", "aye", "bad", "bag", "bah", "bam", +"ban", "bar", "bat", "bay", "be", "bed", "bee", "beg", +"ben", "bet", "bey", "bib", "bid", "big", "bin", "bit", +"bob", "bog", "bon", "boo", "bop", "bow", "boy", "bub", +"bud", "bug", "bum", "bun", "bus", "but", "buy", "by", +"bye", "cab", "cal", "cam", "can", "cap", "car", "cat", +"caw", "cod", "cog", "col", "con", "coo", "cop", "cot", +"cow", "coy", "cry", "cub", "cue", "cup", "cur", "cut", +"dab", "dad", "dam", "dan", "dar", "day", "dee", "del", +"den", "des", "dew", "did", "die", "dig", "din", "dip", +"do", "doe", "dog", "don", "dot", "dow", "dry", "dub", +"dud", "due", "dug", "dun", "ear", "eat", "ed", "eel", +"egg", "ego", "eli", "elk", "elm", "ely", "em", "end", +"est", "etc", "eva", "eve", "ewe", "eye", "fad", "fan", +"far", "fat", "fay", "fed", "fee", "few", "fib", "fig", +"fin", "fir", "fit", "flo", "fly", "foe", "fog", "for", +"fry", "fum", "fun", "fur", "gab", "gad", "gag", "gal", +"gam", "gap", "gas", "gay", "gee", "gel", "gem", "get", +"gig", "gil", "gin", "go", "got", "gum", "gun", "gus", +"gut", "guy", "gym", "gyp", "ha", "had", "hal", "ham", +"han", "hap", "has", "hat", "haw", "hay", "he", "hem", +"hen", "her", "hew", "hey", "hi", "hid", "him", "hip", +"his", "hit", "ho", "hob", "hoc", "hoe", "hog", "hop", +"hot", "how", "hub", "hue", "hug", "huh", "hum", "hut", +"i", "icy", "ida", "if", "ike", "ill", "ink", "inn", +"io", "ion", "iq", "ira", "ire", "irk", "is", "it", +"its", "ivy", "jab", "jag", "jam", "jan", "jar", "jaw", +"jay", "jet", "jig", "jim", "jo", "job", "joe", "jog", +"jot", "joy", "jug", "jut", "kay", "keg", "ken", "key", +"kid", "kim", "kin", "kit", "la", "lab", "lac", "lad", +"lag", "lam", "lap", "law", "lay", "lea", "led", "lee", +"leg", "len", "leo", "let", "lew", "lid", "lie", "lin", +"lip", "lit", "lo", "lob", "log", "lop", "los", "lot", +"lou", "low", "loy", "lug", "lye", "ma", "mac", "mad", +"mae", "man", "mao", "map", "mat", "maw", "may", "me", +"meg", "mel", "men", "met", "mew", "mid", "min", "mit", +"mob", "mod", "moe", "moo", "mop", "mos", "mot", "mow", +"mud", "mug", "mum", "my", "nab", "nag", "nan", "nap", +"nat", "nay", "ne", "ned", "nee", "net", "new", "nib", +"nil", "nip", "nit", "no", "nob", "nod", "non", "nor", +"not", "nov", "now", "nu", "nun", "nut", "o", "oaf", +"oak", "oar", "oat", "odd", "ode", "of", "off", "oft", +"oh", "oil", "ok", "old", "on", "one", "or", "orb", +"ore", "orr", "os", "ott", "our", "out", "ova", "ow", +"owe", "owl", "own", "ox", "pa", "pad", "pal", "pam", +"pan", "pap", "par", "pat", "paw", "pay", "pea", "peg", +"pen", "pep", "per", "pet", "pew", "phi", "pi", "pie", +"pin", "pit", "ply", "po", "pod", "poe", "pop", "pot", +"pow", "pro", "pry", "pub", "pug", "pun", "pup", "put", +"quo", "rag", "ram", "ran", "rap", "rat", "raw", "ray", +"reb", "red", "rep", "ret", "rib", "rid", "rig", "rim", +"rio", "rip", "rob", "rod", "roe", "ron", "rot", "row", +"roy", "rub", "rue", "rug", "rum", "run", "rye", "sac", +"sad", "sag", "sal", "sam", "san", "sap", "sat", "saw", +"say", "sea", "sec", "see", "sen", "set", "sew", "she", +"shy", "sin", "sip", "sir", "sis", "sit", "ski", "sky", +"sly", "so", "sob", "sod", "son", "sop", "sow", "soy", +"spa", "spy", "sub", "sud", "sue", "sum", "sun", "sup", +"tab", "tad", "tag", "tan", "tap", "tar", "tea", "ted", +"tee", "ten", "the", "thy", "tic", "tie", "tim", "tin", +"tip", "to", "toe", "tog", "tom", "ton", "too", "top", +"tow", "toy", "try", "tub", "tug", "tum", "tun", "two", +"un", "up", "us", "use", "van", "vat", "vet", "vie", +"wad", "wag", "war", "was", "way", "we", "web", "wed", +"wee", "wet", "who", "why", "win", "wit", "wok", "won", +"woo", "wow", "wry", "wu", "yam", "yap", "yaw", "ye", +"yea", "yes", "yet", "you", "abed", "abel", "abet", "able", +"abut", "ache", "acid", "acme", "acre", "acta", "acts", "adam", +"adds", "aden", "afar", "afro", "agee", "ahem", "ahoy", "aida", +"aide", "aids", "airy", "ajar", "akin", "alan", "alec", "alga", +"alia", "ally", "alma", "aloe", "also", "alto", "alum", "alva", +"amen", "ames", "amid", "ammo", "amok", "amos", "amra", "andy", +"anew", "anna", "anne", "ante", "anti", "aqua", "arab", "arch", +"area", "argo", "arid", "army", "arts", "arty", "asia", "asks", +"atom", "aunt", "aura", "auto", "aver", "avid", "avis", "avon", +"avow", "away", "awry", "babe", "baby", "bach", "back", "bade", +"bail", "bait", "bake", "bald", "bale", "bali", "balk", "ball", +"balm", "band", "bane", "bang", "bank", "barb", "bard", "bare", +"bark", "barn", "barr", "base", "bash", "bask", "bass", "bate", +"bath", "bawd", "bawl", "bead", "beak", "beam", "bean", "bear", +"beat", "beau", "beck", "beef", "been", "beer", "beet", "bela", +"bell", "belt", "bend", "bent", "berg", "bern", "bert", "bess", +"best", "beta", "beth", "bhoy", "bias", "bide", "bien", "bile", +"bilk", "bill", "bind", "bing", "bird", "bite", "bits", "blab", +"blat", "bled", "blew", "blob", "bloc", "blot", "blow", "blue", +"blum", "blur", "boar", "boat", "boca", "bock", "bode", "body", +"bogy", "bohr", "boil", "bold", "bolo", "bolt", "bomb", "bona", +"bond", "bone", "bong", "bonn", "bony", "book", "boom", "boon", +"boot", "bore", "borg", "born", "bose", "boss", "both", "bout", +"bowl", "boyd", "brad", "brae", "brag", "bran", "bray", "bred", +"brew", "brig", "brim", "brow", "buck", "budd", "buff", "bulb", +"bulk", "bull", "bunk", "bunt", "buoy", "burg", "burl", "burn", +"burr", "burt", "bury", "bush", "buss", "bust", "busy", "byte", +"cady", "cafe", "cage", "cain", "cake", "calf", "call", "calm", +"came", "cane", "cant", "card", "care", "carl", "carr", "cart", +"case", "cash", "cask", "cast", "cave", "ceil", "cell", "cent", +"cern", "chad", "char", "chat", "chaw", "chef", "chen", "chew", +"chic", "chin", "chou", "chow", "chub", "chug", "chum", "cite", +"city", "clad", "clam", "clan", "claw", "clay", "clod", "clog", +"clot", "club", "clue", "coal", "coat", "coca", "cock", "coco", +"coda", "code", "cody", "coed", "coil", "coin", "coke", "cola", +"cold", "colt", "coma", "comb", "come", "cook", "cool", "coon", +"coot", "cord", "core", "cork", "corn", "cost", "cove", "cowl", +"crab", "crag", "cram", "cray", "crew", "crib", "crow", "crud", +"cuba", "cube", "cuff", "cull", "cult", "cuny", "curb", "curd", +"cure", "curl", "curt", "cuts", "dade", "dale", "dame", "dana", +"dane", "dang", "dank", "dare", "dark", "darn", "dart", "dash", +"data", "date", "dave", "davy", "dawn", "days", "dead", "deaf", +"deal", "dean", "dear", "debt", "deck", "deed", "deem", "deer", +"deft", "defy", "dell", "dent", "deny", "desk", "dial", "dice", +"died", "diet", "dime", "dine", "ding", "dint", "dire", "dirt", +"disc", "dish", "disk", "dive", "dock", "does", "dole", "doll", +"dolt", "dome", "done", "doom", "door", "dora", "dose", "dote", +"doug", "dour", "dove", "down", "drab", "drag", "dram", "draw", +"drew", "drub", "drug", "drum", "dual", "duck", "duct", "duel", +"duet", "duke", "dull", "dumb", "dune", "dunk", "dusk", "dust", +"duty", "each", "earl", "earn", "ease", "east", "easy", "eben", +"echo", "eddy", "eden", "edge", "edgy", "edit", "edna", "egan", +"elan", "elba", "ella", "else", "emil", "emit", "emma", "ends", +"eric", "eros", "even", "ever", "evil", "eyed", "face", "fact", +"fade", "fail", "fain", "fair", "fake", "fall", "fame", "fang", +"farm", "fast", "fate", "fawn", "fear", "feat", "feed", "feel", +"feet", "fell", "felt", "fend", "fern", "fest", "feud", "fief", +"figs", "file", "fill", "film", "find", "fine", "fink", "fire", +"firm", "fish", "fisk", "fist", "fits", "five", "flag", "flak", +"flam", "flat", "flaw", "flea", "fled", "flew", "flit", "floc", +"flog", "flow", "flub", "flue", "foal", "foam", "fogy", "foil", +"fold", "folk", "fond", "font", "food", "fool", "foot", "ford", +"fore", "fork", "form", "fort", "foss", "foul", "four", "fowl", +"frau", "fray", "fred", "free", "fret", "frey", "frog", "from", +"fuel", "full", "fume", "fund", "funk", "fury", "fuse", "fuss", +"gaff", "gage", "gail", "gain", "gait", "gala", "gale", "gall", +"galt", "game", "gang", "garb", "gary", "gash", "gate", "gaul", +"gaur", "gave", "gawk", "gear", "geld", "gene", "gent", "germ", +"gets", "gibe", "gift", "gild", "gill", "gilt", "gina", "gird", +"girl", "gist", "give", "glad", "glee", "glen", "glib", "glob", +"glom", "glow", "glue", "glum", "glut", "goad", "goal", "goat", +"goer", "goes", "gold", "golf", "gone", "gong", "good", "goof", +"gore", "gory", "gosh", "gout", "gown", "grab", "grad", "gray", +"greg", "grew", "grey", "grid", "grim", "grin", "grit", "grow", +"grub", "gulf", "gull", "gunk", "guru", "gush", "gust", "gwen", +"gwyn", "haag", "haas", "hack", "hail", "hair", "hale", "half", +"hall", "halo", "halt", "hand", "hang", "hank", "hans", "hard", +"hark", "harm", "hart", "hash", "hast", "hate", "hath", "haul", +"have", "hawk", "hays", "head", "heal", "hear", "heat", "hebe", +"heck", "heed", "heel", "heft", "held", "hell", "helm", "herb", +"herd", "here", "hero", "hers", "hess", "hewn", "hick", "hide", +"high", "hike", "hill", "hilt", "hind", "hint", "hire", "hiss", +"hive", "hobo", "hock", "hoff", "hold", "hole", "holm", "holt", +"home", "hone", "honk", "hood", "hoof", "hook", "hoot", "horn", +"hose", "host", "hour", "hove", "howe", "howl", "hoyt", "huck", +"hued", "huff", "huge", "hugh", "hugo", "hulk", "hull", "hunk", +"hunt", "hurd", "hurl", "hurt", "hush", "hyde", "hymn", "ibis", +"icon", "idea", "idle", "iffy", "inca", "inch", "into", "ions", +"iota", "iowa", "iris", "irma", "iron", "isle", "itch", "item", +"ivan", "jack", "jade", "jail", "jake", "jane", "java", "jean", +"jeff", "jerk", "jess", "jest", "jibe", "jill", "jilt", "jive", +"joan", "jobs", "jock", "joel", "joey", "john", "join", "joke", +"jolt", "jove", "judd", "jude", "judo", "judy", "juju", "juke", +"july", "june", "junk", "juno", "jury", "just", "jute", "kahn", +"kale", "kane", "kant", "karl", "kate", "keel", "keen", "keno", +"kent", "kern", "kerr", "keys", "kick", "kill", "kind", "king", +"kirk", "kiss", "kite", "klan", "knee", "knew", "knit", "knob", +"knot", "know", "koch", "kong", "kudo", "kurd", "kurt", "kyle", +"lace", "lack", "lacy", "lady", "laid", "lain", "lair", "lake", +"lamb", "lame", "land", "lane", "lang", "lard", "lark", "lass", +"last", "late", "laud", "lava", "lawn", "laws", "lays", "lead", +"leaf", "leak", "lean", "lear", "leek", "leer", "left", "lend", +"lens", "lent", "leon", "lesk", "less", "lest", "lets", "liar", +"lice", "lick", "lied", "lien", "lies", "lieu", "life", "lift", +"like", "lila", "lilt", "lily", "lima", "limb", "lime", "lind", +"line", "link", "lint", "lion", "lisa", "list", "live", "load", +"loaf", "loam", "loan", "lock", "loft", "loge", "lois", "lola", +"lone", "long", "look", "loon", "loot", "lord", "lore", "lose", +"loss", "lost", "loud", "love", "lowe", "luck", "lucy", "luge", +"luke", "lulu", "lund", "lung", "lura", "lure", "lurk", "lush", +"lust", "lyle", "lynn", "lyon", "lyra", "mace", "made", "magi", +"maid", "mail", "main", "make", "male", "mali", "mall", "malt", +"mana", "mann", "many", "marc", "mare", "mark", "mars", "mart", +"mary", "mash", "mask", "mass", "mast", "mate", "math", "maul", +"mayo", "mead", "meal", "mean", "meat", "meek", "meet", "meld", +"melt", "memo", "mend", "menu", "mert", "mesh", "mess", "mice", +"mike", "mild", "mile", "milk", "mill", "milt", "mimi", "mind", +"mine", "mini", "mink", "mint", "mire", "miss", "mist", "mite", +"mitt", "moan", "moat", "mock", "mode", "mold", "mole", "moll", +"molt", "mona", "monk", "mont", "mood", "moon", "moor", "moot", +"more", "morn", "mort", "moss", "most", "moth", "move", "much", +"muck", "mudd", "muff", "mule", "mull", "murk", "mush", "must", +"mute", "mutt", "myra", "myth", "nagy", "nail", "nair", "name", +"nary", "nash", "nave", "navy", "neal", "near", "neat", "neck", +"need", "neil", "nell", "neon", "nero", "ness", "nest", "news", +"newt", "nibs", "nice", "nick", "nile", "nina", "nine", "noah", +"node", "noel", "noll", "none", "nook", "noon", "norm", "nose", +"note", "noun", "nova", "nude", "null", "numb", "oath", "obey", +"oboe", "odin", "ohio", "oily", "oint", "okay", "olaf", "oldy", +"olga", "olin", "oman", "omen", "omit", "once", "ones", "only", +"onto", "onus", "oral", "orgy", "oslo", "otis", "otto", "ouch", +"oust", "outs", "oval", "oven", "over", "owly", "owns", "quad", +"quit", "quod", "race", "rack", "racy", "raft", "rage", "raid", +"rail", "rain", "rake", "rank", "rant", "rare", "rash", "rate", +"rave", "rays", "read", "real", "ream", "rear", "reck", "reed", +"reef", "reek", "reel", "reid", "rein", "rena", "rend", "rent", +"rest", "rice", "rich", "rick", "ride", "rift", "rill", "rime", +"ring", "rink", "rise", "risk", "rite", "road", "roam", "roar", +"robe", "rock", "rode", "roil", "roll", "rome", "rood", "roof", +"rook", "room", "root", "rosa", "rose", "ross", "rosy", "roth", +"rout", "rove", "rowe", "rows", "rube", "ruby", "rude", "rudy", +"ruin", "rule", "rung", "runs", "runt", "ruse", "rush", "rusk", +"russ", "rust", "ruth", "sack", "safe", "sage", "said", "sail", +"sale", "salk", "salt", "same", "sand", "sane", "sang", "sank", +"sara", "saul", "save", "says", "scan", "scar", "scat", "scot", +"seal", "seam", "sear", "seat", "seed", "seek", "seem", "seen", +"sees", "self", "sell", "send", "sent", "sets", "sewn", "shag", +"sham", "shaw", "shay", "shed", "shim", "shin", "shod", "shoe", +"shot", "show", "shun", "shut", "sick", "side", "sift", "sigh", +"sign", "silk", "sill", "silo", "silt", "sine", "sing", "sink", +"sire", "site", "sits", "situ", "skat", "skew", "skid", "skim", +"skin", "skit", "slab", "slam", "slat", "slay", "sled", "slew", +"slid", "slim", "slit", "slob", "slog", "slot", "slow", "slug", +"slum", "slur", "smog", "smug", "snag", "snob", "snow", "snub", +"snug", "soak", "soar", "sock", "soda", "sofa", "soft", "soil", +"sold", "some", "song", "soon", "soot", "sore", "sort", "soul", +"sour", "sown", "stab", "stag", "stan", "star", "stay", "stem", +"stew", "stir", "stow", "stub", "stun", "such", "suds", "suit", +"sulk", "sums", "sung", "sunk", "sure", "surf", "swab", "swag", +"swam", "swan", "swat", "sway", "swim", "swum", "tack", "tact", +"tail", "take", "tale", "talk", "tall", "tank", "task", "tate", +"taut", "teal", "team", "tear", "tech", "teem", "teen", "teet", +"tell", "tend", "tent", "term", "tern", "tess", "test", "than", +"that", "thee", "them", "then", "they", "thin", "this", "thud", +"thug", "tick", "tide", "tidy", "tied", "tier", "tile", "till", +"tilt", "time", "tina", "tine", "tint", "tiny", "tire", "toad", +"togo", "toil", "told", "toll", "tone", "tong", "tony", "took", +"tool", "toot", "tore", "torn", "tote", "tour", "tout", "town", +"trag", "tram", "tray", "tree", "trek", "trig", "trim", "trio", +"trod", "trot", "troy", "true", "tuba", "tube", "tuck", "tuft", +"tuna", "tune", "tung", "turf", "turn", "tusk", "twig", "twin", +"twit", "ulan", "unit", "urge", "used", "user", "uses", "utah", +"vail", "vain", "vale", "vary", "vase", "vast", "veal", "veda", +"veil", "vein", "vend", "vent", "verb", "very", "veto", "vice", +"view", "vine", "vise", "void", "volt", "vote", "wack", "wade", +"wage", "wail", "wait", "wake", "wale", "walk", "wall", "walt", +"wand", "wane", "wang", "want", "ward", "warm", "warn", "wart", +"wash", "wast", "wats", "watt", "wave", "wavy", "ways", "weak", +"weal", "wean", "wear", "weed", "week", "weir", "weld", "well", +"welt", "went", "were", "wert", "west", "wham", "what", "whee", +"when", "whet", "whoa", "whom", "wick", "wife", "wild", "will", +"wind", "wine", "wing", "wink", "wino", "wire", "wise", "wish", +"with", "wolf", "wont", "wood", "wool", "word", "wore", "work", +"worm", "worn", "wove", "writ", "wynn", "yale", "yang", "yank", +"yard", "yarn", "yawl", "yawn", "yeah", "year", "yell", "yoga", +"yoke" }; + +const char *getSkeyWd(unsigned int n) +{ + return skeylist[n & 0x7ff]; +} -- cgit v1.2.3