3745 lines
124 KiB
Plaintext
3745 lines
124 KiB
Plaintext
Federal Information
|
|
Processing Standards Publication 181
|
|
|
|
1993 October 5
|
|
|
|
Announcing the Standard for
|
|
|
|
Automated Password Generator
|
|
|
|
|
|
|
|
Federal Information Processing Standards Publications (FIPS PUBS)
|
|
are issued by the National Institute of Standards and Technology
|
|
(NIST) after approval by the Secretary of Commerce pursuant to
|
|
Section 111(d) of the Federal Property and Administrative Services
|
|
Act of 1949 as amended by the Computer Security Act of 1987, Public
|
|
Law 100-235.
|
|
|
|
|
|
1. Name of Standard. Automated Password Generator.
|
|
|
|
2. Category of Standard. Computer Security.
|
|
|
|
3. Explanation. A password is a protected character string used
|
|
to authenticate the identity of a computer system user or to
|
|
authorize access to system resources. When users are allowed to
|
|
select their own passwords they often select passwords that are
|
|
easily compromised. An automated password generator creates random
|
|
passwords that have no association with a particular user.
|
|
|
|
This Automated Password Generator Standard specifies an algorithm
|
|
to generate passwords for the protection of computer resources.
|
|
This standard is for use in conjunction with FIPS PUB 112, Password
|
|
Usage Standard, which provides basic security criteria for the
|
|
design, implementation, and use of passwords. The algorithm uses
|
|
random numbers to select the characters that form the random
|
|
pronounceable passwords. The random numbers are generated by a
|
|
random number subroutine based on the Electronic Codebook mode of
|
|
the Data Encryption Standard (DES) (FIPS PUB 46-1). The random
|
|
number subroutine uses a pseudorandom DES key generated in
|
|
accordance with the procedure described in Appendix C of ANSI
|
|
X9.17.
|
|
|
|
Similar to DES, the FIPS for Automated Password Generator is an
|
|
interoperability standard. Interoperability standards specify
|
|
functions and formats so that data transmitted can be properly
|
|
acted upon when received by another computer. This type of
|
|
standard is independent of physical implementation. Implementors
|
|
are required to use the algorithm defined in the FIPS, however,
|
|
they are not constrained in how they package it. For discussion
|
|
purposes a NIST implementation of the Automated Password Generator
|
|
is provided. It is expected that commercial implementations will
|
|
be based on the latest technologies and differ from NIST's, however
|
|
the results should be logically equivalent to that of this FIPS.
|
|
|
|
4. Approving Authority. Secretary of Commerce.5. Maintenance Agency. U.S. Department of Commerce, National
|
|
Institute of Standards and Technology (NIST), Computer Systems
|
|
Laboratory (CSL).
|
|
|
|
6. Cross Index.
|
|
|
|
a. American National Standards Institute (ANSI) X9.28, Financial
|
|
Institution Multiple Center Key Management (Wholesale) Draft.
|
|
b. Department of Defense CSC-STD-002-85, Password Management
|
|
Guideline.
|
|
c. Federal Information Processing Standards Publication (FIPS PUB)
|
|
48, Guidelines on Evaluation of Techniques for Automated Personal
|
|
Identification.
|
|
d. Federal Information Processing Standards Publication (FIPS PUB)
|
|
46-1, Data Encryption Standard.
|
|
e. Federal Information Processing Standards Publication (FIPS PUB)
|
|
81, DES Modes of Operation.
|
|
f. Federal Information Processing Standards Publication (FIPS PUB)
|
|
83, Guideline on User Authentication Techniques for Computer
|
|
Network Access Control.
|
|
g. Federal Information Processing Standards Publication (FIPS PUB)
|
|
112, Password Usage.
|
|
h. Federal Information Processing Standards Publication (FIPS PUB)
|
|
171, Key Management Using ANSI X9.17.
|
|
i. National Technical Information Service (NTIS) AD A 017676, A
|
|
Random Word Generator for Pronounceable Passwords.
|
|
|
|
7. Objectives. The objectives of this standard are to:
|
|
|
|
a. improve the administration of password systems that are used
|
|
for authenticating the identity of individuals accessing
|
|
computer resources or files;
|
|
|
|
b. provide a standard automated method for producing
|
|
pronounceable passwords that have no association with a
|
|
particular user;
|
|
|
|
c. produce passwords that are easily remembered, stored, and
|
|
entered into computer systems, yet not readily susceptible to
|
|
automated techniques that have been developed to search for
|
|
and disclose passwords.
|
|
|
|
8. Applicability. This standard is applicable to the development
|
|
of procurement or design specifications for implementing an
|
|
automatic password generation algorithm within a computer system.
|
|
It shall be used by all Federal departments and agencies when there
|
|
is a requirement for computer generated pronounceable passwords for
|
|
authenticating users of computer systems, or for authorizing access
|
|
to resources in those systems.
|
|
|
|
This standard does not require the use of passwords in a computer
|
|
system, but establishes an automatic password generation algorithm
|
|
for use in systems where an agency's computer security policy
|
|
requires computer generated pronounceable passwords. It should be
|
|
used in conjunction with FIPS PUB 112, Password Usage Standard,
|
|
which specifies basic security criteria for the design,
|
|
implementation, and use of passwords.
|
|
|
|
9. Export Control. The Bureau of Export Administration, U.S.
|
|
Department of Commerce, is responsible for administering export
|
|
controls on cryptographic products used for authentication and
|
|
access control, which categories would include implementations of
|
|
the Automated Password Generator. Vendors should contact the
|
|
following for a product classification:
|
|
|
|
Bureau of Export Administration
|
|
U.S. Department of Commerce
|
|
P.O. Box 273
|
|
Washington, DC 20044
|
|
Telephone: (202) 482-0708
|
|
|
|
Following this determination, the vendor will be informed whether
|
|
an export license is required and will be provided further
|
|
information as appropriate.
|
|
|
|
10. Specifications. Federal Information Processing Standard (FIPS)
|
|
181, Automated Password Generator (affixed);
|
|
|
|
11. Qualifications. The Automated Password Generator uses the
|
|
Electronic Codebook (ECB) mode of the Data Encryption Standard
|
|
(DES), Federal Information Processing Standard 46-1 (FIPS PUB 46-
|
|
1), as the random number generator. This mode of operation is
|
|
specified in FIPS 81, DES Modes of Operation.
|
|
|
|
The protection provided by the DES algorithm against potential
|
|
threats has been reviewed every 5 years since its adoption in 1977
|
|
and has been reaffirmed during each of those reviews. The DES, and
|
|
the possible threats reducing the security provided by the use of
|
|
DES, will undergo continual review by NIST and other cognizant
|
|
Federal organizations. The new technology available at review time
|
|
will be evaluated to determine its impact on the DES. In addition,
|
|
the awareness of any breakthrough in technology or any mathematical
|
|
weakness of the algorithm will cause NIST to reevaluate the DES and
|
|
provide necessary revisions.
|
|
|
|
12. Implementation Schedule. This Standard becomes effective
|
|
March 25, 1994.
|
|
|
|
13. Waivers. Under certain exceptional circumstances, the heads of
|
|
Federal departments and agencies may approve waivers to Federal
|
|
Information Processing Standards (FIPS). The head of such agency
|
|
may redelegate such authority only to a senior official designated
|
|
pursuant to section 3506(b) of Title 44, U.S. Code. Waivers shall
|
|
be granted only when compliance with a standard would:
|
|
|
|
a. adversely affect the accomplishment of the mission of an
|
|
operator of a Federal computer system, or
|
|
|
|
b. cause a major adverse financial impact on the operator
|
|
which is not offset by Government-wide savings.
|
|
|
|
Agency heads may act upon a written waiver request containing the
|
|
information detailed above. Agency heads may also act without a
|
|
written waiver request when they determine that conditions for
|
|
meeting the standard cannot be met. Agency heads may approve
|
|
waivers only by a written decision which explains the basis on
|
|
which the agency head made the required finding(s). A copy of each
|
|
such decision, with procurement sensitive or classified portions
|
|
clearly identified, shall be sent to: National Institute of
|
|
Standards and Technology; ATTN: FIPS Waiver Decisions; Technology
|
|
Building, Room B-154; Gaithersburg, MD 20899.
|
|
|
|
In addition, notice of each waiver granted and each delegation of
|
|
authority to approve waivers shall be sent promptly to the
|
|
Committee on Government Operations of the House of Representatives
|
|
and the Committee on Government Affairs of the Senate and shall be
|
|
published promptly in the Federal Register.
|
|
|
|
When the determination on a waiver applies to the procurement of
|
|
equipment and/or services, a notice of the waiver determination
|
|
must be published in the Commerce Business Daily as a part of the
|
|
notice of solicitation for offers of an acquisition or, if the
|
|
waiver determination is made after that notice is published, by
|
|
amendment to such notice.
|
|
|
|
A copy of the waiver, any supporting documents, the document
|
|
approving the waiver, and any supporting and accompanying
|
|
documents, with such deletions as the agency is authorized and
|
|
decides to make under 5 U.S.C Sec. 552(b), shall be part of the
|
|
procurement documentation and retained by the agency.
|
|
|
|
14. Where to Obtain Copies. Copies of this publication are
|
|
available for sale by the National Technical Information Service,
|
|
U.S. Department of Commerce, Springfield, VA 22161. When ordering,
|
|
refer to Federal Information Processing Standards Publication 181
|
|
(FIPSPUB181), and identify the title. When microfiche is desired,
|
|
this should be specified. Payment may be made by check, money
|
|
order, credit card, or deposit account.Federal Information
|
|
Processing Standards Publication 181
|
|
|
|
1993 October 5
|
|
|
|
Announcing the Standard for
|
|
|
|
Automated Password Generator
|
|
|
|
|
|
|
|
Contents
|
|
|
|
|
|
1.0 INTRODUCTION . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .6
|
|
|
|
|
|
2.0 TECHNICAL EXPLANATION . . . . . . . . . . . . . . . . . . . . . . . . 6
|
|
2.1 Unit Table . . . . . . . . . . . . . . . . . . . . . . . . . 6
|
|
2.2 Digram Table . . . . . . . . . . . . . . . . . . . . . . . . 7
|
|
2.3 Random Number Generator Subroutine . . . . . . . . . . . . . 7
|
|
2.4 Random Word Algorithm. . . . . . . . . . . . . . . . . . . . 8
|
|
2.5 NIST Implementation. . . . . . . . . . . . . . . . . . . . . 9
|
|
|
|
Appendix A . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
|
|
1.0 INTRODUCTION
|
|
|
|
The Automated Password Generator standard is derived from a C-code
|
|
version of the program described in "A Random Word Generator For
|
|
Pronounceable Passwords," National Technical Information Service
|
|
(NTIS) AD A 017676. The original program used Unix system
|
|
functions to produce the random numbers needed by the password
|
|
generator. These functions were replaced with a DES-based random
|
|
number subroutine that uses DES in the Electronic Code Book (ECB)
|
|
mode. As input, DES uses the old password or user supplied
|
|
character string, and a pseudorandom key created in accordance with
|
|
the procedure described in Appendix C of ANSI X9.17. Any change to
|
|
either the key or input data string causes DES to generate an
|
|
entirely different random number. Every time this occurs the
|
|
password generator creates a new random password.
|
|
|
|
|
|
2.0 TECHNICAL EXPLANATION
|
|
|
|
The Automated Password Generator standard is organized as a main
|
|
procedure that references three major components: (1) the "unit
|
|
table"; (2) the "digram table"; and (3) the "random number
|
|
subroutine." The random password generator works by forming
|
|
pronounceable syllables and concatenating them to form a word.
|
|
Rules of pronounceability are stored in a table for every unit and
|
|
every pair of units (digram). The rules are used to determine
|
|
whether a given unit is legal or illegal, based on its position
|
|
within the syllable and adjacent units. Most rules and checks are
|
|
syllable oriented and do not depend on anything outside the current
|
|
syllable. The main procedure (algorithm) defines the internal
|
|
rules used to generate random words. The three components and the
|
|
algorithm are described below.
|
|
|
|
Appendix A is the code for the NIST implementation of the Automated
|
|
Password Generator standard. This code consists of the C-code
|
|
version of the program described in "A Random Word Generator For
|
|
Pronounceable Passwords," the code that comprises the DES random
|
|
number subroutine, the actual DES subroutine, and the code for
|
|
generating the pseudorandom key. Implementations in other
|
|
programming languages are acceptable, however, the results obtained
|
|
must be logically equivalent to those produced by this standard.
|
|
|
|
In the NIST implementation of the password generator, the values
|
|
selected for the two DES keys and the seed for the random number
|
|
generator are readable in the code (Appendix A). In an actual
|
|
vendor or user developed implementation the values of the keys and
|
|
the seed would be secret, randomly generated values set by the
|
|
application.
|
|
|
|
|
|
2.1 Unit Table
|
|
|
|
The unit table defines the units (alphabetic characters) and
|
|
specifies rules pertaining to the individual units used in a
|
|
randomly generated word. For example, the location of vowels in
|
|
the words generated is determined by these rules. The unit table
|
|
used in the Automated Password Generator standard is identical to
|
|
that furnished in the report "A Random Word Generator For
|
|
Pronounceable Passwords" (item i in Cross Index).
|
|
|
|
|
|
2.2 Digram Table
|
|
|
|
The digram table specifies rules about all possible pairs of units
|
|
and the juxtaposition of units. The table contains one entry for
|
|
every pair of units (digram), whether that pair is allowed or not.
|
|
The random word generator ensures that the rules specified in the
|
|
digram table are satisfied for every two consecutive units in the
|
|
word being formed. The digram table is also from the original
|
|
report.
|
|
|
|
|
|
2.3 Random Number Generator Subroutine
|
|
|
|
The random number generator uses a DES subroutine to produce double
|
|
precision floating point values between 0 and (excluding) 1. These
|
|
numbers are multiplied by a program variable n which is an integer
|
|
value. This operation yields a random integer between 0 and (n-1)
|
|
inclusive. The random numbers created by the DES routine serve as
|
|
input to the random word generator. The subroutine to generate
|
|
these numbers is called by the word generator each time a character
|
|
(unit) is needed.
|
|
|
|
Not all characters generated will be acceptable to the word
|
|
generator in every position of the word. Each character is checked
|
|
for appropriateness using the rules defined by the unit and digram
|
|
tables. Therefore the random number generator subroutine will be
|
|
repeatedly called until an acceptable character is returned. An
|
|
upper limit of 100 calls is placed on generating any particular
|
|
character. If that number is reached the whole word is discarded
|
|
and the program starts over.
|
|
|
|
The actual distribution of legal units is different for every
|
|
position in a particular word which, for any unit, depends on the
|
|
units that precede it as well as the units and digram tables. The
|
|
random number subroutine itself makes no tests for legal units.
|
|
|
|
As its input DES accepts two 64 bit data blocks. One consists of
|
|
the old password or a data string; the other is a 64 bit (56 bits
|
|
+ 8 parity bits) pseudorandom key derived using the procedure
|
|
described in Appendix C of ANSI X9.17. The old password is entered
|
|
manually from the keyboard. An input array is created from the
|
|
first eight bytes of the password or input string. The program
|
|
will accept a null string (carriage return). All characters past
|
|
the eighth are disregarded. If the input block is less than eight
|
|
characters long the extra elements in the input array are filled
|
|
with ASCII 0. The Electronic Codebook (ECB) mode of DES described
|
|
in FIPS 81 ("DES Modes of Operation," December 2, 1980) is then
|
|
used to encrypt the input data. The output is a 64-bit random
|
|
number which is the encrypted form of the input.
|
|
The first function in the DES structure is setkey(), which converts
|
|
the pseudorandom key to a format used by DES for the encryption.
|
|
The command-line options sent to setkey are (0, 0, key). The first
|
|
0 is set so that setkey() does not generate parity; the second 0
|
|
tells setkey() that encryption (rather than decryption) is
|
|
required. Key is a pointer to the beginning of the key array.
|
|
After setkey(), the des() function is called. For input it uses
|
|
the addresses of the input and output arrays. Both input and
|
|
output are defined as unsigned character arrays of length 8 bytes.
|
|
|
|
|
|
The output array, out, is sent to a function, answer(), which
|
|
returns the final required number. The function answer() takes in
|
|
the address of the output array as an unsigned char pointer and the
|
|
integer n for which a value of 0 to (n-1) is needed by the random
|
|
word program. This function creates a variable sum, defined as an
|
|
unsigned integer. To obtain a numerical value from the output
|
|
character array, it adds the ASCII values of the first three
|
|
elements in the out array and stores the sum in the variable sum.
|
|
Thus, sum = out[0] + out[1] + out[2], which is an integer. To
|
|
obtain a number with the required range of 0 to n-1 from sum, the
|
|
function takes the modulus of sum and n, (sum%n). This value is
|
|
then returned to the calling function within the random word
|
|
program.
|
|
|
|
|
|
2.4 Random Word Algorithm
|
|
|
|
The algorithm used to generate random words is fixed and cannot be
|
|
modified without changing the logic of the program. The function
|
|
of the algorithm is to determine whether a given unit, generated by
|
|
the random unit subroutine, can be appended to the end of the
|
|
partial word formed so far. Rules of pronounceability are stored
|
|
in the unit and digram tables discussed above. The rules are used
|
|
to check if a given unit is legal or illegal. If illegal, the unit
|
|
is discarded and the random unit subroutine is called again. Once
|
|
a unit is accepted, various state variables are updated and a unit
|
|
for the next position in the word is tried. Most rules and checks
|
|
are syllable oriented and do not depend on anything outside the
|
|
current syllables. When the end of the word is reached, additional
|
|
checks are made before the algorithm terminates.
|
|
|
|
Passwords created by this automated password generator are composed
|
|
of the 26 characters of the English alphabet. Although numbers and
|
|
special characters are not permitted, the password space, which is
|
|
a function of the number of characters in the password, is very
|
|
large. Approximately 18 million 6-character, 5.7 billion 8-
|
|
character, and 1.6 trillion 10-character passwords can be created
|
|
by the program. Users should select a password space commensurate
|
|
with the level of security required for the information being
|
|
protected.
|
|
|
|
The password algorithm does not preclude the generation of words
|
|
found in a standard English dictionary. If required, a
|
|
computerized dictionary could be used to check for English words,
|
|
and the implementation could include software tests to prevent them
|
|
from being offered to users as passwords.
|
|
2.5 NIST Implementation
|
|
|
|
Figure 1 is a block diagram of the NIST implementation of the
|
|
automated password generation algorithm. Appendix A contains the
|
|
C-code for the DES, random key generation, and random word
|
|
generation routines that were used in the implementation (see
|
|
shaded boxes in Fig. 1). The personal computer used by NIST to
|
|
demonstrate the standard is implementation dependent. NIST
|
|
replaced the Unix random number routine in the original version of
|
|
the program with the "DES Randomizer" and "Generate Random Key"
|
|
function. The DES randomizer accepts an old password and a
|
|
pseudorandom key created in accordance with Appendix C of ANSI
|
|
X9.17 ( FIPSPUB 171) and generates a random number. This number is
|
|
used by the Random Word Generator to develop a password. As the
|
|
password is being generated each group of letters is subjected to
|
|
tests of grammar and semantics to determine if an acceptable word
|
|
has been created. If all tests are passed, the new password is
|
|
output to the PC.
|
|
|
|
In the NIST implementation, the values for minlen and maxlen, which
|
|
define the minimun and maximum size of the password, were set at 5
|
|
and 8 respectively. A user needing a fixed length password word
|
|
could set these variables to a specific value.
|
|
|
|
|
|
|
|
|
|
Appendix A
|
|
|
|
The following is a listing of the source code referenced in the
|
|
Automated Password Generator Standard.
|
|
|
|
|
|
/*
|
|
* randomword (word, hyphenated_word, minlen, maxlen, restrict,
|
|
seed)
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
|
|
#define RAN_DEBUG
|
|
#define B1
|
|
|
|
#define TRUE 1
|
|
#define FALSE 0
|
|
|
|
#define RULE_SIZE (sizeof(rules)/sizeof(struct unit))
|
|
#define ALLOWED(flag) (digram[units_in_syllable[current_unit -
|
|
1]][unit] & (flag))
|
|
|
|
#define MAX_UNACCEPTABLE 20
|
|
#define MAX_RETRIES (4 * (int) pwlen + RULE_SIZE)
|
|
|
|
#define NOT_BEGIN_SYLLABLE 010
|
|
#define NO_FINAL_SPLIT 04
|
|
#define VOWEL 02
|
|
#define ALTERNATE_VOWEL 01
|
|
#define NO_SPECIAL_RULE 0
|
|
|
|
#define BEGIN 0200
|
|
#define NOT_BEGIN 0100
|
|
#define BREAK 040
|
|
#define PREFIX 020
|
|
#define ILLEGAL_PAIR 010
|
|
#define SUFFIX 04
|
|
#define END 02
|
|
#define NOT_END 01
|
|
#define ANY_COMBINATION 0
|
|
|
|
typedef unsigned int uint;
|
|
typedef int boolean;
|
|
|
|
static int get_word();
|
|
static boolean have_initial_y();
|
|
static boolean illegal_placement();
|
|
static boolean improper_word();
|
|
static boolean have_final_split();
|
|
static char *get_syllable();
|
|
static unsigned short int random_unit();
|
|
static unsigned int randint();
|
|
static unsigned short int get_random();
|
|
static void set_seed();
|
|
|
|
extern char *calloc ();
|
|
extern char *malloc ();
|
|
extern char *strcpy ();
|
|
extern char *strcat ();
|
|
extern long time ();
|
|
extern long atol ();
|
|
extern double drand48();
|
|
extern int fscanf();
|
|
extern int fprintf();
|
|
|
|
|
|
struct unit
|
|
{
|
|
char unit_code[5];
|
|
unsigned short int flags;
|
|
};
|
|
|
|
static struct unit 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[][RULE_SIZE] =
|
|
{
|
|
/* 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 RAN_DEBUG
|
|
main (argc, argv)
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
register int argno;
|
|
register long seed;
|
|
register unsigned short int pwlen;
|
|
register unsigned short int minimum;
|
|
int number_of_words;
|
|
boolean no_legal_words;
|
|
register char *unhyphenated_word;
|
|
register char *hyphenated_word;
|
|
time_t ltime;
|
|
|
|
#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 (RAN_DEBUG is set), we generate the seed
|
|
from here
|
|
* rather than the first entry to randomword() .
|
|
*/
|
|
if (seed == 0L){
|
|
time(<ime);
|
|
set_seed((long) ltime);
|
|
}
|
|
|
|
if (minimum > pwlen)
|
|
{
|
|
(void) fflush(stdout);
|
|
(void) fprintf (stderr, "minimum (%u) new password length
|
|
cannot exceed maximum (%u)\n", (uint) minimum, (uint) pwlen);
|
|
(void) fflush(stderr);
|
|
exit (1);
|
|
}
|
|
(void) fflush(stderr);
|
|
(void) fprintf (stdout, "(New password will be between %u and
|
|
%u characters long)\n", (uint) minimum, (uint) pwlen);
|
|
(void) fflush (stdout);
|
|
for (argno = 1; argno <= number_of_words; argno++)
|
|
{
|
|
unhyphenated_word = calloc (sizeof (char), pwlen + 1);
|
|
hyphenated_word = calloc (sizeof (char), 2 * pwlen);
|
|
#ifdef B1
|
|
switch (algorithm) {
|
|
default:
|
|
case 0:
|
|
(void) randomword (unhyphenated_word, hyphenated_word,
|
|
minimum, pwlen, no_legal_words, 0L);
|
|
(void) fflush(stderr);
|
|
(void) fprintf (stdout, "%s (%s)\n", unhyphenated_word,
|
|
hyphenated_word);
|
|
break;
|
|
case 1:
|
|
(void) randomchars (unhyphenated_word, minimum, pwlen,
|
|
no_legal_words, 0L);
|
|
(void) fflush(stderr);
|
|
(void) fprintf (stdout, "%s\n", unhyphenated_word);
|
|
break;
|
|
case 2:
|
|
(void) randomletters (unhyphenated_word, minimum, pwlen,
|
|
no_legal_words, 0L);
|
|
(void) fflush(stderr);
|
|
(void) fprintf (stdout, "%s\n", unhyphenated_word);
|
|
break;
|
|
}
|
|
#else
|
|
(void) randomword (unhyphenated_word, hyphenated_word,
|
|
minimum, pwlen, no_legal_words, 0L);
|
|
(void) fflush(stderr);
|
|
(void) fprintf (stdout, "%s (%s)\n", unhyphenated_word,
|
|
hyphenated_word);
|
|
#endif
|
|
(void) fflush (stdout);
|
|
free (unhyphenated_word);
|
|
free (hyphenated_word);
|
|
}
|
|
}
|
|
#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(string, minlen, maxlen, restrict, seed)
|
|
register char *string;
|
|
register unsigned short int minlen;
|
|
register unsigned short int maxlen;
|
|
register boolean restrict;
|
|
long seed;
|
|
{
|
|
register int loop_count;
|
|
register unsigned short int string_size;
|
|
register unsigned short int build;
|
|
static 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 RAN_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
|
|
int) '!',
|
|
(unsigned short int) '~');
|
|
}
|
|
|
|
|
|
|
|
|
|
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(string, minlen, maxlen, restrict, seed)
|
|
register char *string;
|
|
register unsigned short int minlen;
|
|
register unsigned short int maxlen;
|
|
register boolean restrict;
|
|
long seed;
|
|
{
|
|
register int loop_count;
|
|
register unsigned short int string_size;
|
|
register unsigned short int build;
|
|
static 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 RAN_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
|
|
int) 'a', (unsigned short int) '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 (word, hyphenated_word, minlen, maxlen, restrict, seed)
|
|
register char *word;
|
|
register char *hyphenated_word;
|
|
register unsigned short int minlen;
|
|
register unsigned short int maxlen;
|
|
register boolean restrict;
|
|
long seed;
|
|
{
|
|
register int pwlen;
|
|
register int loop_count;
|
|
static 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 RAN_DEBUG
|
|
set_seed(seed);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Check for minlen>maxlen. This is an error.
|
|
* and a length of 0.
|
|
*/
|
|
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) {
|
|
(void) fflush(stdout);
|
|
(void) fprintf(stderr, "could not find acceptable random
|
|
password\n");
|
|
(void) 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 (word, hyphenated_word, pwlen)
|
|
char *word;
|
|
char *hyphenated_word;
|
|
unsigned short int pwlen;
|
|
{
|
|
register unsigned short int word_length;
|
|
register unsigned short int syllable_length;
|
|
register char *new_syllable;
|
|
register unsigned short int *syllable_units;
|
|
register unsigned short int word_size;
|
|
register unsigned short int word_place;
|
|
int unsigned short *word_units;
|
|
int unsigned short syllable_size;
|
|
int unsigned 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 int *)
|
|
calloc (sizeof (unsigned short int), pwlen);
|
|
syllable_units =
|
|
(unsigned short int *)
|
|
calloc (sizeof (unsigned short int), pwlen);
|
|
new_syllable =
|
|
calloc (sizeof (unsigned short int), pwlen);
|
|
|
|
/*
|
|
* Find syllables until the entire word is constructed.
|
|
*/
|
|
while (word_length < pwlen)
|
|
{
|
|
/*
|
|
* Get the syllable and find its length.
|
|
*/
|
|
(void) 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)
|
|
{
|
|
(void) strcpy (word, new_syllable);
|
|
(void) strcpy (hyphenated_word, new_syllable);
|
|
}
|
|
else
|
|
{
|
|
(void) strcat (word, new_syllable);
|
|
(void) strcat (hyphenated_word, "-");
|
|
(void) 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;
|
|
(void) strcpy (word, "");
|
|
(void) 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 (units, word_size)
|
|
register unsigned short int *units;
|
|
register unsigned short int word_size;
|
|
{
|
|
register unsigned short int unit_count;
|
|
register 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 (units, unit_size)
|
|
register unsigned short int *units;
|
|
register unsigned short int unit_size;
|
|
{
|
|
register unsigned short int unit_count;
|
|
register unsigned short int vowel_count;
|
|
register unsigned short int 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 (units, unit_size)
|
|
register unsigned short int *units;
|
|
register unsigned short int unit_size;
|
|
{
|
|
register unsigned short int unit_count;
|
|
register unsigned short int 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 (syllable, pwlen, units_in_syllable, syllable_length)
|
|
char *syllable;
|
|
unsigned short int pwlen;
|
|
unsigned short int *units_in_syllable;
|
|
unsigned short int *syllable_length;
|
|
{
|
|
register unsigned short int unit;
|
|
register short int current_unit;
|
|
register unsigned short int vowel_count;
|
|
register boolean rule_broken;
|
|
register boolean want_vowel;
|
|
register boolean want_another_unit;
|
|
int unsigned tries;
|
|
int unsigned short last_unit;
|
|
int short length_left;
|
|
unsigned short int hold_saved_unit;
|
|
static unsigned short int saved_unit;
|
|
static unsigned short int 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;
|
|
(void) strcpy (syllable, "");
|
|
vowel_count = 0;
|
|
current_unit = 0;
|
|
length_left = (short int) 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++;
|
|
(void) 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 int) 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 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 (length_left == 0)
|
|
if (rules[unit].flags & VOWEL)
|
|
want_another_unit = FALSE;
|
|
else
|
|
rule_broken = TRUE;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* 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)
|
|
{
|
|
/*
|
|
* 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
|
|
{
|
|
/*
|
|
* We are not at the start of a syllable.
|
|
* Save the previous unit for later tests.
|
|
*/
|
|
last_unit = units_in_syllable[current_unit - 1];
|
|
|
|
/*
|
|
* 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
|
|
/*
|
|
* 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.
|
|
*/
|
|
if ((vowel_count != 0) &&
|
|
!(rules[last_unit].flags & VOWEL))
|
|
{
|
|
/*
|
|
* 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
|
|
/*
|
|
* 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 ((vowel_count != 0) && (length_left > 0))
|
|
{
|
|
/*
|
|
* 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 int) 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;
|
|
(void) strcat (syllable, rules[unit].unit_code);
|
|
break;
|
|
case 1:
|
|
current_unit--;
|
|
break;
|
|
case 2:
|
|
(void) strcpy (&syllable[strlen (syllable) -
|
|
strlen (rules[last_unit].
|
|
unit_code)],
|
|
"");
|
|
length_left += (short int) 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_length = current_unit;
|
|
|
|
current_unit++;
|
|
}
|
|
while ((tries <= MAX_RETRIES) && want_another_unit);
|
|
}
|
|
while (rule_broken ||
|
|
illegal_placement (units_in_syllable, *syllable_length));
|
|
|
|
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 (units, pwlen)
|
|
register unsigned short int *units;
|
|
register unsigned short int pwlen;
|
|
{
|
|
register unsigned short int vowel_count;
|
|
register unsigned short int unit_count;
|
|
register 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 int 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 int 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 int
|
|
random_unit (type)
|
|
register unsigned short int type;
|
|
{
|
|
register unsigned short int 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 int))];
|
|
else
|
|
/*
|
|
* Get any letter according to the English distribution.
|
|
*/
|
|
number = numbers[get_random (0, sizeof (numbers) / sizeof
|
|
(unsigned short int))];
|
|
return (number);
|
|
}
|
|
|
|
|
|
/*
|
|
* This routine should return a uniformly distributed random number
|
|
between
|
|
* minlen and maxlen inclusive. The Electronic Code Book form of
|
|
DES is
|
|
* used to produce the random number. The inputs to DES are the
|
|
old pass-
|
|
* word and a pseudorandom key generated according to the procedure
|
|
out-
|
|
* lined in Appendix C of ANSI X9.17.
|
|
*/
|
|
|
|
static unsigned short int
|
|
get_random (minlen, maxlen)
|
|
register unsigned short int minlen;
|
|
register unsigned short int maxlen;
|
|
{
|
|
return minlen + (unsigned short int) randint ((int) (maxlen -
|
|
minlen + 1));
|
|
}
|
|
|
|
|
|
/*
|
|
* Produces a random number from 0 to n-1 .
|
|
*/
|
|
static unsigned int
|
|
randint(n)
|
|
int n;
|
|
{
|
|
return ((unsigned int) (randfunc(n)));
|
|
}
|
|
|
|
|
|
/ * Set the seed. This routine will only set the seed once, even
|
|
if
|
|
* called from multiple sources.
|
|
*/
|
|
static void
|
|
set_seed(seed)
|
|
long seed;
|
|
{
|
|
int been_here_before = 0;
|
|
|
|
if (!been_here_before) {
|
|
been_here_before = 1;
|
|
srand(seed);
|
|
}
|
|
}
|
|
|
|
/* takes in old password and calls program to generate random
|
|
number by
|
|
calling the DES function. This function is called many times.
|
|
It
|
|
asks for the old password the first time and then sends that
|
|
password
|
|
to the DES function on every successive call afterwards. */
|
|
|
|
static int randfunc(n)
|
|
int n;
|
|
{
|
|
int i, len;
|
|
static char passwd[9];
|
|
static boolean newpass=0;
|
|
if(!newpass)
|
|
{
|
|
printf("Please enter old password or input string: ");
|
|
gets(passwd);
|
|
printf("string entered: %s\n", passwd);
|
|
len = strlen(passwd);
|
|
for (i=len; i<8; i++)
|
|
passwd[i] = '0';
|
|
printf("string padded: %s\n", passwd);
|
|
newpass=1;
|
|
}
|
|
return(descall(passwd, n));
|
|
}
|
|
|
|
|
|
/* descall calls the pseudorandom key generator, random, described
|
|
in Appendix C of
|
|
ANSI 9.17 and puts the resulting value into the array key. The
|
|
arguments of random
|
|
indicate that odd parity should be generated and that the input
|
|
string is eight bytes
|
|
in length. The des routine, which uses key and the old password as
|
|
arguments, is then
|
|
called. The output from des, out, is then sent to the routine,
|
|
answer, for processing */
|
|
|
|
|
|
descall(in, n)
|
|
unsigned char *in;
|
|
int n;
|
|
{
|
|
unsigned char key[8];
|
|
unsigned char out[8];
|
|
int i;
|
|
|
|
random(key, 1,);
|
|
setkey(0, 0, key);
|
|
des(in, out);
|
|
return (answer(out,n));
|
|
}
|
|
|
|
/* 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(out,n)
|
|
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);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
**************
|
|
* DES.C
|
|
VERSION 4.00 *
|
|
|
|
*----------------------------------------------------------------
|
|
---------------------------------------*
|
|
* D A T A E N C R Y P T I O N S T A N D A R D
|
|
*
|
|
* FEDERAL INFORMATION PROCESSING STANDARDS PUBLICATION (FIPS PUB)
|
|
46-1
|
|
|
|
*----------------------------------------------------------------
|
|
---------------------------------------*
|
|
* This software was produced at the National Institute of
|
|
Standards and Techology *
|
|
* (NIST) as a part of research efforts and for demonstration
|
|
purposes only. Our *
|
|
* primary goals in its design did not include widespread use
|
|
outside of *
|
|
* our own laboratories. Acceptance of this software implies that
|
|
you *
|
|
* agree to accept it as nonproprietary and unlicensed, not
|
|
supported by *
|
|
* NIST, and not carrying any warranty, either expressed or
|
|
implied, as to *
|
|
* its performance or fitness for any particular purpose.
|
|
*
|
|
|
|
*----------------------------------------------------------------
|
|
---------------------------------------*
|
|
* Cryptographic devices and technical data regarding them are
|
|
subject to *
|
|
* Federal Government export controls as specified in Title 22,
|
|
Code of *
|
|
* Federal Regulations, Parts 121 through 128. Cryptographic
|
|
devices *
|
|
* implementing the Data Encryption Standard (DES) and technical
|
|
data *
|
|
* regarding them must comply with these Federal regulations.
|
|
*
|
|
|
|
*----------------------------------------------------------------
|
|
---------------------------------------*
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
#define BYTE unsigned char
|
|
#define INT unsigned int
|
|
|
|
/****************************************************************
|
|
**************
|
|
* SETKEY() Generate key schedule for given key and type of
|
|
cryption *
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
/* PERMUTED CHOICE 1 (PC1) */
|
|
INT PC1[] = {
|
|
57,49,41,33,25,17, 9,
|
|
1,58,50,42,34,26,18,
|
|
10, 2,59,51,43,35,27,
|
|
19,11, 3,60,52,44,36,
|
|
63,55,47,39,31,23,15,
|
|
7,62,54,46,38,30,22,
|
|
14, 6,61,53,45,37,29,
|
|
21,13, 5,28,20,12, 4,
|
|
};
|
|
|
|
/* Schedule of left shifts for C and D blocks */
|
|
unsigned short shifts[] = { 1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1 };
|
|
|
|
/* PERMUTED CHOICE 2 (PC2) */
|
|
INT PC2[] = {
|
|
14,17,11,24, 1, 5,
|
|
3,28,15, 6,21,10,
|
|
23,19,12, 4,26, 8,
|
|
16, 7,27,20,13, 2,
|
|
41,52,31,37,47,55,
|
|
30,40,51,45,33,48,
|
|
44,49,39,56,34,53,
|
|
46,42,50,36,29,32,
|
|
};
|
|
|
|
/* Key schedule of 16 48-bit subkeys generated from 64-bit key */
|
|
BYTE KS[16][48];
|
|
|
|
setkey(sw1,sw2,pkey)
|
|
INT sw1; /* parity: 0=ignore,1=check */
|
|
INT sw2; /* type cryption: 0=encrypt,1=decrypt */
|
|
BYTE *pkey; /* 64-bit key packed into 8 bytes */
|
|
{
|
|
register INT i, j, k, t1, t2;
|
|
static BYTE key[64];
|
|
static BYTE CD[56];
|
|
|
|
/* Double-check 'parity' parameter */
|
|
if (sw1 != 0 && sw1 != 1) {
|
|
printf("\007*** setkey: bad parity parameter (%d)
|
|
***\n", sw1);
|
|
return(0);
|
|
}
|
|
|
|
/* Double-check 'type of cryption' parameter */
|
|
if (sw2 != 0 && sw2 != 1) {
|
|
printf("\007*** setkey: bad cryption parameter (%d)
|
|
***\n",sw2);
|
|
return(0);
|
|
}
|
|
|
|
/* Unpack KEY from 8 bits/byte into 1 bit/byte */
|
|
unpack8(pkey,key);
|
|
|
|
/* Check for ODD key parity */
|
|
if (sw1 == 1) {
|
|
for (i=0; i<64; i++) {
|
|
k = 1;
|
|
for (j=0; j<7; j++,i++) k = (k + key[i]) % 2;
|
|
if (key[i] != k) return(0);
|
|
}
|
|
}
|
|
|
|
/* Permute unpacked key with PC1 to generate C and D */
|
|
for (i=0; i<56; i++) CD[i] = key[PC1[i]-1];
|
|
|
|
/* Rotate and permute C and D to generate 16 subkeys */
|
|
for (i=0; i<16; i++) {
|
|
/* Rotate C and D */
|
|
for (j=0; j<shifts[i]; j++) {
|
|
t1 = CD[0];
|
|
t2 = CD[28];
|
|
for (k=0; k<27; k++) {
|
|
CD[k] = CD[k+1];
|
|
CD[k+28] = CD[k+29];
|
|
}
|
|
CD[27] = t1;
|
|
CD[55] = t2;
|
|
}
|
|
/* Set order of subkeys for type of cryption */
|
|
j = sw2 ? 15-i : i;
|
|
/* Permute C and D with PC2 to generate KS[j] */
|
|
for (k=0; k<48; k++) KS[j][k] = CD[PC2[k]-1];
|
|
}
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************
|
|
**************
|
|
* DES()
|
|
*
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
|
|
/* INITIAL PERMUTATION (IP) */
|
|
INT IP[] = {
|
|
58,50,42,34,26,18,10, 2,
|
|
60,52,44,36,28,20,12, 4,
|
|
62,54,46,38,30,22,14, 6,
|
|
64,56,48,40,32,24,16, 8,
|
|
57,49,41,33,25,17, 9, 1,
|
|
59,51,43,35,27,19,11, 3,
|
|
61,53,45,37,29,21,13, 5,
|
|
63,55,47,39,31,23,15, 7,
|
|
};
|
|
|
|
/* REVERSE FINAL PERMUTATION (IP-1) */
|
|
INT RFP[] = {
|
|
8,40,16,48,24,56,32,64,
|
|
7,39,15,47,23,55,31,63,
|
|
6,38,14,46,22,54,30,62,
|
|
5,37,13,45,21,53,29,61,
|
|
4,36,12,44,20,52,28,60,
|
|
3,35,11,43,19,51,27,59,
|
|
2,34,10,42,18,50,26,58,
|
|
1,33, 9,41,17,49,25,57,
|
|
};
|
|
|
|
/* E BIT-SELECTION TABLE */
|
|
INT E[] = {
|
|
32, 1, 2, 3, 4, 5,
|
|
4, 5, 6, 7, 8, 9,
|
|
8, 9,10,11,12,13,
|
|
12,13,14,15,16,17,
|
|
16,17,18,19,20,21,
|
|
20,21,22,23,24,25,
|
|
24,25,26,27,28,29,
|
|
28,29,30,31,32, 1,
|
|
};
|
|
|
|
/* PERMUTATION FUNCTION P */
|
|
INT P[] = {
|
|
16, 7,20,21,
|
|
29,12,28,17,
|
|
1,15,23,26,
|
|
5,18,31,10,
|
|
2, 8,24,14,
|
|
32,27, 3, 9,
|
|
19,13,30, 6,
|
|
22,11, 4,25,
|
|
};
|
|
|
|
/* 8 S-BOXES */
|
|
INT S[8][64] = {
|
|
14, 4,13, 1, 2,15,11, 8, 3,10, 6,12, 5, 9, 0, 7,
|
|
0,15, 7, 4,14, 2,13, 1,10, 6,12,11, 9, 5, 3, 8,
|
|
4, 1,14, 8,13, 6, 2,11,15,12, 9, 7, 3,10, 5, 0,
|
|
15,12, 8, 2, 4, 9, 1, 7, 5,11, 3,14,10, 0, 6,13,
|
|
|
|
15, 1, 8,14, 6,11, 3, 4, 9, 7, 2,13,12, 0, 5,10,
|
|
3,13, 4, 7,15, 2, 8,14,12, 0, 1,10, 6, 9,11, 5,
|
|
0,14, 7,11,10, 4,13, 1, 5, 8,12, 6, 9, 3, 2,15,
|
|
13, 8,10, 1, 3,15, 4, 2,11, 6, 7,12, 0, 5,14, 9,
|
|
|
|
10, 0, 9,14, 6, 3,15, 5, 1,13,12, 7,11, 4, 2, 8,
|
|
13, 7, 0, 9, 3, 4, 6,10, 2, 8, 5,14,12,11,15, 1,
|
|
13, 6, 4, 9, 8,15, 3, 0,11, 1, 2,12, 5,10,14, 7,
|
|
1,10,13, 0, 6, 9, 8, 7, 4,15,14, 3,11, 5, 2,12,
|
|
|
|
7,13,14, 3, 0, 6, 9,10, 1, 2, 8, 5,11,12, 4,15,
|
|
13, 8,11, 5, 6,15, 0, 3, 4, 7, 2,12, 1,10,14, 9,
|
|
10, 6, 9, 0,12,11, 7,13,15, 1, 3,14, 5, 2, 8, 4,
|
|
3,15, 0, 6,10, 1,13, 8, 9, 4, 5,11,12, 7, 2,14,
|
|
|
|
2,12, 4, 1, 7,10,11, 6, 8, 5, 3,15,13, 0,14, 9,
|
|
14,11, 2,12, 4, 7,13, 1, 5, 0,15,10, 3, 9, 8, 6,
|
|
4, 2, 1,11,10,13, 7, 8,15, 9,12, 5, 6, 3, 0,14,
|
|
11, 8,12, 7, 1,14, 2,13, 6,15, 0, 9,10, 4, 5, 3,
|
|
|
|
12, 1,10,15, 9, 2, 6, 8, 0,13, 3, 4,14, 7, 5,11,
|
|
10,15, 4, 2, 7,12, 9, 5, 6, 1,13,14, 0,11, 3, 8,
|
|
9,14,15, 5, 2, 8,12, 3, 7, 0, 4,10, 1,13,11, 6,
|
|
4, 3, 2,12, 9, 5,15,10,11,14, 1, 7, 6, 0, 8,13,
|
|
|
|
4,11, 2,14,15, 0, 8,13, 3,12, 9, 7, 5,10, 6, 1,
|
|
13, 0,11, 7, 4, 9, 1,10,14, 3, 5,12, 2,15, 8, 6,
|
|
1, 4,11,13,12, 3, 7,14,10,15, 6, 8, 0, 5, 9, 2,
|
|
6,11,13, 8, 1, 4,10, 7, 9, 5, 0,15,14, 2, 3,12,
|
|
|
|
13, 2, 8, 4, 6,15,11, 1,10, 9, 3,14, 5, 0,12, 7,
|
|
1,15,13, 8,10, 3, 7, 4,12, 5, 6,11, 0,14, 9, 2,
|
|
7,11, 4, 1, 9,12,14, 2, 0, 6,10,13,15, 3, 5, 8,
|
|
2, 1,14, 7, 4,10, 8,13,15,12, 9, 0, 3, 5, 6,11,
|
|
};
|
|
|
|
|
|
des(in,out)
|
|
BYTE *in; /* packed 64-bit INPUT block */
|
|
BYTE *out; /* packed 64-bit OUTPUT block */
|
|
{
|
|
register INT i, j, k, t;
|
|
static BYTE block[64]; /* unpacked 64-bit input/output
|
|
block */
|
|
static BYTE LR[64], f[32], preS[48];
|
|
|
|
/* Unpack the INPUT block */
|
|
unpack8(in,block);
|
|
|
|
/* Permute unpacked input block with IP to generate L and
|
|
R */
|
|
for (j=0; j<64; j++) LR[j] = block[IP[j]-1];
|
|
|
|
/* Perform 16 rounds */
|
|
for (i=0; i<16; i++) {
|
|
/* Expand R to 48 bits with E and XOR with i-th
|
|
subkey */
|
|
for (j=0; j<48; j++) preS[j] = LR[E[j]+31] ^
|
|
KS[i][j];
|
|
/* Map 8 6-bit blocks into 8 4-bit blocks using
|
|
S-Boxes */
|
|
for (j=0; j<8; j++) {
|
|
/* Compute index t into j-th S-box */
|
|
k = 6*j;
|
|
t = preS[k];
|
|
t = (t<<1) | preS[k+5];
|
|
t = (t<<1) | preS[k+1];
|
|
t = (t<<1) | preS[k+2];
|
|
t = (t<<1) | preS[k+3];
|
|
t = (t<<1) | preS[k+4];
|
|
/* Fetch t-th entry from j-th S-box */
|
|
t = S[j][t];
|
|
/* Generate 4-bit block from S-box entry */
|
|
k = 4*j;
|
|
f[k] = (t>>3) & 1;
|
|
f[k+1] = (t>>2) & 1;
|
|
f[k+2] = (t>>1) & 1;
|
|
f[k+3] = t & 1;
|
|
}
|
|
for (j=0; j<32; j++) {
|
|
/* Copy R */
|
|
t = LR[j+32];
|
|
/* Permute f w/ P and XOR w/ L to generate new
|
|
R */
|
|
LR[j+32] = LR[j] ^ f[P[j]-1];
|
|
/* Copy original R to new L */
|
|
LR[j] = t;
|
|
}
|
|
}
|
|
|
|
/* Permute L and R with reverse IP-1 to generate output
|
|
block */
|
|
for (j=0; j<64; j++) block[j] = LR[RFP[j]-1];
|
|
|
|
/* Pack data into 8 bits per byte */
|
|
pack8(out,block);
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
**************
|
|
* PACK8() Pack 64 bytes at 1 bit/byte into 8 bytes at 8
|
|
bits/byte *
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
pack8(packed,binary)
|
|
BYTE *packed; /* packed block ( 8 bytes at 8 bits/byte) */
|
|
BYTE *binary; /* the unpacked block (64 bytes at 1 bit/byte)
|
|
*/
|
|
{
|
|
register INT i, j, k;
|
|
|
|
for (i=0; i<8; i++) {
|
|
k = 0;
|
|
for (j=0; j<8; j++) k = (k<<1) + *binary++;
|
|
*packed++ = k;
|
|
}
|
|
}
|
|
|
|
/****************************************************************
|
|
**************
|
|
* UNPACK8() Unpack 8 bytes at 8 bits/byte into 64 bytes at 1
|
|
bit/byte *
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
unpack8(packed,binary)
|
|
BYTE *packed; /* packed block (8 bytes at 8 bits/byte) */
|
|
BYTE *binary; /* unpacked block (64 bytes at 1 bit/byte) */
|
|
{
|
|
register INT i, j, k;
|
|
|
|
for (i=0; i<8; i++) {
|
|
k = *packed++;
|
|
for (j=0; j<8; j++) *binary++ = (k>>(7-j)) & 01;
|
|
}
|
|
}
|
|
|
|
#include <dos.h>
|
|
|
|
#define BYTE unsigned char
|
|
#define INT unsigned int
|
|
|
|
#define DECRYPT 1
|
|
#define ENCRYPT 0
|
|
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
|
|
#define SINGLE 1
|
|
#define PAIR 2
|
|
|
|
#define IGNORE 0
|
|
#define PKEYLEN 8
|
|
|
|
int krypt(int, int, int, BYTE *, int, BYTE *, BYTE *);
|
|
void random(BYTE *, int);
|
|
void set_parity(BYTE *, int);
|
|
void daytime(char *);
|
|
BYTE *bytncpy(BYTE *, BYTE *, int);
|
|
BYTE *bytnxor(BYTE *, BYTE *, BYTE *, int);
|
|
|
|
/****************************************************************
|
|
**************
|
|
* KRYPT() Encrypt/decrypt key or key pair
|
|
*
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
int krypt(sw1,sw2,sw3,kek,sw4,ikey,okey)
|
|
int sw1; /* ODD parity: 0=ignore, 1=check & report */
|
|
int sw2; /* type of cryption: 0=encrypt, 1=decrypt */
|
|
int sw3; /* length of kek: 1=single, 2=pair */
|
|
BYTE *kek; /* packed key-encrypting key */
|
|
int sw4; /* length of key: 1=single, 2=pair */
|
|
BYTE *ikey; /* packed input key */
|
|
BYTE *okey; /* packed output key */
|
|
{
|
|
char tkey[PKEYLEN];
|
|
|
|
/* DOUBLE-CHECK PARAMETERS */
|
|
if (sw3!=SINGLE && sw3!=PAIR) {
|
|
printf("krypt: bad kek length (%d)",sw3);
|
|
exit(1);
|
|
}
|
|
if (sw4!=SINGLE && sw4!=PAIR) {
|
|
printf("krypt: bad key length (%d)",sw4);
|
|
exit(1);
|
|
}
|
|
if (sw3==SINGLE && sw4==PAIR)
|
|
exit(1);
|
|
|
|
if (!setkey(sw1,sw2,kek)) return(FALSE);
|
|
des(ikey,okey);
|
|
if (sw3==SINGLE && sw4==SINGLE) return(TRUE); /* single by
|
|
single */
|
|
|
|
if (!setkey(sw1,sw2^01,kek+PKEYLEN)) return(FALSE);
|
|
des(okey,tkey);
|
|
(void) setkey(sw1,sw2,kek);
|
|
des(tkey,okey);
|
|
if (sw4==SINGLE) return(TRUE); /* single by double */
|
|
|
|
(void)
|
|
krypt(sw1,sw2,PAIR,kek,SINGLE,ikey+PKEYLEN,okey+PKEYLEN);
|
|
return(TRUE); /* double by double */
|
|
}
|
|
|
|
|
|
/****************************************************************
|
|
**************
|
|
* RANDOM() Pseudorandom KEY and IV Generator.
|
|
*
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
/* Random Key */
|
|
static BYTE rndkey[PAIR*PKEYLEN] =
|
|
{0xE0,0x9A,0xA8,0x0F,0xAB,0x72,0x1C,0x3D,
|
|
|
|
0x8F,0x7D,0xC9,0x9E,0x8F,0x02,0xB6,0x2A};
|
|
|
|
/* Seed */
|
|
static BYTE seed[PKEYLEN] =
|
|
{0xCF,0x65,0xAE,0x7F,0xB1,0x79,0xBB,0xE3};
|
|
|
|
void random(dest,odd)
|
|
BYTE *dest; /* destination for random KEY or IV */
|
|
int odd; /* generate ODD parity? 0=no, 1=yes */
|
|
{
|
|
BYTE dt[PKEYLEN]; /* date/time vector */
|
|
BYTE i[PKEYLEN];
|
|
BYTE j[PKEYLEN];
|
|
BYTE r[PKEYLEN];
|
|
|
|
/* DOUBLE-CHECK PARAMETERS */
|
|
if (odd!=FALSE && odd!=TRUE) {
|
|
printf("random: bad generate parity option (%d)", odd);
|
|
exit(1);
|
|
}
|
|
|
|
/* GET DATE/TIME VECTOR */
|
|
daytime(dt);
|
|
|
|
/* I = eRNDKEY(DT) */
|
|
(void) krypt(IGNORE,ENCRYPT,PAIR,rndkey,SINGLE,dt,i);
|
|
|
|
/* R = eRNDKEY(I + V) */
|
|
(void) bytnxor(j,i,seed,PKEYLEN);
|
|
(void) krypt(IGNORE,ENCRYPT,PAIR,rndkey,SINGLE,j,r);
|
|
|
|
/* new seed = eRNDKEY(R + I) */
|
|
(void) bytnxor(j,i,r,PKEYLEN);
|
|
(void) krypt(IGNORE,ENCRYPT,PAIR,rndkey,SINGLE,j,seed);
|
|
|
|
/* GENERATE ODD PARITY, IF NEEDED */
|
|
if (odd) set_parity(r,SINGLE);
|
|
|
|
(void) bytncpy(dest,r,PKEYLEN);
|
|
}
|
|
|
|
/****************************************************************
|
|
**************
|
|
* SET_PARITY() Set ODD parity
|
|
*
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
void set_parity(key,len)
|
|
BYTE *key; /* packed 64 or 128-bit key */
|
|
int len; /* key length: 1=SINGLE, 2=PAIR */
|
|
{
|
|
int i, j, parity, mask;
|
|
|
|
/* DOUBLE-CHECK PARAMETER */
|
|
if (len!=SINGLE && len!=PAIR) {
|
|
printf("set_parity: bad len parameter (%d)", len);
|
|
exit(1);
|
|
}
|
|
|
|
for (i=0; i<(len*PKEYLEN); i++) {
|
|
parity = 1;
|
|
mask = 2;
|
|
for (j=0; j<7; j++) {
|
|
parity = (parity + ((key[i] & mask) >> (j+1))) % 2;
|
|
mask = 2 * mask;
|
|
}
|
|
if (parity==0) key[i] = key[i] & 0xfe;/* clear */
|
|
if (parity==1) key[i] = key[i] | 0x01;/* set */
|
|
}
|
|
}
|
|
|
|
|
|
void daytime(dt)
|
|
char *dt; /* dt[8] = 64-bit block based on date & time */
|
|
{
|
|
register i;
|
|
int tt[8];
|
|
/* struct regval { int ax, bx, cx, dx, si, di, ds, es; };
|
|
struct regval call_regs, ret_regs; */
|
|
union REGS call_regs;
|
|
union REGS ret_regs;
|
|
|
|
call_regs.x.ax = 0x2a00; /* GET DATE */
|
|
intdos(&call_regs, &ret_regs);
|
|
tt[0] = ret_regs.x.cx - 1900; /* cx = year */
|
|
tt[1] = (ret_regs.x.dx & 0xff00) >> 8; /* dh = month */
|
|
tt[2] = ret_regs.x.dx & 0x00ff; /* dl = day */
|
|
|
|
call_regs.x.ax = 0x2c00; /* GET TIME */
|
|
intdos(&call_regs, &ret_regs);
|
|
tt[3] = (ret_regs.x.cx & 0xff00) >> 8; /* ch = hours */
|
|
tt[4] = ret_regs.x.cx & 0x00ff; /* cl = minutes */
|
|
tt[5] = (ret_regs.x.dx & 0xff00) >> 8; /* dh = seconds */
|
|
tt[6] = 0;
|
|
tt[7] = 0;
|
|
|
|
for (i=0;i<8;i++)
|
|
dt[i] = (char) tt[i];
|
|
}
|
|
|
|
/****************************************************************
|
|
**************
|
|
* BYTNCPY() Copy block of packed BYTEs
|
|
*
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
BYTE *bytncpy(dest,src,len) /* return pointer to destination
|
|
block */
|
|
BYTE *dest; /* destination block */
|
|
BYTE *src; /* source block */
|
|
int len; /* number of bytes */
|
|
{
|
|
while (len-- > 0) *dest++ = *src++;
|
|
return(dest);
|
|
}
|
|
|
|
/****************************************************************
|
|
**************
|
|
* BYTNXOR() XOR blocks of packed BYTEs
|
|
*
|
|
|
|
*****************************************************************
|
|
*************/
|
|
|
|
BYTE *bytnxor(dest,src1,src2,len) /* return ptr to destination
|
|
block */
|
|
BYTE *dest; /* destination block */
|
|
BYTE *src1; /* source block 1 */
|
|
BYTE *src2; /* source block 2 */
|
|
int len; /* number of BYTEs */
|
|
{
|
|
while (len-- > 0) *dest++ = *src1++ ^ *src2++;
|
|
return(dest);
|
|
}
|
|
|