/* * Passogva 1.0 - A random password generator based on FIPS-181 * * Copyright (c) 2004 Steven Hazel * * Permission to use, copy, modify, distribute, and sell this software * and its documentation for any purpose is hereby granted without * fee, provided that the above copyright notice appear in all copies * and that both that copyright notice and this permission notice * appear in supporting documentation. No representations are made * about the suitability of this software for any purpose. It is * provided "as is" without express or implied warranty. * * See Also: * FIPS 181 - (APG), Automated Password Generator: * http://www.itl.nist.gov/fipspubs/fip181.htm * * This is a C language implementation of the Automated Password * Generator standard, like the program described in "A Random Word * Generator For Pronounceable Passwords". This code is based on the * program contained in Appendix A of FIPS Publication 181, "Standard * for Automated Password Generator". In accordance with the * standard, the results obtained from this program are logically * equivalent to those produced by the standard. * * Deviations From Standard: * * This implementation deviates in one critical way from the standard * upon which it is based: the random number generator in this * implementation does not use DES. Instead, it uses the rand(3) * system call. */ #include #include #include #include #include #include #define PASSOGVA_DEBUG #define B1 #define TRUE 1 #define FALSE 0 #define NUM_RULES 34 #define ALLOWED(flag) (digram[units_in_syllable[current_unit - 1]][unit]\ & (flag)) #define MAX_UNACCEPTABLE 20 #define MAX_RETRIES (4 * (int) pwlen + NUM_RULES) #define NOT_BEGIN_SYLLABLE 010 #define NO_FINAL_SPLIT 004 #define VOWEL 002 #define ALTERNATE_VOWEL 001 #define NO_SPECIAL_RULE 000 #define BEGIN 0200 #define NOT_BEGIN 0100 #define BREAK 0040 #define PREFIX 0020 #define ILLEGAL_PAIR 0010 #define SUFFIX 0004 #define END 0002 #define NOT_END 0001 #define ANY_COMBINATION 0000 typedef int boolean; static int get_word (char *word, char *hyphenated_word, unsigned short pwlen); static boolean have_initial_y (unsigned short *units, unsigned short unit_size); static boolean illegal_placement (unsigned short *units, unsigned short pwlen); static boolean improper_word (unsigned short *units, unsigned short word_size); static boolean have_final_split (unsigned short *units, unsigned short unit_size); static char *get_syllable (char *syllable, unsigned short pwlen, unsigned short *units_in_syllable, unsigned short *syllable_length); static unsigned short random_unit (unsigned short type); static unsigned int randint(int n); static unsigned short get_random (unsigned short minlen, unsigned short maxlen); static void set_seed(long seed); int randomchars (char *string, unsigned short minlen, unsigned short maxlen, boolean restrict, long seed); int randomletters (char *string, unsigned short minlen, unsigned short maxlen, boolean restrict, long seed); int randomword (char *word, char *hyphenated_word, unsigned short minlen, unsigned short maxlen, boolean restrict, long seed); struct unit { char unit_code[5]; unsigned short flags; }; static struct unit rules[NUM_RULES] = { {"a", VOWEL}, {"b", NO_SPECIAL_RULE}, {"c", NO_SPECIAL_RULE}, {"d", NO_SPECIAL_RULE}, {"e", NO_FINAL_SPLIT | VOWEL}, {"f", NO_SPECIAL_RULE}, {"g", NO_SPECIAL_RULE}, {"h", NO_SPECIAL_RULE}, {"i", VOWEL}, {"j", NO_SPECIAL_RULE}, {"k", NO_SPECIAL_RULE}, {"l", NO_SPECIAL_RULE}, {"m", NO_SPECIAL_RULE}, {"n", NO_SPECIAL_RULE}, {"o", VOWEL}, {"p", NO_SPECIAL_RULE}, {"r", NO_SPECIAL_RULE}, {"s", NO_SPECIAL_RULE}, {"t", NO_SPECIAL_RULE}, {"u", VOWEL}, {"v", NO_SPECIAL_RULE}, {"w", NO_SPECIAL_RULE}, {"x", NOT_BEGIN_SYLLABLE}, {"y", ALTERNATE_VOWEL | VOWEL}, {"z", NO_SPECIAL_RULE}, {"ch", NO_SPECIAL_RULE}, {"gh", NO_SPECIAL_RULE}, {"ph", NO_SPECIAL_RULE}, {"rh", NO_SPECIAL_RULE}, {"sh", NO_SPECIAL_RULE}, {"th", NO_SPECIAL_RULE}, {"wh", NO_SPECIAL_RULE}, {"qu", NO_SPECIAL_RULE}, {"ck", NOT_BEGIN_SYLLABLE} }; static int digram[NUM_RULES][NUM_RULES] = { { /* aa */ ILLEGAL_PAIR, /* ab */ ANY_COMBINATION, /* ac */ ANY_COMBINATION, /* ad */ ANY_COMBINATION, /* ae */ ILLEGAL_PAIR, /* af */ ANY_COMBINATION, /* ag */ ANY_COMBINATION, /* ah */ NOT_BEGIN | BREAK | NOT_END, /* ai */ ANY_COMBINATION, /* aj */ ANY_COMBINATION, /* ak */ ANY_COMBINATION, /* al */ ANY_COMBINATION, /* am */ ANY_COMBINATION, /* an */ ANY_COMBINATION, /* ao */ ILLEGAL_PAIR, /* ap */ ANY_COMBINATION, /* ar */ ANY_COMBINATION, /* as */ ANY_COMBINATION, /* at */ ANY_COMBINATION, /* au */ ANY_COMBINATION, /* av */ ANY_COMBINATION, /* aw */ ANY_COMBINATION, /* ax */ ANY_COMBINATION, /* ay */ ANY_COMBINATION, /* az */ ANY_COMBINATION, /* ach */ ANY_COMBINATION, /* agh */ ILLEGAL_PAIR, /* aph */ ANY_COMBINATION, /* arh */ ILLEGAL_PAIR, /* ash */ ANY_COMBINATION, /* ath */ ANY_COMBINATION, /* awh */ ILLEGAL_PAIR, /* aqu */ BREAK | NOT_END, /* ack */ ANY_COMBINATION }, { /* ba */ ANY_COMBINATION, /* bb */ NOT_BEGIN | BREAK | NOT_END, /* bc */ NOT_BEGIN | BREAK | NOT_END, /* bd */ NOT_BEGIN | BREAK | NOT_END, /* be */ ANY_COMBINATION, /* bf */ NOT_BEGIN | BREAK | NOT_END, /* bg */ NOT_BEGIN | BREAK | NOT_END, /* bh */ NOT_BEGIN | BREAK | NOT_END, /* bi */ ANY_COMBINATION, /* bj */ NOT_BEGIN | BREAK | NOT_END, /* bk */ NOT_BEGIN | BREAK | NOT_END, /* bl */ BEGIN | SUFFIX | NOT_END, /* bm */ NOT_BEGIN | BREAK | NOT_END, /* bn */ NOT_BEGIN | BREAK | NOT_END, /* bo */ ANY_COMBINATION, /* bp */ NOT_BEGIN | BREAK | NOT_END, /* br */ BEGIN | END, /* bs */ NOT_BEGIN, /* bt */ NOT_BEGIN | BREAK | NOT_END, /* bu */ ANY_COMBINATION, /* bv */ NOT_BEGIN | BREAK | NOT_END, /* bw */ NOT_BEGIN | BREAK | NOT_END, /* bx */ ILLEGAL_PAIR, /* by */ ANY_COMBINATION, /* bz */ NOT_BEGIN | BREAK | NOT_END, /* bch */ NOT_BEGIN | BREAK | NOT_END, /* bgh */ ILLEGAL_PAIR, /* bph */ NOT_BEGIN | BREAK | NOT_END, /* brh */ ILLEGAL_PAIR, /* bsh */ NOT_BEGIN | BREAK | NOT_END, /* bth */ NOT_BEGIN | BREAK | NOT_END, /* bwh */ ILLEGAL_PAIR, /* bqu */ NOT_BEGIN | BREAK | NOT_END, /* bck */ ILLEGAL_PAIR }, { /* ca */ ANY_COMBINATION, /* cb */ NOT_BEGIN | BREAK | NOT_END, /* cc */ NOT_BEGIN | BREAK | NOT_END, /* cd */ NOT_BEGIN | BREAK | NOT_END, /* ce */ ANY_COMBINATION, /* cf */ NOT_BEGIN | BREAK | NOT_END, /* cg */ NOT_BEGIN | BREAK | NOT_END, /* ch */ NOT_BEGIN | BREAK | NOT_END, /* ci */ ANY_COMBINATION, /* cj */ NOT_BEGIN | BREAK | NOT_END, /* ck */ NOT_BEGIN | BREAK | NOT_END, /* cl */ SUFFIX | NOT_END, /* cm */ NOT_BEGIN | BREAK | NOT_END, /* cn */ NOT_BEGIN | BREAK | NOT_END, /* co */ ANY_COMBINATION, /* cp */ NOT_BEGIN | BREAK | NOT_END, /* cr */ NOT_END, /* cs */ NOT_BEGIN | END, /* ct */ NOT_BEGIN | PREFIX, /* cu */ ANY_COMBINATION, /* cv */ NOT_BEGIN | BREAK | NOT_END, /* cw */ NOT_BEGIN | BREAK | NOT_END, /* cx */ ILLEGAL_PAIR, /* cy */ ANY_COMBINATION, /* cz */ NOT_BEGIN | BREAK | NOT_END, /* cch */ ILLEGAL_PAIR, /* cgh */ ILLEGAL_PAIR, /* cph */ NOT_BEGIN | BREAK | NOT_END, /* crh */ ILLEGAL_PAIR, /* csh */ NOT_BEGIN | BREAK | NOT_END, /* cth */ NOT_BEGIN | BREAK | NOT_END, /* cwh */ ILLEGAL_PAIR, /* cqu */ NOT_BEGIN | SUFFIX | NOT_END, /* cck */ ILLEGAL_PAIR }, { /* da */ ANY_COMBINATION, /* db */ NOT_BEGIN | BREAK | NOT_END, /* dc */ NOT_BEGIN | BREAK | NOT_END, /* dd */ NOT_BEGIN, /* de */ ANY_COMBINATION, /* df */ NOT_BEGIN | BREAK | NOT_END, /* dg */ NOT_BEGIN | BREAK | NOT_END, /* dh */ NOT_BEGIN | BREAK | NOT_END, /* di */ ANY_COMBINATION, /* dj */ NOT_BEGIN | BREAK | NOT_END, /* dk */ NOT_BEGIN | BREAK | NOT_END, /* dl */ NOT_BEGIN | BREAK | NOT_END, /* dm */ NOT_BEGIN | BREAK | NOT_END, /* dn */ NOT_BEGIN | BREAK | NOT_END, /* do */ ANY_COMBINATION, /* dp */ NOT_BEGIN | BREAK | NOT_END, /* dr */ BEGIN | NOT_END, /* ds */ NOT_BEGIN | END, /* dt */ NOT_BEGIN | BREAK | NOT_END, /* du */ ANY_COMBINATION, /* dv */ NOT_BEGIN | BREAK | NOT_END, /* dw */ NOT_BEGIN | BREAK | NOT_END, /* dx */ ILLEGAL_PAIR, /* dy */ ANY_COMBINATION, /* dz */ NOT_BEGIN | BREAK | NOT_END, /* dch */ NOT_BEGIN | BREAK | NOT_END, /* dgh */ NOT_BEGIN | BREAK | NOT_END, /* dph */ NOT_BEGIN | BREAK | NOT_END, /* drh */ ILLEGAL_PAIR, /* dsh */ NOT_BEGIN | NOT_END, /* dth */ NOT_BEGIN | PREFIX, /* dwh */ ILLEGAL_PAIR, /* dqu */ NOT_BEGIN | BREAK | NOT_END, /* dck */ ILLEGAL_PAIR }, { /* ea */ ANY_COMBINATION, /* eb */ ANY_COMBINATION, /* ec */ ANY_COMBINATION, /* ed */ ANY_COMBINATION, /* ee */ ANY_COMBINATION, /* ef */ ANY_COMBINATION, /* eg */ ANY_COMBINATION, /* eh */ NOT_BEGIN | BREAK | NOT_END, /* ei */ NOT_END, /* ej */ ANY_COMBINATION, /* ek */ ANY_COMBINATION, /* el */ ANY_COMBINATION, /* em */ ANY_COMBINATION, /* en */ ANY_COMBINATION, /* eo */ BREAK, /* ep */ ANY_COMBINATION, /* er */ ANY_COMBINATION, /* es */ ANY_COMBINATION, /* et */ ANY_COMBINATION, /* eu */ ANY_COMBINATION, /* ev */ ANY_COMBINATION, /* ew */ ANY_COMBINATION, /* ex */ ANY_COMBINATION, /* ey */ ANY_COMBINATION, /* ez */ ANY_COMBINATION, /* ech */ ANY_COMBINATION, /* egh */ NOT_BEGIN | BREAK | NOT_END, /* eph */ ANY_COMBINATION, /* erh */ ILLEGAL_PAIR, /* esh */ ANY_COMBINATION, /* eth */ ANY_COMBINATION, /* ewh */ ILLEGAL_PAIR, /* equ */ BREAK | NOT_END, /* eck */ ANY_COMBINATION }, { /* fa */ ANY_COMBINATION, /* fb */ NOT_BEGIN | BREAK | NOT_END, /* fc */ NOT_BEGIN | BREAK | NOT_END, /* fd */ NOT_BEGIN | BREAK | NOT_END, /* fe */ ANY_COMBINATION, /* ff */ NOT_BEGIN, /* fg */ NOT_BEGIN | BREAK | NOT_END, /* fh */ NOT_BEGIN | BREAK | NOT_END, /* fi */ ANY_COMBINATION, /* fj */ NOT_BEGIN | BREAK | NOT_END, /* fk */ NOT_BEGIN | BREAK | NOT_END, /* fl */ BEGIN | SUFFIX | NOT_END, /* fm */ NOT_BEGIN | BREAK | NOT_END, /* fn */ NOT_BEGIN | BREAK | NOT_END, /* fo */ ANY_COMBINATION, /* fp */ NOT_BEGIN | BREAK | NOT_END, /* fr */ BEGIN | NOT_END, /* fs */ NOT_BEGIN, /* ft */ NOT_BEGIN, /* fu */ ANY_COMBINATION, /* fv */ NOT_BEGIN | BREAK | NOT_END, /* fw */ NOT_BEGIN | BREAK | NOT_END, /* fx */ ILLEGAL_PAIR, /* fy */ NOT_BEGIN, /* fz */ NOT_BEGIN | BREAK | NOT_END, /* fch */ NOT_BEGIN | BREAK | NOT_END, /* fgh */ NOT_BEGIN | BREAK | NOT_END, /* fph */ NOT_BEGIN | BREAK | NOT_END, /* frh */ ILLEGAL_PAIR, /* fsh */ NOT_BEGIN | BREAK | NOT_END, /* fth */ NOT_BEGIN | BREAK | NOT_END, /* fwh */ ILLEGAL_PAIR, /* fqu */ NOT_BEGIN | BREAK | NOT_END, /* fck */ ILLEGAL_PAIR }, { /* ga */ ANY_COMBINATION, /* gb */ NOT_BEGIN | BREAK | NOT_END, /* gc */ NOT_BEGIN | BREAK | NOT_END, /* gd */ NOT_BEGIN | BREAK | NOT_END, /* ge */ ANY_COMBINATION, /* gf */ NOT_BEGIN | BREAK | NOT_END, /* gg */ NOT_BEGIN, /* gh */ NOT_BEGIN | BREAK | NOT_END, /* gi */ ANY_COMBINATION, /* gj */ NOT_BEGIN | BREAK | NOT_END, /* gk */ ILLEGAL_PAIR, /* gl */ BEGIN | SUFFIX | NOT_END, /* gm */ NOT_BEGIN | BREAK | NOT_END, /* gn */ NOT_BEGIN | BREAK | NOT_END, /* go */ ANY_COMBINATION, /* gp */ NOT_BEGIN | BREAK | NOT_END, /* gr */ BEGIN | NOT_END, /* gs */ NOT_BEGIN | END, /* gt */ NOT_BEGIN | BREAK | NOT_END, /* gu */ ANY_COMBINATION, /* gv */ NOT_BEGIN | BREAK | NOT_END, /* gw */ NOT_BEGIN | BREAK | NOT_END, /* gx */ ILLEGAL_PAIR, /* gy */ NOT_BEGIN, /* gz */ NOT_BEGIN | BREAK | NOT_END, /* gch */ NOT_BEGIN | BREAK | NOT_END, /* ggh */ ILLEGAL_PAIR, /* gph */ NOT_BEGIN | BREAK | NOT_END, /* grh */ ILLEGAL_PAIR, /* gsh */ NOT_BEGIN, /* gth */ NOT_BEGIN, /* gwh */ ILLEGAL_PAIR, /* gqu */ NOT_BEGIN | BREAK | NOT_END, /* gck */ ILLEGAL_PAIR }, { /* ha */ ANY_COMBINATION, /* hb */ NOT_BEGIN | BREAK | NOT_END, /* hc */ NOT_BEGIN | BREAK | NOT_END, /* hd */ NOT_BEGIN | BREAK | NOT_END, /* he */ ANY_COMBINATION, /* hf */ NOT_BEGIN | BREAK | NOT_END, /* hg */ NOT_BEGIN | BREAK | NOT_END, /* hh */ ILLEGAL_PAIR, /* hi */ ANY_COMBINATION, /* hj */ NOT_BEGIN | BREAK | NOT_END, /* hk */ NOT_BEGIN | BREAK | NOT_END, /* hl */ NOT_BEGIN | BREAK | NOT_END, /* hm */ NOT_BEGIN | BREAK | NOT_END, /* hn */ NOT_BEGIN | BREAK | NOT_END, /* ho */ ANY_COMBINATION, /* hp */ NOT_BEGIN | BREAK | NOT_END, /* hr */ NOT_BEGIN | BREAK | NOT_END, /* hs */ NOT_BEGIN | BREAK | NOT_END, /* ht */ NOT_BEGIN | BREAK | NOT_END, /* hu */ ANY_COMBINATION, /* hv */ NOT_BEGIN | BREAK | NOT_END, /* hw */ NOT_BEGIN | BREAK | NOT_END, /* hx */ ILLEGAL_PAIR, /* hy */ ANY_COMBINATION, /* hz */ NOT_BEGIN | BREAK | NOT_END, /* hch */ NOT_BEGIN | BREAK | NOT_END, /* hgh */ NOT_BEGIN | BREAK | NOT_END, /* hph */ NOT_BEGIN | BREAK | NOT_END, /* hrh */ ILLEGAL_PAIR, /* hsh */ NOT_BEGIN | BREAK | NOT_END, /* hth */ NOT_BEGIN | BREAK | NOT_END, /* hwh */ ILLEGAL_PAIR, /* hqu */ NOT_BEGIN | BREAK | NOT_END, /* hck */ ILLEGAL_PAIR }, { /* ia */ ANY_COMBINATION, /* ib */ ANY_COMBINATION, /* ic */ ANY_COMBINATION, /* id */ ANY_COMBINATION, /* ie */ NOT_BEGIN, /* if */ ANY_COMBINATION, /* ig */ ANY_COMBINATION, /* ih */ NOT_BEGIN | BREAK | NOT_END, /* ii */ ILLEGAL_PAIR, /* ij */ ANY_COMBINATION, /* ik */ ANY_COMBINATION, /* il */ ANY_COMBINATION, /* im */ ANY_COMBINATION, /* in */ ANY_COMBINATION, /* io */ BREAK, /* ip */ ANY_COMBINATION, /* ir */ ANY_COMBINATION, /* is */ ANY_COMBINATION, /* it */ ANY_COMBINATION, /* iu */ NOT_BEGIN | BREAK | NOT_END, /* iv */ ANY_COMBINATION, /* iw */ NOT_BEGIN | BREAK | NOT_END, /* ix */ ANY_COMBINATION, /* iy */ NOT_BEGIN | BREAK | NOT_END, /* iz */ ANY_COMBINATION, /* ich */ ANY_COMBINATION, /* igh */ NOT_BEGIN, /* iph */ ANY_COMBINATION, /* irh */ ILLEGAL_PAIR, /* ish */ ANY_COMBINATION, /* ith */ ANY_COMBINATION, /* iwh */ ILLEGAL_PAIR, /* iqu */ BREAK | NOT_END, /* ick */ ANY_COMBINATION }, { /* ja */ ANY_COMBINATION, /* jb */ NOT_BEGIN | BREAK | NOT_END, /* jc */ NOT_BEGIN | BREAK | NOT_END, /* jd */ NOT_BEGIN | BREAK | NOT_END, /* je */ ANY_COMBINATION, /* jf */ NOT_BEGIN | BREAK | NOT_END, /* jg */ ILLEGAL_PAIR, /* jh */ NOT_BEGIN | BREAK | NOT_END, /* ji */ ANY_COMBINATION, /* jj */ ILLEGAL_PAIR, /* jk */ NOT_BEGIN | BREAK | NOT_END, /* jl */ NOT_BEGIN | BREAK | NOT_END, /* jm */ NOT_BEGIN | BREAK | NOT_END, /* jn */ NOT_BEGIN | BREAK | NOT_END, /* jo */ ANY_COMBINATION, /* jp */ NOT_BEGIN | BREAK | NOT_END, /* jr */ NOT_BEGIN | BREAK | NOT_END, /* js */ NOT_BEGIN | BREAK | NOT_END, /* jt */ NOT_BEGIN | BREAK | NOT_END, /* ju */ ANY_COMBINATION, /* jv */ NOT_BEGIN | BREAK | NOT_END, /* jw */ NOT_BEGIN | BREAK | NOT_END, /* jx */ ILLEGAL_PAIR, /* jy */ NOT_BEGIN, /* jz */ NOT_BEGIN | BREAK | NOT_END, /* jch */ NOT_BEGIN | BREAK | NOT_END, /* jgh */ NOT_BEGIN | BREAK | NOT_END, /* jph */ NOT_BEGIN | BREAK | NOT_END, /* jrh */ ILLEGAL_PAIR, /* jsh */ NOT_BEGIN | BREAK | NOT_END, /* jth */ NOT_BEGIN | BREAK | NOT_END, /* jwh */ ILLEGAL_PAIR, /* jqu */ NOT_BEGIN | BREAK | NOT_END, /* jck */ ILLEGAL_PAIR }, { /* ka */ ANY_COMBINATION, /* kb */ NOT_BEGIN | BREAK | NOT_END, /* kc */ NOT_BEGIN | BREAK | NOT_END, /* kd */ NOT_BEGIN | BREAK | NOT_END, /* ke */ ANY_COMBINATION, /* kf */ NOT_BEGIN | BREAK | NOT_END, /* kg */ NOT_BEGIN | BREAK | NOT_END, /* kh */ NOT_BEGIN | BREAK | NOT_END, /* ki */ ANY_COMBINATION, /* kj */ NOT_BEGIN | BREAK | NOT_END, /* kk */ NOT_BEGIN | BREAK | NOT_END, /* kl */ SUFFIX | NOT_END, /* km */ NOT_BEGIN | BREAK | NOT_END, /* kn */ BEGIN | SUFFIX | NOT_END, /* ko */ ANY_COMBINATION, /* kp */ NOT_BEGIN | BREAK | NOT_END, /* kr */ SUFFIX | NOT_END, /* ks */ NOT_BEGIN | END, /* kt */ NOT_BEGIN | BREAK | NOT_END, /* ku */ ANY_COMBINATION, /* kv */ NOT_BEGIN | BREAK | NOT_END, /* kw */ NOT_BEGIN | BREAK | NOT_END, /* kx */ ILLEGAL_PAIR, /* ky */ NOT_BEGIN, /* kz */ NOT_BEGIN | BREAK | NOT_END, /* kch */ NOT_BEGIN | BREAK | NOT_END, /* kgh */ NOT_BEGIN | BREAK | NOT_END, /* kph */ NOT_BEGIN | PREFIX, /* krh */ ILLEGAL_PAIR, /* ksh */ NOT_BEGIN, /* kth */ NOT_BEGIN | BREAK | NOT_END, /* kwh */ ILLEGAL_PAIR, /* kqu */ NOT_BEGIN | BREAK | NOT_END, /* kck */ ILLEGAL_PAIR }, { /* la */ ANY_COMBINATION, /* lb */ NOT_BEGIN | PREFIX, /* lc */ NOT_BEGIN | BREAK | NOT_END, /* ld */ NOT_BEGIN | PREFIX, /* le */ ANY_COMBINATION, /* lf */ NOT_BEGIN | PREFIX, /* lg */ NOT_BEGIN | PREFIX, /* lh */ NOT_BEGIN | BREAK | NOT_END, /* li */ ANY_COMBINATION, /* lj */ NOT_BEGIN | PREFIX, /* lk */ NOT_BEGIN | PREFIX, /* ll */ NOT_BEGIN | PREFIX, /* lm */ NOT_BEGIN | PREFIX, /* ln */ NOT_BEGIN | BREAK | NOT_END, /* lo */ ANY_COMBINATION, /* lp */ NOT_BEGIN | PREFIX, /* lr */ NOT_BEGIN | BREAK | NOT_END, /* ls */ NOT_BEGIN, /* lt */ NOT_BEGIN | PREFIX, /* lu */ ANY_COMBINATION, /* lv */ NOT_BEGIN | PREFIX, /* lw */ NOT_BEGIN | BREAK | NOT_END, /* lx */ ILLEGAL_PAIR, /* ly */ ANY_COMBINATION, /* lz */ NOT_BEGIN | BREAK | NOT_END, /* lch */ NOT_BEGIN | PREFIX, /* lgh */ NOT_BEGIN | BREAK | NOT_END, /* lph */ NOT_BEGIN | PREFIX, /* lrh */ ILLEGAL_PAIR, /* lsh */ NOT_BEGIN | PREFIX, /* lth */ NOT_BEGIN | PREFIX, /* lwh */ ILLEGAL_PAIR, /* lqu */ NOT_BEGIN | BREAK | NOT_END, /* lck */ ILLEGAL_PAIR }, { /* ma */ ANY_COMBINATION, /* mb */ NOT_BEGIN | BREAK | NOT_END, /* mc */ NOT_BEGIN | BREAK | NOT_END, /* md */ NOT_BEGIN | BREAK | NOT_END, /* me */ ANY_COMBINATION, /* mf */ NOT_BEGIN | BREAK | NOT_END, /* mg */ NOT_BEGIN | BREAK | NOT_END, /* mh */ NOT_BEGIN | BREAK | NOT_END, /* mi */ ANY_COMBINATION, /* mj */ NOT_BEGIN | BREAK | NOT_END, /* mk */ NOT_BEGIN | BREAK | NOT_END, /* ml */ NOT_BEGIN | BREAK | NOT_END, /* mm */ NOT_BEGIN, /* mn */ NOT_BEGIN | BREAK | NOT_END, /* mo */ ANY_COMBINATION, /* mp */ NOT_BEGIN, /* mr */ NOT_BEGIN | BREAK | NOT_END, /* ms */ NOT_BEGIN, /* mt */ NOT_BEGIN, /* mu */ ANY_COMBINATION, /* mv */ NOT_BEGIN | BREAK | NOT_END, /* mw */ NOT_BEGIN | BREAK | NOT_END, /* mx */ ILLEGAL_PAIR, /* my */ ANY_COMBINATION, /* mz */ NOT_BEGIN | BREAK | NOT_END, /* mch */ NOT_BEGIN | PREFIX, /* mgh */ NOT_BEGIN | BREAK | NOT_END, /* mph */ NOT_BEGIN, /* mrh */ ILLEGAL_PAIR, /* msh */ NOT_BEGIN, /* mth */ NOT_BEGIN, /* mwh */ ILLEGAL_PAIR, /* mqu */ NOT_BEGIN | BREAK | NOT_END, /* mck */ ILLEGAL_PAIR }, { /* na */ ANY_COMBINATION, /* nb */ NOT_BEGIN | BREAK | NOT_END, /* nc */ NOT_BEGIN | BREAK | NOT_END, /* nd */ NOT_BEGIN, /* ne */ ANY_COMBINATION, /* nf */ NOT_BEGIN | BREAK | NOT_END, /* ng */ NOT_BEGIN | PREFIX, /* nh */ NOT_BEGIN | BREAK | NOT_END, /* ni */ ANY_COMBINATION, /* nj */ NOT_BEGIN | BREAK | NOT_END, /* nk */ NOT_BEGIN | PREFIX, /* nl */ NOT_BEGIN | BREAK | NOT_END, /* nm */ NOT_BEGIN | BREAK | NOT_END, /* nn */ NOT_BEGIN, /* no */ ANY_COMBINATION, /* np */ NOT_BEGIN | BREAK | NOT_END, /* nr */ NOT_BEGIN | BREAK | NOT_END, /* ns */ NOT_BEGIN, /* nt */ NOT_BEGIN, /* nu */ ANY_COMBINATION, /* nv */ NOT_BEGIN | BREAK | NOT_END, /* nw */ NOT_BEGIN | BREAK | NOT_END, /* nx */ ILLEGAL_PAIR, /* ny */ NOT_BEGIN, /* nz */ NOT_BEGIN | BREAK | NOT_END, /* nch */ NOT_BEGIN | PREFIX, /* ngh */ NOT_BEGIN | BREAK | NOT_END, /* nph */ NOT_BEGIN | PREFIX, /* nrh */ ILLEGAL_PAIR, /* nsh */ NOT_BEGIN, /* nth */ NOT_BEGIN, /* nwh */ ILLEGAL_PAIR, /* nqu */ NOT_BEGIN | BREAK | NOT_END, /* nck */ NOT_BEGIN | PREFIX }, { /* oa */ ANY_COMBINATION, /* ob */ ANY_COMBINATION, /* oc */ ANY_COMBINATION, /* od */ ANY_COMBINATION, /* oe */ ILLEGAL_PAIR, /* of */ ANY_COMBINATION, /* og */ ANY_COMBINATION, /* oh */ NOT_BEGIN | BREAK | NOT_END, /* oi */ ANY_COMBINATION, /* oj */ ANY_COMBINATION, /* ok */ ANY_COMBINATION, /* ol */ ANY_COMBINATION, /* om */ ANY_COMBINATION, /* on */ ANY_COMBINATION, /* oo */ ANY_COMBINATION, /* op */ ANY_COMBINATION, /* or */ ANY_COMBINATION, /* os */ ANY_COMBINATION, /* ot */ ANY_COMBINATION, /* ou */ ANY_COMBINATION, /* ov */ ANY_COMBINATION, /* ow */ ANY_COMBINATION, /* ox */ ANY_COMBINATION, /* oy */ ANY_COMBINATION, /* oz */ ANY_COMBINATION, /* och */ ANY_COMBINATION, /* ogh */ NOT_BEGIN, /* oph */ ANY_COMBINATION, /* orh */ ILLEGAL_PAIR, /* osh */ ANY_COMBINATION, /* oth */ ANY_COMBINATION, /* owh */ ILLEGAL_PAIR, /* oqu */ BREAK | NOT_END, /* ock */ ANY_COMBINATION }, { /* pa */ ANY_COMBINATION, /* pb */ NOT_BEGIN | BREAK | NOT_END, /* pc */ NOT_BEGIN | BREAK | NOT_END, /* pd */ NOT_BEGIN | BREAK | NOT_END, /* pe */ ANY_COMBINATION, /* pf */ NOT_BEGIN | BREAK | NOT_END, /* pg */ NOT_BEGIN | BREAK | NOT_END, /* ph */ NOT_BEGIN | BREAK | NOT_END, /* pi */ ANY_COMBINATION, /* pj */ NOT_BEGIN | BREAK | NOT_END, /* pk */ NOT_BEGIN | BREAK | NOT_END, /* pl */ SUFFIX | NOT_END, /* pm */ NOT_BEGIN | BREAK | NOT_END, /* pn */ NOT_BEGIN | BREAK | NOT_END, /* po */ ANY_COMBINATION, /* pp */ NOT_BEGIN | PREFIX, /* pr */ NOT_END, /* ps */ NOT_BEGIN | END, /* pt */ NOT_BEGIN | END, /* pu */ NOT_BEGIN | END, /* pv */ NOT_BEGIN | BREAK | NOT_END, /* pw */ NOT_BEGIN | BREAK | NOT_END, /* px */ ILLEGAL_PAIR, /* py */ ANY_COMBINATION, /* pz */ NOT_BEGIN | BREAK | NOT_END, /* pch */ NOT_BEGIN | BREAK | NOT_END, /* pgh */ NOT_BEGIN | BREAK | NOT_END, /* pph */ NOT_BEGIN | BREAK | NOT_END, /* prh */ ILLEGAL_PAIR, /* psh */ NOT_BEGIN | BREAK | NOT_END, /* pth */ NOT_BEGIN | BREAK | NOT_END, /* pwh */ ILLEGAL_PAIR, /* pqu */ NOT_BEGIN | BREAK | NOT_END, /* pck */ ILLEGAL_PAIR }, { /* ra */ ANY_COMBINATION, /* rb */ NOT_BEGIN | PREFIX, /* rc */ NOT_BEGIN | PREFIX, /* rd */ NOT_BEGIN | PREFIX, /* re */ ANY_COMBINATION, /* rf */ NOT_BEGIN | PREFIX, /* rg */ NOT_BEGIN | PREFIX, /* rh */ NOT_BEGIN | BREAK | NOT_END, /* ri */ ANY_COMBINATION, /* rj */ NOT_BEGIN | PREFIX, /* rk */ NOT_BEGIN | PREFIX, /* rl */ NOT_BEGIN | PREFIX, /* rm */ NOT_BEGIN | PREFIX, /* rn */ NOT_BEGIN | PREFIX, /* ro */ ANY_COMBINATION, /* rp */ NOT_BEGIN | PREFIX, /* rr */ NOT_BEGIN | PREFIX, /* rs */ NOT_BEGIN | PREFIX, /* rt */ NOT_BEGIN | PREFIX, /* ru */ ANY_COMBINATION, /* rv */ NOT_BEGIN | PREFIX, /* rw */ NOT_BEGIN | BREAK | NOT_END, /* rx */ ILLEGAL_PAIR, /* ry */ ANY_COMBINATION, /* rz */ NOT_BEGIN | PREFIX, /* rch */ NOT_BEGIN | PREFIX, /* rgh */ NOT_BEGIN | BREAK | NOT_END, /* rph */ NOT_BEGIN | PREFIX, /* rrh */ ILLEGAL_PAIR, /* rsh */ NOT_BEGIN | PREFIX, /* rth */ NOT_BEGIN | PREFIX, /* rwh */ ILLEGAL_PAIR, /* rqu */ NOT_BEGIN | PREFIX | NOT_END, /* rck */ NOT_BEGIN | PREFIX }, { /* sa */ ANY_COMBINATION, /* sb */ NOT_BEGIN | BREAK | NOT_END, /* sc */ NOT_END, /* sd */ NOT_BEGIN | BREAK | NOT_END, /* se */ ANY_COMBINATION, /* sf */ NOT_BEGIN | BREAK | NOT_END, /* sg */ NOT_BEGIN | BREAK | NOT_END, /* sh */ NOT_BEGIN | BREAK | NOT_END, /* si */ ANY_COMBINATION, /* sj */ NOT_BEGIN | BREAK | NOT_END, /* sk */ ANY_COMBINATION, /* sl */ BEGIN | SUFFIX | NOT_END, /* sm */ SUFFIX | NOT_END, /* sn */ PREFIX | SUFFIX | NOT_END, /* so */ ANY_COMBINATION, /* sp */ ANY_COMBINATION, /* sr */ NOT_BEGIN | NOT_END, /* ss */ NOT_BEGIN | PREFIX, /* st */ ANY_COMBINATION, /* su */ ANY_COMBINATION, /* sv */ NOT_BEGIN | BREAK | NOT_END, /* sw */ BEGIN | SUFFIX | NOT_END, /* sx */ ILLEGAL_PAIR, /* sy */ ANY_COMBINATION, /* sz */ NOT_BEGIN | BREAK | NOT_END, /* sch */ BEGIN | SUFFIX | NOT_END, /* sgh */ NOT_BEGIN | BREAK | NOT_END, /* sph */ NOT_BEGIN | BREAK | NOT_END, /* srh */ ILLEGAL_PAIR, /* ssh */ NOT_BEGIN | BREAK | NOT_END, /* sth */ NOT_BEGIN | BREAK | NOT_END, /* swh */ ILLEGAL_PAIR, /* squ */ SUFFIX | NOT_END, /* sck */ NOT_BEGIN }, { /* ta */ ANY_COMBINATION, /* tb */ NOT_BEGIN | BREAK | NOT_END, /* tc */ NOT_BEGIN | BREAK | NOT_END, /* td */ NOT_BEGIN | BREAK | NOT_END, /* te */ ANY_COMBINATION, /* tf */ NOT_BEGIN | BREAK | NOT_END, /* tg */ NOT_BEGIN | BREAK | NOT_END, /* th */ NOT_BEGIN | BREAK | NOT_END, /* ti */ ANY_COMBINATION, /* tj */ NOT_BEGIN | BREAK | NOT_END, /* tk */ NOT_BEGIN | BREAK | NOT_END, /* tl */ NOT_BEGIN | BREAK | NOT_END, /* tm */ NOT_BEGIN | BREAK | NOT_END, /* tn */ NOT_BEGIN | BREAK | NOT_END, /* to */ ANY_COMBINATION, /* tp */ NOT_BEGIN | BREAK | NOT_END, /* tr */ NOT_END, /* ts */ NOT_BEGIN | END, /* tt */ NOT_BEGIN | PREFIX, /* tu */ ANY_COMBINATION, /* tv */ NOT_BEGIN | BREAK | NOT_END, /* tw */ BEGIN | SUFFIX | NOT_END, /* tx */ ILLEGAL_PAIR, /* ty */ ANY_COMBINATION, /* tz */ NOT_BEGIN | BREAK | NOT_END, /* tch */ NOT_BEGIN, /* tgh */ NOT_BEGIN | BREAK | NOT_END, /* tph */ NOT_BEGIN | END, /* trh */ ILLEGAL_PAIR, /* tsh */ NOT_BEGIN | END, /* tth */ NOT_BEGIN | BREAK | NOT_END, /* twh */ ILLEGAL_PAIR, /* tqu */ NOT_BEGIN | BREAK | NOT_END, /* tck */ ILLEGAL_PAIR }, { /* ua */ NOT_BEGIN | BREAK | NOT_END, /* ub */ ANY_COMBINATION, /* uc */ ANY_COMBINATION, /* ud */ ANY_COMBINATION, /* ue */ NOT_BEGIN, /* uf */ ANY_COMBINATION, /* ug */ ANY_COMBINATION, /* uh */ NOT_BEGIN | BREAK | NOT_END, /* ui */ NOT_BEGIN | BREAK | NOT_END, /* uj */ ANY_COMBINATION, /* uk */ ANY_COMBINATION, /* ul */ ANY_COMBINATION, /* um */ ANY_COMBINATION, /* un */ ANY_COMBINATION, /* uo */ NOT_BEGIN | BREAK, /* up */ ANY_COMBINATION, /* ur */ ANY_COMBINATION, /* us */ ANY_COMBINATION, /* ut */ ANY_COMBINATION, /* uu */ ILLEGAL_PAIR, /* uv */ ANY_COMBINATION, /* uw */ NOT_BEGIN | BREAK | NOT_END, /* ux */ ANY_COMBINATION, /* uy */ NOT_BEGIN | BREAK | NOT_END, /* uz */ ANY_COMBINATION, /* uch */ ANY_COMBINATION, /* ugh */ NOT_BEGIN | PREFIX, /* uph */ ANY_COMBINATION, /* urh */ ILLEGAL_PAIR, /* ush */ ANY_COMBINATION, /* uth */ ANY_COMBINATION, /* uwh */ ILLEGAL_PAIR, /* uqu */ BREAK | NOT_END, /* uck */ ANY_COMBINATION }, { /* va */ ANY_COMBINATION, /* vb */ NOT_BEGIN | BREAK | NOT_END, /* vc */ NOT_BEGIN | BREAK | NOT_END, /* vd */ NOT_BEGIN | BREAK | NOT_END, /* ve */ ANY_COMBINATION, /* vf */ NOT_BEGIN | BREAK | NOT_END, /* vg */ NOT_BEGIN | BREAK | NOT_END, /* vh */ NOT_BEGIN | BREAK | NOT_END, /* vi */ ANY_COMBINATION, /* vj */ NOT_BEGIN | BREAK | NOT_END, /* vk */ NOT_BEGIN | BREAK | NOT_END, /* vl */ NOT_BEGIN | BREAK | NOT_END, /* vm */ NOT_BEGIN | BREAK | NOT_END, /* vn */ NOT_BEGIN | BREAK | NOT_END, /* vo */ ANY_COMBINATION, /* vp */ NOT_BEGIN | BREAK | NOT_END, /* vr */ NOT_BEGIN | BREAK | NOT_END, /* vs */ NOT_BEGIN | BREAK | NOT_END, /* vt */ NOT_BEGIN | BREAK | NOT_END, /* vu */ ANY_COMBINATION, /* vv */ NOT_BEGIN | BREAK | NOT_END, /* vw */ NOT_BEGIN | BREAK | NOT_END, /* vx */ ILLEGAL_PAIR, /* vy */ NOT_BEGIN, /* vz */ NOT_BEGIN | BREAK | NOT_END, /* vch */ NOT_BEGIN | BREAK | NOT_END, /* vgh */ NOT_BEGIN | BREAK | NOT_END, /* vph */ NOT_BEGIN | BREAK | NOT_END, /* vrh */ ILLEGAL_PAIR, /* vsh */ NOT_BEGIN | BREAK | NOT_END, /* vth */ NOT_BEGIN | BREAK | NOT_END, /* vwh */ ILLEGAL_PAIR, /* vqu */ NOT_BEGIN | BREAK | NOT_END, /* vck */ ILLEGAL_PAIR }, { /* wa */ ANY_COMBINATION, /* wb */ NOT_BEGIN | PREFIX, /* wc */ NOT_BEGIN | BREAK | NOT_END, /* wd */ NOT_BEGIN | PREFIX | END, /* we */ ANY_COMBINATION, /* wf */ NOT_BEGIN | PREFIX, /* wg */ NOT_BEGIN | PREFIX | END, /* wh */ NOT_BEGIN | BREAK | NOT_END, /* wi */ ANY_COMBINATION, /* wj */ NOT_BEGIN | BREAK | NOT_END, /* wk */ NOT_BEGIN | PREFIX, /* wl */ NOT_BEGIN | PREFIX | SUFFIX, /* wm */ NOT_BEGIN | PREFIX, /* wn */ NOT_BEGIN | PREFIX, /* wo */ ANY_COMBINATION, /* wp */ NOT_BEGIN | PREFIX, /* wr */ BEGIN | SUFFIX | NOT_END, /* ws */ NOT_BEGIN | PREFIX, /* wt */ NOT_BEGIN | PREFIX, /* wu */ ANY_COMBINATION, /* wv */ NOT_BEGIN | PREFIX, /* ww */ NOT_BEGIN | BREAK | NOT_END, /* wx */ NOT_BEGIN | PREFIX, /* wy */ ANY_COMBINATION, /* wz */ NOT_BEGIN | PREFIX, /* wch */ NOT_BEGIN, /* wgh */ NOT_BEGIN | BREAK | NOT_END, /* wph */ NOT_BEGIN, /* wrh */ ILLEGAL_PAIR, /* wsh */ NOT_BEGIN, /* wth */ NOT_BEGIN, /* wwh */ ILLEGAL_PAIR, /* wqu */ NOT_BEGIN | BREAK | NOT_END, /* wck */ NOT_BEGIN }, { /* xa */ NOT_BEGIN, /* xb */ NOT_BEGIN | BREAK | NOT_END, /* xc */ NOT_BEGIN | BREAK | NOT_END, /* xd */ NOT_BEGIN | BREAK | NOT_END, /* xe */ NOT_BEGIN, /* xf */ NOT_BEGIN | BREAK | NOT_END, /* xg */ NOT_BEGIN | BREAK | NOT_END, /* xh */ NOT_BEGIN | BREAK | NOT_END, /* xi */ NOT_BEGIN, /* xj */ NOT_BEGIN | BREAK | NOT_END, /* xk */ NOT_BEGIN | BREAK | NOT_END, /* xl */ NOT_BEGIN | BREAK | NOT_END, /* xm */ NOT_BEGIN | BREAK | NOT_END, /* xn */ NOT_BEGIN | BREAK | NOT_END, /* xo */ NOT_BEGIN, /* xp */ NOT_BEGIN | BREAK | NOT_END, /* xr */ NOT_BEGIN | BREAK | NOT_END, /* xs */ NOT_BEGIN | BREAK | NOT_END, /* xt */ NOT_BEGIN | BREAK | NOT_END, /* xu */ NOT_BEGIN, /* xv */ NOT_BEGIN | BREAK | NOT_END, /* xw */ NOT_BEGIN | BREAK | NOT_END, /* xx */ ILLEGAL_PAIR, /* xy */ NOT_BEGIN, /* xz */ NOT_BEGIN | BREAK | NOT_END, /* xch */ NOT_BEGIN | BREAK | NOT_END, /* xgh */ NOT_BEGIN | BREAK | NOT_END, /* xph */ NOT_BEGIN | BREAK | NOT_END, /* xrh */ ILLEGAL_PAIR, /* xsh */ NOT_BEGIN | BREAK | NOT_END, /* xth */ NOT_BEGIN | BREAK | NOT_END, /* xwh */ ILLEGAL_PAIR, /* xqu */ NOT_BEGIN | BREAK | NOT_END, /* xck */ ILLEGAL_PAIR }, { /* ya */ ANY_COMBINATION, /* yb */ NOT_BEGIN, /* yc */ NOT_BEGIN | NOT_END, /* yd */ NOT_BEGIN, /* ye */ ANY_COMBINATION, /* yf */ NOT_BEGIN | NOT_END, /* yg */ NOT_BEGIN, /* yh */ NOT_BEGIN | BREAK | NOT_END, /* yi */ BEGIN | NOT_END, /* yj */ NOT_BEGIN | NOT_END, /* yk */ NOT_BEGIN, /* yl */ NOT_BEGIN | NOT_END, /* ym */ NOT_BEGIN, /* yn */ NOT_BEGIN, /* yo */ ANY_COMBINATION, /* yp */ NOT_BEGIN, /* yr */ NOT_BEGIN | BREAK | NOT_END, /* ys */ NOT_BEGIN, /* yt */ NOT_BEGIN, /* yu */ ANY_COMBINATION, /* yv */ NOT_BEGIN | NOT_END, /* yw */ NOT_BEGIN | BREAK | NOT_END, /* yx */ NOT_BEGIN, /* yy */ ILLEGAL_PAIR, /* yz */ NOT_BEGIN, /* ych */ NOT_BEGIN | BREAK | NOT_END, /* ygh */ NOT_BEGIN | BREAK | NOT_END, /* yph */ NOT_BEGIN | BREAK | NOT_END, /* yrh */ ILLEGAL_PAIR, /* ysh */ NOT_BEGIN | BREAK | NOT_END, /* yth */ NOT_BEGIN | BREAK | NOT_END, /* ywh */ ILLEGAL_PAIR, /* yqu */ NOT_BEGIN | BREAK | NOT_END, /* yck */ ILLEGAL_PAIR }, { /* za */ ANY_COMBINATION, /* zb */ NOT_BEGIN | BREAK | NOT_END, /* zc */ NOT_BEGIN | BREAK | NOT_END, /* zd */ NOT_BEGIN | BREAK | NOT_END, /* ze */ ANY_COMBINATION, /* zf */ NOT_BEGIN | BREAK | NOT_END, /* zg */ NOT_BEGIN | BREAK | NOT_END, /* zh */ NOT_BEGIN | BREAK | NOT_END, /* zi */ ANY_COMBINATION, /* zj */ NOT_BEGIN | BREAK | NOT_END, /* zk */ NOT_BEGIN | BREAK | NOT_END, /* zl */ NOT_BEGIN | BREAK | NOT_END, /* zm */ NOT_BEGIN | BREAK | NOT_END, /* zn */ NOT_BEGIN | BREAK | NOT_END, /* zo */ ANY_COMBINATION, /* zp */ NOT_BEGIN | BREAK | NOT_END, /* zr */ NOT_BEGIN | NOT_END, /* zs */ NOT_BEGIN | BREAK | NOT_END, /* zt */ NOT_BEGIN, /* zu */ ANY_COMBINATION, /* zv */ NOT_BEGIN | BREAK | NOT_END, /* zw */ SUFFIX | NOT_END, /* zx */ ILLEGAL_PAIR, /* zy */ ANY_COMBINATION, /* zz */ NOT_BEGIN, /* zch */ NOT_BEGIN | BREAK | NOT_END, /* zgh */ NOT_BEGIN | BREAK | NOT_END, /* zph */ NOT_BEGIN | BREAK | NOT_END, /* zrh */ ILLEGAL_PAIR, /* zsh */ NOT_BEGIN | BREAK | NOT_END, /* zth */ NOT_BEGIN | BREAK | NOT_END, /* zwh */ ILLEGAL_PAIR, /* zqu */ NOT_BEGIN | BREAK | NOT_END, /* zck */ ILLEGAL_PAIR }, { /* cha */ ANY_COMBINATION, /* chb */ NOT_BEGIN | BREAK | NOT_END, /* chc */ NOT_BEGIN | BREAK | NOT_END, /* chd */ NOT_BEGIN | BREAK | NOT_END, /* che */ ANY_COMBINATION, /* chf */ NOT_BEGIN | BREAK | NOT_END, /* chg */ NOT_BEGIN | BREAK | NOT_END, /* chh */ NOT_BEGIN | BREAK | NOT_END, /* chi */ ANY_COMBINATION, /* chj */ NOT_BEGIN | BREAK | NOT_END, /* chk */ NOT_BEGIN | BREAK | NOT_END, /* chl */ NOT_BEGIN | BREAK | NOT_END, /* chm */ NOT_BEGIN | BREAK | NOT_END, /* chn */ NOT_BEGIN | BREAK | NOT_END, /* cho */ ANY_COMBINATION, /* chp */ NOT_BEGIN | BREAK | NOT_END, /* chr */ NOT_END, /* chs */ NOT_BEGIN | BREAK | NOT_END, /* cht */ NOT_BEGIN | BREAK | NOT_END, /* chu */ ANY_COMBINATION, /* chv */ NOT_BEGIN | BREAK | NOT_END, /* chw */ NOT_BEGIN | NOT_END, /* chx */ ILLEGAL_PAIR, /* chy */ ANY_COMBINATION, /* chz */ NOT_BEGIN | BREAK | NOT_END, /* chch */ ILLEGAL_PAIR, /* chgh */ NOT_BEGIN | BREAK | NOT_END, /* chph */ NOT_BEGIN | BREAK | NOT_END, /* chrh */ ILLEGAL_PAIR, /* chsh */ NOT_BEGIN | BREAK | NOT_END, /* chth */ NOT_BEGIN | BREAK | NOT_END, /* chwh */ ILLEGAL_PAIR, /* chqu */ NOT_BEGIN | BREAK | NOT_END, /* chck */ ILLEGAL_PAIR }, { /* gha */ ANY_COMBINATION, /* ghb */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghc */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghd */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghe */ ANY_COMBINATION, /* ghf */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghg */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghh */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghi */ BEGIN | NOT_END, /* ghj */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghk */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghl */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghm */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghn */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* gho */ BEGIN | NOT_END, /* ghp */ NOT_BEGIN | BREAK | NOT_END, /* ghr */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghs */ NOT_BEGIN | PREFIX, /* ght */ NOT_BEGIN | PREFIX, /* ghu */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghv */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghw */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghx */ ILLEGAL_PAIR, /* ghy */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghz */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghch */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghgh */ ILLEGAL_PAIR, /* ghph */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghrh */ ILLEGAL_PAIR, /* ghsh */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghth */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghwh */ ILLEGAL_PAIR, /* ghqu */ NOT_BEGIN | BREAK | PREFIX | NOT_END, /* ghck */ ILLEGAL_PAIR }, { /* pha */ ANY_COMBINATION, /* phb */ NOT_BEGIN | BREAK | NOT_END, /* phc */ NOT_BEGIN | BREAK | NOT_END, /* phd */ NOT_BEGIN | BREAK | NOT_END, /* phe */ ANY_COMBINATION, /* phf */ NOT_BEGIN | BREAK | NOT_END, /* phg */ NOT_BEGIN | BREAK | NOT_END, /* phh */ NOT_BEGIN | BREAK | NOT_END, /* phi */ ANY_COMBINATION, /* phj */ NOT_BEGIN | BREAK | NOT_END, /* phk */ NOT_BEGIN | BREAK | NOT_END, /* phl */ BEGIN | SUFFIX | NOT_END, /* phm */ NOT_BEGIN | BREAK | NOT_END, /* phn */ NOT_BEGIN | BREAK | NOT_END, /* pho */ ANY_COMBINATION, /* php */ NOT_BEGIN | BREAK | NOT_END, /* phr */ NOT_END, /* phs */ NOT_BEGIN, /* pht */ NOT_BEGIN, /* phu */ ANY_COMBINATION, /* phv */ NOT_BEGIN | NOT_END, /* phw */ NOT_BEGIN | NOT_END, /* phx */ ILLEGAL_PAIR, /* phy */ NOT_BEGIN, /* phz */ NOT_BEGIN | BREAK | NOT_END, /* phch */ NOT_BEGIN | BREAK | NOT_END, /* phgh */ NOT_BEGIN | BREAK | NOT_END, /* phph */ ILLEGAL_PAIR, /* phrh */ ILLEGAL_PAIR, /* phsh */ NOT_BEGIN | BREAK | NOT_END, /* phth */ NOT_BEGIN | BREAK | NOT_END, /* phwh */ ILLEGAL_PAIR, /* phqu */ NOT_BEGIN | BREAK | NOT_END, /* phck */ ILLEGAL_PAIR }, { /* rha */ BEGIN | NOT_END, /* rhb */ ILLEGAL_PAIR, /* rhc */ ILLEGAL_PAIR, /* rhd */ ILLEGAL_PAIR, /* rhe */ BEGIN | NOT_END, /* rhf */ ILLEGAL_PAIR, /* rhg */ ILLEGAL_PAIR, /* rhh */ ILLEGAL_PAIR, /* rhi */ BEGIN | NOT_END, /* rhj */ ILLEGAL_PAIR, /* rhk */ ILLEGAL_PAIR, /* rhl */ ILLEGAL_PAIR, /* rhm */ ILLEGAL_PAIR, /* rhn */ ILLEGAL_PAIR, /* rho */ BEGIN | NOT_END, /* rhp */ ILLEGAL_PAIR, /* rhr */ ILLEGAL_PAIR, /* rhs */ ILLEGAL_PAIR, /* rht */ ILLEGAL_PAIR, /* rhu */ BEGIN | NOT_END, /* rhv */ ILLEGAL_PAIR, /* rhw */ ILLEGAL_PAIR, /* rhx */ ILLEGAL_PAIR, /* rhy */ BEGIN | NOT_END, /* rhz */ ILLEGAL_PAIR, /* rhch */ ILLEGAL_PAIR, /* rhgh */ ILLEGAL_PAIR, /* rhph */ ILLEGAL_PAIR, /* rhrh */ ILLEGAL_PAIR, /* rhsh */ ILLEGAL_PAIR, /* rhth */ ILLEGAL_PAIR, /* rhwh */ ILLEGAL_PAIR, /* rhqu */ ILLEGAL_PAIR, /* rhck */ ILLEGAL_PAIR }, { /* sha */ ANY_COMBINATION, /* shb */ NOT_BEGIN | BREAK | NOT_END, /* shc */ NOT_BEGIN | BREAK | NOT_END, /* shd */ NOT_BEGIN | BREAK | NOT_END, /* she */ ANY_COMBINATION, /* shf */ NOT_BEGIN | BREAK | NOT_END, /* shg */ NOT_BEGIN | BREAK | NOT_END, /* shh */ ILLEGAL_PAIR, /* shi */ ANY_COMBINATION, /* shj */ NOT_BEGIN | BREAK | NOT_END, /* shk */ NOT_BEGIN, /* shl */ BEGIN | SUFFIX | NOT_END, /* shm */ BEGIN | SUFFIX | NOT_END, /* shn */ BEGIN | SUFFIX | NOT_END, /* sho */ ANY_COMBINATION, /* shp */ NOT_BEGIN, /* shr */ BEGIN | SUFFIX | NOT_END, /* shs */ NOT_BEGIN | BREAK | NOT_END, /* sht */ SUFFIX, /* shu */ ANY_COMBINATION, /* shv */ NOT_BEGIN | BREAK | NOT_END, /* shw */ SUFFIX | NOT_END, /* shx */ ILLEGAL_PAIR, /* shy */ ANY_COMBINATION, /* shz */ NOT_BEGIN | BREAK | NOT_END, /* shch */ NOT_BEGIN | BREAK | NOT_END, /* shgh */ NOT_BEGIN | BREAK | NOT_END, /* shph */ NOT_BEGIN | BREAK | NOT_END, /* shrh */ ILLEGAL_PAIR, /* shsh */ ILLEGAL_PAIR, /* shth */ NOT_BEGIN | BREAK | NOT_END, /* shwh */ ILLEGAL_PAIR, /* shqu */ NOT_BEGIN | BREAK | NOT_END, /* shck */ ILLEGAL_PAIR }, { /* tha */ ANY_COMBINATION, /* thb */ NOT_BEGIN | BREAK | NOT_END, /* thc */ NOT_BEGIN | BREAK | NOT_END, /* thd */ NOT_BEGIN | BREAK | NOT_END, /* the */ ANY_COMBINATION, /* thf */ NOT_BEGIN | BREAK | NOT_END, /* thg */ NOT_BEGIN | BREAK | NOT_END, /* thh */ NOT_BEGIN | BREAK | NOT_END, /* thi */ ANY_COMBINATION, /* thj */ NOT_BEGIN | BREAK | NOT_END, /* thk */ NOT_BEGIN | BREAK | NOT_END, /* thl */ NOT_BEGIN | BREAK | NOT_END, /* thm */ NOT_BEGIN | BREAK | NOT_END, /* thn */ NOT_BEGIN | BREAK | NOT_END, /* tho */ ANY_COMBINATION, /* thp */ NOT_BEGIN | BREAK | NOT_END, /* thr */ NOT_END, /* ths */ NOT_BEGIN | END, /* tht */ NOT_BEGIN | BREAK | NOT_END, /* thu */ ANY_COMBINATION, /* thv */ NOT_BEGIN | BREAK | NOT_END, /* thw */ SUFFIX | NOT_END, /* thx */ ILLEGAL_PAIR, /* thy */ ANY_COMBINATION, /* thz */ NOT_BEGIN | BREAK | NOT_END, /* thch */ NOT_BEGIN | BREAK | NOT_END, /* thgh */ NOT_BEGIN | BREAK | NOT_END, /* thph */ NOT_BEGIN | BREAK | NOT_END, /* thrh */ ILLEGAL_PAIR, /* thsh */ NOT_BEGIN | BREAK | NOT_END, /* thth */ ILLEGAL_PAIR, /* thwh */ ILLEGAL_PAIR, /* thqu */ NOT_BEGIN | BREAK | NOT_END, /* thck */ ILLEGAL_PAIR }, { /* wha */ BEGIN | NOT_END, /* whb */ ILLEGAL_PAIR, /* whc */ ILLEGAL_PAIR, /* whd */ ILLEGAL_PAIR, /* whe */ BEGIN | NOT_END, /* whf */ ILLEGAL_PAIR, /* whg */ ILLEGAL_PAIR, /* whh */ ILLEGAL_PAIR, /* whi */ BEGIN | NOT_END, /* whj */ ILLEGAL_PAIR, /* whk */ ILLEGAL_PAIR, /* whl */ ILLEGAL_PAIR, /* whm */ ILLEGAL_PAIR, /* whn */ ILLEGAL_PAIR, /* who */ BEGIN | NOT_END, /* whp */ ILLEGAL_PAIR, /* whr */ ILLEGAL_PAIR, /* whs */ ILLEGAL_PAIR, /* wht */ ILLEGAL_PAIR, /* whu */ ILLEGAL_PAIR, /* whv */ ILLEGAL_PAIR, /* whw */ ILLEGAL_PAIR, /* whx */ ILLEGAL_PAIR, /* why */ BEGIN | NOT_END, /* whz */ ILLEGAL_PAIR, /* whch */ ILLEGAL_PAIR, /* whgh */ ILLEGAL_PAIR, /* whph */ ILLEGAL_PAIR, /* whrh */ ILLEGAL_PAIR, /* whsh */ ILLEGAL_PAIR, /* whth */ ILLEGAL_PAIR, /* whwh */ ILLEGAL_PAIR, /* whqu */ ILLEGAL_PAIR, /* whck */ ILLEGAL_PAIR }, { /* qua */ ANY_COMBINATION, /* qub */ ILLEGAL_PAIR, /* quc */ ILLEGAL_PAIR, /* qud */ ILLEGAL_PAIR, /* que */ ANY_COMBINATION, /* quf */ ILLEGAL_PAIR, /* qug */ ILLEGAL_PAIR, /* quh */ ILLEGAL_PAIR, /* qui */ ANY_COMBINATION, /* quj */ ILLEGAL_PAIR, /* quk */ ILLEGAL_PAIR, /* qul */ ILLEGAL_PAIR, /* qum */ ILLEGAL_PAIR, /* qun */ ILLEGAL_PAIR, /* quo */ ANY_COMBINATION, /* qup */ ILLEGAL_PAIR, /* qur */ ILLEGAL_PAIR, /* qus */ ILLEGAL_PAIR, /* qut */ ILLEGAL_PAIR, /* quu */ ILLEGAL_PAIR, /* quv */ ILLEGAL_PAIR, /* quw */ ILLEGAL_PAIR, /* qux */ ILLEGAL_PAIR, /* quy */ ILLEGAL_PAIR, /* quz */ ILLEGAL_PAIR, /* quch */ ILLEGAL_PAIR, /* qugh */ ILLEGAL_PAIR, /* quph */ ILLEGAL_PAIR, /* qurh */ ILLEGAL_PAIR, /* qush */ ILLEGAL_PAIR, /* quth */ ILLEGAL_PAIR, /* quwh */ ILLEGAL_PAIR, /* ququ */ ILLEGAL_PAIR, /* quck */ ILLEGAL_PAIR }, { /* cka */ NOT_BEGIN | BREAK | NOT_END, /* ckb */ NOT_BEGIN | BREAK | NOT_END, /* ckc */ NOT_BEGIN | BREAK | NOT_END, /* ckd */ NOT_BEGIN | BREAK | NOT_END, /* cke */ NOT_BEGIN | BREAK | NOT_END, /* ckf */ NOT_BEGIN | BREAK | NOT_END, /* ckg */ NOT_BEGIN | BREAK | NOT_END, /* ckh */ NOT_BEGIN | BREAK | NOT_END, /* cki */ NOT_BEGIN | BREAK | NOT_END, /* ckj */ NOT_BEGIN | BREAK | NOT_END, /* ckk */ NOT_BEGIN | BREAK | NOT_END, /* ckl */ NOT_BEGIN | BREAK | NOT_END, /* ckm */ NOT_BEGIN | BREAK | NOT_END, /* ckn */ NOT_BEGIN | BREAK | NOT_END, /* cko */ NOT_BEGIN | BREAK | NOT_END, /* ckp */ NOT_BEGIN | BREAK | NOT_END, /* ckr */ NOT_BEGIN | BREAK | NOT_END, /* cks */ NOT_BEGIN, /* ckt */ NOT_BEGIN | BREAK | NOT_END, /* cku */ NOT_BEGIN | BREAK | NOT_END, /* ckv */ NOT_BEGIN | BREAK | NOT_END, /* ckw */ NOT_BEGIN | BREAK | NOT_END, /* ckx */ ILLEGAL_PAIR, /* cky */ NOT_BEGIN, /* ckz */ NOT_BEGIN | BREAK | NOT_END, /* ckch */ NOT_BEGIN | BREAK | NOT_END, /* ckgh */ NOT_BEGIN | BREAK | NOT_END, /* ckph */ NOT_BEGIN | BREAK | NOT_END, /* ckrh */ ILLEGAL_PAIR, /* cksh */ NOT_BEGIN | BREAK | NOT_END, /* ckth */ NOT_BEGIN | BREAK | NOT_END, /* ckwh */ ILLEGAL_PAIR, /* ckqu */ NOT_BEGIN | BREAK | NOT_END, /* ckck */ ILLEGAL_PAIR } }; #ifdef PASSOGVA_DEBUG int main (int argc, char **argv) { int argno; long seed; unsigned short pwlen; unsigned short minimum; int number_of_words; boolean no_legal_words; char *unhyphenated_word; char *hyphenated_word; time_t ltime; pid_t lpid; #ifdef B1 int algorithm = 0; #endif number_of_words = 1; no_legal_words = FALSE; seed = 0L; pwlen = 8; minimum = 6; for (argno = 0; argno < argc; argno++) { if (argv[argno][0] == '-') { switch (argv[argno][1]) { #ifdef B1 case 'a': algorithm = atoi (&argv[argno][2]); break; #endif case 's': seed = atol (&argv[argno][2]); if (seed == 0L) seed = 1L; set_seed(seed); break; case 'l': pwlen = abs (atoi (&argv[argno][2])); if (pwlen < 1) pwlen = 8; break; case 'm': minimum = abs (atoi (&argv[argno][2])); if (minimum < 1) minimum = 1; break; case 'n': no_legal_words = TRUE; break; } } else { number_of_words = atoi (argv[argno]); } if (number_of_words < 1) { number_of_words = 1; } } /* * During debugging (PASSOGVA_DEBUG is set), we generate the seed from * here rather than the first entry to randomword() . */ if (seed == 0L) { time(<ime); lpid = getpid(); set_seed((long) ltime ^ (lpid + (lpid << 15))); } if (minimum > pwlen) { fflush(stdout); fprintf (stderr, "minimum (%u) new password length cannot exceed maximum (%u)\n", (uint) minimum, (uint) pwlen); fflush(stderr); exit (1); } for (argno = 1; argno <= number_of_words; argno++) { unhyphenated_word = (char *)calloc (sizeof (char), pwlen + 1); hyphenated_word = (char *)calloc (sizeof (char), 2 * pwlen); #ifdef B1 switch (algorithm) { default: case 0: randomword(unhyphenated_word, hyphenated_word, minimum, pwlen, no_legal_words, 0L); fflush(stderr); fprintf(stdout, "%s (%s)\n", unhyphenated_word, hyphenated_word); break; case 1: randomchars(unhyphenated_word, minimum, pwlen, no_legal_words, 0L); fflush(stderr); fprintf(stdout, "%s\n", unhyphenated_word); break; case 2: randomletters(unhyphenated_word, minimum, pwlen, no_legal_words, 0L); fflush(stderr); fprintf(stdout, "%s\n", unhyphenated_word); break; } #else randomword(unhyphenated_word, hyphenated_word, minimum, pwlen, no_legal_words, 0L); fflush(stderr); fprintf(stdout, "%s (%s)\n", unhyphenated_word, hyphenated_word); #endif fflush(stdout); free(unhyphenated_word); free(hyphenated_word); } return 0; } #endif #ifdef B1 /* * Randomchars will generate a random string and place it in the * buffer word. The word must be pre-allocated. The words generated * will have sizes between minlen and maxlen. If restrict is TRUE, * words will not be generated that appear as login names or as * entries in the on-line dictionary. The seed is used on first use * of the routine. The length of the word is returned, or -1 if there * were an error (length settings are wrong or dictionary checking * could not be done). The seed is used on first use of the routine. */ int randomchars (char *string, unsigned short minlen, unsigned short maxlen, boolean restrict, long seed) { int loop_count; unsigned short string_size; unsigned short build; static int been_here_before = FALSE; /* * Execute this upon startup. This initializes the environment, * including seed'ing the random number generator and loading the * on-line dictionary. */ if (!been_here_before) { been_here_before = TRUE; #ifndef PASSOGVA_DEBUG set_seed(seed); #endif } /* * Check for minlen > maxlen. This is an error. */ if (minlen > maxlen) { return (-1); } loop_count = 0; string_size = get_random(minlen, maxlen); do { for (build = 0; build < string_size; build++) { string[build] = (char) get_random((unsigned short) '!', (unsigned short) '~'); } restrict = 0; loop_count++; } while (restrict && (loop_count <= MAX_UNACCEPTABLE)); string[string_size] = '\0'; return string_size; } /* * Randomletters will generate a random string of letters and place it * in the buffer word. The word must be pre-allocated. The words * generated will have sizes between minlen and maxlen. If restrict * is TRUE, words will not be generated that appear as login names or * as entries in the on-line dictionary. The seed is used on first * use of the routine. The length of the word is returned, or -1 if * there were an error (length settings are wrong or dictionary * checking could not be done). The seed is used on first use of the * routine. */ int randomletters (char *string, unsigned short minlen, unsigned short maxlen, boolean restrict, long seed) { int loop_count; unsigned short string_size; unsigned short build; static int been_here_before = FALSE; /* * Execute this upon startup. This initializes the environment, * including seed'ing the random number generator and loading the * on-line dictionary. */ if (!been_here_before) { been_here_before = TRUE; #ifndef PASSOGVA_DEBUG set_seed(seed); #endif } /* * Check for minlen > maxlen. This is an error. */ if (minlen > maxlen) { return (-1); } loop_count = 0; string_size = get_random(minlen, maxlen); do { for (build = 0; build < string_size; build++) { string[build] = (char) get_random((unsigned short) 'a', (unsigned short) 'z'); } restrict = 0; loop_count++; } while (restrict && (loop_count <= MAX_UNACCEPTABLE)); string[string_size] = '\0'; return string_size; } #endif /* * Randomword will generate a random word and place it in the buffer * word. Also, the hyphenated word will be placed into the buffer * hyphenated_word. Both word and hyphenated_word must be * pre-allocated. The words generated will have sizes between minlen * and maxlen. If restrict is TRUE, words will not be generated that * appear as login names or as entries in the on-line dictionary. * This algorithm was initially worded out by Morrie Gasser in 1975. * Any changes here are minimal so that as many word combinations can * be produced as possible (and thus keep the words random). The seed * is used on first use of the routine. The length of the * unhyphenated word is returned, or -1 if there were an error (length * settings are wrong or dictionary checking could not be done. */ int randomword (char *word, char *hyphenated_word, unsigned short minlen, unsigned short maxlen, boolean restrict, long seed) { int pwlen; int loop_count; static int been_here_before = FALSE; /* * Execute this upon startup. This initializes the environment, * including seed'ing the random number generator and loading the * on-line dictionary. */ if (!been_here_before) { been_here_before = TRUE; #ifndef PASSOGVA_DEBUG set_seed(seed); #endif } /* * Check for minlen>maxlen. This is an error. */ if (minlen > maxlen) { return (-1); } /* * Check for zero length words. This is technically not an error, * so we take the short cut and return a null word and a length of * 0. */ if (maxlen == 0) { word[0] = '\0'; hyphenated_word[0] = '\0'; return (0); } /* * Continue finding words until the criteria are satisfied. The * criteria are, if restrict is set, that if the word appears as * either a login name or as part of the on-line dictionary, throw * out the word and look for another. */ loop_count = 0; do { /* * Get a random word. Its length is a random quantity from with * the limits specified in the call to randomword(). */ pwlen = get_word(word, hyphenated_word, get_random (minlen, maxlen)); restrict = 0; loop_count++; } while (restrict && (loop_count <= MAX_UNACCEPTABLE)); if (restrict) { fflush(stdout); fprintf(stderr, "could not find acceptable random password\n"); fflush(stderr); exit(1); } return (pwlen); } /* * This is the routine that returns a random word -- as yet unchecked * against the passwd file or the dictionary. It collects random * syllables until a predetermined word length is found. If a retry * threshold is reached, another word is tried. Given that the random * number generator is uniformly distributed, eventually a word will * be found if the retry limit is adequately large enough. */ static int get_word (char *word, char *hyphenated_word, unsigned short pwlen) { unsigned short word_length; unsigned short syllable_length; char *new_syllable; unsigned short *syllable_units; unsigned short word_size; unsigned short word_place; unsigned short *word_units; unsigned short syllable_size; unsigned int tries; /* * Keep count of retries. */ tries = 0; /* * The length of the word in characters. */ word_length = 0; /* * The length of the word in character units (each of which is one * or two characters long). */ word_size = 0; /* * Initialize the array storing the word units. Since we know the * length of the word, we only need one of that length. This method * is preferable to a static array, since it allows us flexibility * in choosing arbitrarily long word lengths. Since a word can * contain one syllable, we should make syllable_units, the array * holding the analogous units for an individual syllable, the same * length. No explicit rule limits the length of syllables, but * digram rules and heuristics do so indirectly. */ word_units = (unsigned short *) calloc (pwlen, sizeof (unsigned short)); syllable_units = (unsigned short *) calloc (pwlen, sizeof (unsigned short)); new_syllable = (char *) calloc (pwlen, sizeof (unsigned short)); /* * Find syllables until the entire word is constructed. */ while (word_length < pwlen) { /* * Get the syllable and find its length. */ get_syllable(new_syllable, pwlen - word_length, syllable_units, &syllable_size); syllable_length = strlen(new_syllable); /* * Append the syllable units to the word units. */ for (word_place = 0; word_place <= syllable_size; word_place++) { word_units[word_size + word_place] = syllable_units[word_place]; } word_size += syllable_size + 1; /* * If the word has been improperly formed, throw out the syllable. * The checks performed here are those that must be formed on a * word basis. The other tests are performed entirely within the * syllable. Otherwise, append the syllable to the word and * append the syllable to the hyphenated version of the word. */ if (improper_word(word_units, word_size) || ((word_length == 0) && have_initial_y(syllable_units, syllable_size)) || ((word_length + syllable_length == pwlen) && have_final_split(syllable_units, syllable_size))) { word_size -= syllable_size + 1; } else { if (word_length == 0) { strcpy(word, new_syllable); strcpy(hyphenated_word, new_syllable); } else { strcat(word, new_syllable); strcat(hyphenated_word, "-"); strcat(hyphenated_word, new_syllable); } word_length += syllable_length; } /* * Keep track of the times we have tried to get syllables. If we * have exceeded the threshold, reinitialize the pwlen and * word_size variables, clear out the word arrays, and start from * scratch. */ tries++; if (tries > MAX_RETRIES) { word_length = 0; word_size = 0; tries = 0; strcpy (word, ""); strcpy (hyphenated_word, ""); } } /* * The units arrays and syllable storage are internal to this * routine. Since the caller has no need for them, we release the * space. */ free((char *)new_syllable); free((char *)syllable_units); free((char *)word_units); return ((int)word_length); } /* * Check that the word does not contain illegal combinations that may * span syllables. Specifically, these are: * 1. An illegal pair of units between syllables. * 2. Three consecutive vowel units. * 3. Three consecutive consonant units. * The checks are made against units (1 or 2 letters), not against the * individual letters, so three consecutive units can have the length * of 6 at most. */ static boolean improper_word (unsigned short *units, unsigned short word_size) { unsigned short unit_count; boolean failure; failure = FALSE; for (unit_count = 0; !failure && (unit_count < word_size); unit_count++) { /* * Check for ILLEGAL_PAIR. This should have been caught for units * within a syllable, but in some cases it would have gone * unnoticed for units between syllables (e.g., when saved_unit's * in get_syllable() were not used). */ if ((unit_count != 0) && (digram[units[unit_count - 1]][units[unit_count]] & ILLEGAL_PAIR)) { failure = TRUE; } /* * Check for consecutive vowels or consonants. Because the * initial y of a syllable is treated as a consonant rather than * as a vowel, we exclude y from the first vowel in the vowel * test. The only problem comes when y ends a syllable and two * other vowels start the next, like fly-oint. Since such words * are still pronounceable, we accept this. */ if (!failure && (unit_count >= 2)) { /* * Vowel check. */ if ((((rules[units[unit_count - 2]].flags & VOWEL) && !(rules[units[unit_count - 2]].flags & ALTERNATE_VOWEL)) && (rules[units[unit_count - 1]].flags & VOWEL) && (rules[units[unit_count]].flags & VOWEL)) || /* * Consonant check. */ (!(rules[units[unit_count - 2]].flags & VOWEL) && !(rules[units[unit_count - 1]].flags & VOWEL) && !(rules[units[unit_count]].flags & VOWEL))) { failure = TRUE; } } } return (failure); } /* * Treating y as a vowel is sometimes a problem. Some words get * formed that look irregular. One special group is when y starts a * word and is the only vowel in the first syllable. The word ycl is * one example. We discard words like these. */ static boolean have_initial_y (unsigned short *units, unsigned short unit_size) { unsigned short unit_count; unsigned short vowel_count; unsigned short normal_vowel_count; vowel_count = 0; normal_vowel_count = 0; for (unit_count = 0; unit_count <= unit_size; unit_count++) { /* * Count vowels. */ if (rules[units[unit_count]].flags & VOWEL) { vowel_count++; /* * Count the vowels that are not: 1. y, 2. at the start of the * word. */ if (!(rules[units[unit_count]].flags & ALTERNATE_VOWEL) || (unit_count != 0)) { normal_vowel_count++; } } } return ((vowel_count <= 1) && (normal_vowel_count == 0)); } /* * Besides the problem with the letter y, there is one with a silent e * at the end of words, like face or nice. We allow this silent e, * but we do not allow it as the only vowel at the end of the word or * syllables like ble will be generated. */ static boolean have_final_split (unsigned short *units, unsigned short unit_size) { unsigned short unit_count; unsigned short vowel_count; vowel_count = 0; /* * Count all the vowels in the word. */ for (unit_count = 0; unit_count <= unit_size; unit_count++) { if (rules[units[unit_count]].flags & VOWEL) { vowel_count++; } } /* * Return TRUE iff the only vowel was e, found at the end if the * word. */ return ((vowel_count == 1) && (rules[units[unit_size]].flags & NO_FINAL_SPLIT)); } /* * Generate next unit to password, making sure that it follows * these rules: * 1. Each syllable must contain exactly 1 or 2 consecutive * vowels, where y is considered a vowel. * 2. Syllable end is determined as follows: * a. Vowel is generated and previous unit is a * consonant and syllable already has a vowel. In * this case, new syllable is started and already * contains a vowel. * b. A pair determined to be a "break" pair is encountered. * In this case new syllable is started with second unit * of this pair. * c. End of password is encountered. * d. "begin" pair is encountered legally. New syllable is * started with this pair. * e. "end" pair is legally encountered. New syllable has * nothing yet. * 3. Try generating another unit if: * a. third consecutive vowel and not y. * b. "break" pair generated but no vowel yet in current * or previous 2 units are "not_end". * c. "begin" pair generated but no vowel in syllable * preceding begin pair, or both previous 2 pairs are * designated "not_end". * d. "end" pair generated but no vowel in current syllable * or in "end" pair. * e. "not_begin" pair generated but new syllable must * begin (because previous syllable ended as defined in * 2 above). * f. vowel is generated and 2a is satisfied, but no syllable * break is possible in previous 3 pairs. * g. Second and third units of syllable must begin, and * first unit is "alternate_vowel". */ static char *get_syllable (char *syllable, unsigned short pwlen, unsigned short *units_in_syllable, unsigned short *syllable_size) { unsigned short unit; short current_unit; unsigned short vowel_count; boolean rule_broken; boolean want_vowel; boolean want_another_unit; unsigned int tries; unsigned short last_unit; short length_left; unsigned short hold_saved_unit; static unsigned short saved_unit; static unsigned short saved_pair[2]; /* * This is needed if the saved_unit is tries and the syllable then * discarded because of the retry limit. Since the saved_unit is OK * and fits in nicely with the preceding syllable, we will always * use it. */ hold_saved_unit = saved_unit; /* * Loop until valid syllable is found. */ do { /* * Try for a new syllable. Initialize all pertinent syllable * variables. */ tries = 0; saved_unit = hold_saved_unit; strcpy(syllable, ""); *syllable_size = 0; vowel_count = 0; current_unit = 0; length_left = (short) pwlen; want_another_unit = TRUE; /* * This loop finds all the units for the syllable. */ do { want_vowel = FALSE; /* * This loop continues until a valid unit is found for the * current position within the syllable. */ do { /* * If there are saved_unit's from the previous syllable, use * them up first. */ if (saved_unit != 0) { /* * If there were two saved units, the first is guaranteed * (by checks performed in the previous syllable) to be * valid. We ignore the checks and place it in this * syllable manually. */ if (saved_unit == 2) { units_in_syllable[0] = saved_pair[1]; if (rules[saved_pair[1]].flags & VOWEL) { vowel_count++; } current_unit++; strcpy(syllable, rules[saved_pair[1]].unit_code); length_left -= strlen(syllable); } /* * The unit becomes the last unit checked in the previous * syllable. */ unit = saved_pair[0]; /* * The saved units have been used. Do not try to reuse them * in this syllable (unless this particular syllable is * rejected at which point we start to rebuild it with these * same saved units. */ saved_unit = 0; } else { /* * If we don't have to scoff the saved units, we generate a * random one. If we know it has to be a vowel, we get one * rather than looping through until one shows up. */ if (want_vowel) { unit = random_unit(VOWEL); } else { unit = random_unit(NO_SPECIAL_RULE); } } length_left -= (short) strlen(rules[unit].unit_code); /* * Prevent having a word longer than expected. */ if (length_left < 0) { rule_broken = TRUE; } else { rule_broken = FALSE; } /* * First unit of syllable. This is special because the digram * tests require 2 units and we don't have that yet. * Nevertheless, we can perform some checks. */ if (current_unit == 0) { /* * If the shouldn't begin a syllable, don't use it. */ if (rules[unit].flags & NOT_BEGIN_SYLLABLE) { rule_broken = TRUE; } else if (length_left == 0) { /* * If this is the last unit of a word, we have a one unit * syllable. Since each syllable must have a vowel, we * make sure the unit is a vowel. Otherwise, we discard * it. */ if (rules[unit].flags & VOWEL) { want_another_unit = FALSE; } else { rule_broken = TRUE; } } } else { /* * We are not at the start of a syllable. Save the previous * unit for later tests. */ last_unit = units_in_syllable[current_unit - 1]; /* * There are some digram tests that are universally true. * We test them out. */ /* * Reject ILLEGAL_PAIRS of units. */ if ((ALLOWED (ILLEGAL_PAIR)) || /* * Reject units that will be split between syllables * when the syllable has no vowels in it. */ (ALLOWED (BREAK) && (vowel_count == 0)) || /* * Reject a unit that will end a syllable when no * previous unit was a vowel and neither is this one. */ (ALLOWED (END) && (vowel_count == 0) && !(rules[unit].flags & VOWEL))) { rule_broken = TRUE; } if (current_unit == 1) { /* Set last_unit to be 0, which is "a", which is a vowel, which is a hack. This is what was happening anyway when it was never set in this case. --sah */ last_unit = 0; /* * Reject the unit if we are at te starting digram of a * syllable and it does not fit. */ if (ALLOWED (NOT_BEGIN)) { rule_broken = TRUE; } } else { /* * Do not allow syllables where the first letter is y and * the next pair can begin a syllable. This may lead to * splits where y is left alone in a syllable. Also, the * combination does not sound to good even if not split. */ if (((current_unit == 2) && (ALLOWED (BEGIN)) && (rules[units_in_syllable[0]].flags & ALTERNATE_VOWEL)) || /* * If this is the last unit of a word, we should * reject any digram that cannot end a syllable. */ (ALLOWED (NOT_END) && (length_left == 0)) || /* * Reject the unit if the digram it forms wants to * break the syllable, but the resulting digram that * would end the syllable is not allowed to end a * syllable. */ (ALLOWED (BREAK) && (digram[units_in_syllable [current_unit - 2]] [last_unit] & NOT_END)) || /* * Reject the unit if the digram it forms expects a * vowel preceding it and there is none. */ (ALLOWED (PREFIX) && !(rules[units_in_syllable [current_unit - 2]].flags & VOWEL))) { rule_broken = TRUE; } /* * The following checks occur when the current unit is a * vowel and we are not looking at a word ending with an * e. */ if (!rule_broken && (rules[unit].flags & VOWEL) && ((length_left > 0) || !(rules[last_unit].flags & NO_FINAL_SPLIT))) { /* * Don't allow 3 consecutive vowels in a syllable. * Although some words formed like this are OK, like * beau, most are not. */ if ((vowel_count > 1) && (rules[last_unit].flags & VOWEL)) { rule_broken = TRUE; } else if ((vowel_count != 0) && !(rules[last_unit].flags & VOWEL)) { /* * Check for the case of vowels-consonants-vowel, * which is only legal if the last vowel is an e and * we are the end of the word (wich is not happening * here due to a previous check. */ /* * Try to save the vowel for the next syllable, but if * the syllable left here is not proper (i.e., the * resulting last digram cannot legally end it), just * discard it and try for another. */ if (digram[units_in_syllable [current_unit - 2]] [last_unit] & NOT_END) { rule_broken = TRUE; } else { saved_unit = 1; saved_pair[0] = unit; want_another_unit = FALSE; } } } } /* * The unit picked and the digram formed are legal. We now * determine if we can end the syllable. It may, in some * cases, mean the last unit(s) may be deferred to the next * syllable. We also check here to see if the digram formed * expects a vowel to follow. */ if (!rule_broken && want_another_unit) { /* * This word ends in a silent e. */ if (((vowel_count != 0) && (rules[unit].flags & NO_FINAL_SPLIT) && (length_left == 0) && !(rules[last_unit].flags & VOWEL)) || /* * This syllable ends either because the digram is an * END pair or we would otherwise exceed the length of * the word. */ (ALLOWED (END) || (length_left == 0))) { want_another_unit = FALSE; } else if ((vowel_count != 0) && (length_left > 0)) { /* * Since we have a vowel in the syllable already, if the * digram calls for the end of the syllable, we can * legally split it off. We also make sure that we are * not at the end of the dangerous because that syllable * may not have vowels, or it may not be a legal * syllable end, and the retrying mechanism will loop * infinitely with the same digram. */ /* * If we must begin a syllable, we do so if the only * vowel in THIS syllable is not part of the digram we * are pushing to the next syllable. */ if (ALLOWED (BEGIN) && (current_unit > 1) && !((vowel_count == 1) && (rules[last_unit].flags & VOWEL))) { saved_unit = 2; saved_pair[0] = unit; saved_pair[1] = last_unit; want_another_unit = FALSE; } else if (ALLOWED (BREAK)) { saved_unit = 1; saved_pair[0] = unit; want_another_unit = FALSE; } } else if (ALLOWED (SUFFIX)) { want_vowel = TRUE; } } } tries++; /* * If this unit was illegal, redetermine the amount of letters * left to go in the word. */ if (rule_broken) { length_left += (short) strlen (rules[unit].unit_code); } } while (rule_broken && (tries <= MAX_RETRIES)); /* * The unit fit OK. */ if (tries <= MAX_RETRIES) { /* * If the unit were a vowel, count it in. However, if the * unit were a y and appear at the start of the syllable, * treat it like a constant (so that words like year can * appear and not conflict with the 3 consecutive vowel rule. */ if ((rules[unit].flags & VOWEL) && ((current_unit > 0) || !(rules[unit].flags & ALTERNATE_VOWEL))) { vowel_count++; } /* * If a unit or units were to be saved, we must adjust the * syllable formed. Otherwise, we append the current unit to * the syllable. */ switch (saved_unit) { case 0: units_in_syllable[current_unit] = unit; strcat(syllable, rules[unit].unit_code); break; case 1: current_unit--; break; case 2: strcpy(&syllable[strlen (syllable) - strlen (rules[last_unit]. unit_code)], ""); length_left += (short) strlen(rules[last_unit].unit_code); current_unit -= 2; break; } } else { /* * Whoops! Too many tries. We set rule_broken so we can loop * in the outer loop and try another syllable. */ rule_broken = TRUE; /* * ...and the syllable length grows. */ *syllable_size = current_unit; } current_unit++; } while ((tries <= MAX_RETRIES) && want_another_unit); } while (rule_broken || illegal_placement (units_in_syllable, *syllable_size)); return (syllable); } /* * This routine goes through an individual syllable and checks for * illegal combinations of letters that go beyond looking at digrams. * We look at things like 3 consecutive vowels or consonants, or * syllables with consonants between vowels (unless one of them is the * final silent e). */ static boolean illegal_placement (unsigned short *units, unsigned short pwlen) { unsigned short vowel_count; unsigned short unit_count; boolean failure; vowel_count = 0; failure = FALSE; for (unit_count = 0; !failure && (unit_count <= pwlen); unit_count++) { if (unit_count >= 1) { /* * Don't allow vowels to be split with consonants in a single * syllable. If we find such a combination (except for the * silent e) we have to discard the syllable). */ if ((!(rules[units[unit_count - 1]].flags & VOWEL) && (rules[units[unit_count]].flags & VOWEL) && !((rules[units[unit_count]].flags & NO_FINAL_SPLIT) && (unit_count == pwlen)) && (vowel_count != 0)) || /* * Perform these checks when we have at least 3 units. */ ((unit_count >= 2) && /* * Disallow 3 consecutive consonants. */ ((!(rules[units[unit_count - 2]].flags & VOWEL) && !(rules[units[unit_count - 1]].flags & VOWEL) && !(rules[units[unit_count]].flags & VOWEL)) || /* * Disallow 3 consecutive vowels, where the first is not a * y. */ (((rules[units[unit_count - 2]].flags & VOWEL) && !((rules[units[0]].flags & ALTERNATE_VOWEL) && (unit_count == 2))) && (rules[units[unit_count - 1]].flags & VOWEL) && (rules[units[unit_count]].flags & VOWEL))))) failure = TRUE; } /* * Count the vowels in the syllable. As mentioned somewhere * above, exclude the initial y of a syllable. Instead, treat it * as a consonant. */ if ((rules[units[unit_count]].flags & VOWEL) && !((rules[units[0]].flags & ALTERNATE_VOWEL) && (unit_count == 0) && (pwlen != 0))) vowel_count++; } return (failure); } /* * This is the standard random unit generating routine for * get_syllable(). It does not reference the digrams, but assumes * that it contains 34 units in a particular order. This routine * attempts to return unit indexes with a distribution approaching * that of the distribution of the 34 units in English. In order to * do this, a random number (supposedly uniformly distributed) is used * to do a table lookup into an array containing unit indices. There * are 211 entries in the array for the random_unit entry point. The * probability of a particular unit being generated is equal to the * fraction of those 211 entries that contain that unit index. For * example, the letter `a' is unit number 1. Since unit index 1 * appears 10 times in the array, the probability of selecting an `a' * is 10/211. * * Changes may be made to the digram table without affect to this * procedure providing the letter-to-number correspondence of the * units does not change. Likewise, the distribution of the 34 units * may be altered (and the array size may be changed) in this * procedure without affecting the digram table or any other programs * using the random_word subroutine. */ static unsigned short numbers[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 25, 26, 27, 28, 29, 29, 30, 31, 32, 33 }; /* * This structure has a typical English frequency of vowels. The * value of an entry is the vowel position (a=0, e=4, i=8, o=14, u=19, * y=23) in the rules array. The number of times the value appears is * the frequency. Thus, the letter "a" is assumed to appear 2/12 = * 1/6 of the time. This array may be altered if better data is * obtained. The routines that use vowel_numbers will adjust to the * size difference automatically. */ static unsigned short vowel_numbers[] = { 0, 0, 4, 4, 4, 8, 8, 14, 14, 19, 19, 23 }; /* * Select a unit (a letter or a consonant group). If a vowel is * expected, use the vowel_numbers array rather than looping through * the numbers array until a vowel is found. */ static unsigned short random_unit (unsigned short type) { unsigned short number; /* * Sometimes, we are asked to explicitly get a vowel (i.e., if a * digram pair expects one following it). This is a shortcut to do * that and avoid looping with rejected consonants. */ if (type & VOWEL) { number = vowel_numbers[get_random(0, (sizeof (vowel_numbers) / sizeof (unsigned short)))]; } else { /* * Get any letter according to the English distribution. */ number = numbers[get_random(0, (sizeof (numbers) / sizeof (unsigned short)))]; } return (number); } /* * Return a random number between minlen and maxlen inclusive. */ static unsigned short get_random (unsigned short minlen, unsigned short maxlen) { return minlen + (unsigned short) randint((int) (maxlen - minlen + 1)); } /* * Produces a random number from 0 to n-1 . */ static unsigned int randint(int n) { return (rand() % n); } /* * Set the seed. This routine will only set the seed once, even if * called from multiple sources. */ static void set_seed(long seed) { int been_here_before = 0; if (!been_here_before) { been_here_before = 1; srand(seed); } } /* * answer takes the array out and creates variable sum by adding * certain values within the array together. To get a number from 0 * to n-1, it returns sum mod n (sum%n) */ int answer (unsigned char *out, int n) { unsigned int sum; /* * every time this function is called, it adds the first three * positions of out to get sum. */ sum = out[0] + out[1] +out[2]; return (sum % n); }