commit c777362a387350e7d78c99fd4c77eff6e0189a68 Author: Adel I. Mirzazhanov Date: Thu Feb 22 17:00:10 2001 +0600 APG v1.2.12 diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..6a73815 --- /dev/null +++ b/CHANGES @@ -0,0 +1,67 @@ +apg-1.2.12 + Added support for AIX, and some compatibility reports + +apg-1.2.11 + Changed default owner of apg and apgd (now it is root). + Some cosmetic changes. + +apg-1.2.1 + Changed -R option. Changed documentation. + +apg-1.2.1b + Changed impementation of -y option. Now you can disable it + before compilation. + Added option -M for new style password modes specification. + (see apg(1) apgd(8)). + Added support for IRIX + (Thanks to Andrew J. Caird ) + +apg-1.2.1a2 + Added option -y (see apg(1)). + (Thanks to Andrew J. Caird ) + Some minior fixes for APG for Solaris. + +apg-1.2.1alpha + Added option -R (see apg(1) and apgd(8)). + +apg-1.2.0 + Changed random character password generation algorithm. + Changed user random seed generation procedures. + +apg-1.1.61b + Fixed directory permissions (thanks to Adrian Ho ). + Fixed random segfault when run with the -s argument + (thanks to Peter Pentchev ) + +apg-1.1.6b + Fixed random number generation error. + (Thanks to Rainer Wichmann ) + Now RNG uses local time with precision of microseconds + as initial seed. + (Thanks to Rainer Wichmann ) + Fixed error that was the reason of random APG crashes. + Added support for /dev/random for seed generation. + +apg-1.1.5 + Fixed some compiler warnings + Fixed pronounceable password generation error with modes -C -N. But + there is another bug ;-( Sorry... + It is no more an error if min_pass_len > max_pass_len. + Changed installation procedure + Added option -d (see apg(1)). + +apg-1.1.4 + Modified pronounceable password generation algorithm. + Now support -N and -C options, but still pronounceable ;-) + +apg-1.0.4 + Added option -c (see apg(1)).Changed apg.c, apg.1 manpage. + +apg-1.0.3 + Fixed somecode style errors. Changed INSTALL, apgd.8 manpage. + +apg-1.0.2 + Improved event logging of apgd. Changed INSTALL. + +apg-1.0.1 + Fixed password length error diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..87b115a --- /dev/null +++ b/COPYING @@ -0,0 +1,27 @@ +Copyright (c) 1999, 2000, 2001 +Adel I. Mirzazhanov. All rights reserved + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1.Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2.Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3.The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + \ No newline at end of file diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..f7afd40 --- /dev/null +++ b/INSTALL @@ -0,0 +1,91 @@ +Installation + +There are 2 types of installation: (1) stand-alone, (2) client-server +(See README for details). You can use each type separetly or you can +use them together. + +The simplest way to install this package is: +1. untar the distribution and cd to the top: + + % gzip -d -c apg-1.X.XX.tar.gz | tar xf - + % cd apg-1.X.XX + +If you are reading this file, you probably have already done this! + +2. Edit the Makefile + +3. make the software: + + For stand-alone: + + % make standalone + + For client-server: + + % make cliserv + + For both: + + % make all + +4. install the binaries and man pages. You may need to be superuser +to do this (depending on where you are installing things): + + % su + # make install + +5. You can remove the program binaries and object files from the +source code directory by typing + + % make clean + +NOTE: THE REST IS FOR CLIENT-SERVER INSTALLATION ONLY !!! + +6. Modify your /etc/inetd.conf file to contain the line below. +You may have to modify it to support your version of the file. + + pwdgen stream tcp nowait nobody /usr/local/sbin/apgd apgd [options] + +or + pwdgen stream tcp nowait nobody /usr/sbin/tcpd /usr/local/sbin/apgd [options] + +if you use tcp_wrapers. (for options see apgd(8) manpage) + +For all OS versions you must modify, your /etc/services file needs +to include the following line: + + pwdgen 129/tcp # PWDGEN service + +7. Restart inetd with a + + # kill -HUP inetdpid + +8. Configure your syslogd daemon to handle events `daemon.info' and +`daemon.debug' see syslogd(8) and syslog.conf(5) + +9. Check that apgd is working + + % telnet your.host.name 129 + +or + + % telnet your.host.name pwdgen + +10. Customize your apgcli.pl - APG client +Edit apgcli.pl file that can be found in src/perl directory of +source distribution tree + +----------------------------------> src/perl/apgcli.pl +#!/usr/bin/perl -w # Put here the real location of perl +$host = "localhost"; # Put here the name of your APG server +use IO::Socket; +$remote = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $host, + PeerPort => "pwdgen(129)", + ) + or die "cannot connect to pwdgen port at $host"; +while ( <$remote> ) { print } +----------------------------------> src/perl/apgcli.pl + +END diff --git a/INSTALL.CYGWIN b/INSTALL.CYGWIN new file mode 100644 index 0000000..95bb135 --- /dev/null +++ b/INSTALL.CYGWIN @@ -0,0 +1,43 @@ +Installation of APG toolkit for CYGWIN + +Generaly there are 2 types of installation: +(1) standalone +(2) client-server +but only standalone installation implemented for CYGWIN yet. + +The instruction below IS FOR STANDALONE INSTALLATION ONLY + +The simplest way to install this package is: +1. untar the distribution and cd to the top: + + % gzip -d -c apg-1.X.XX.tar.gz | tar xf - + % cd apg-1.X.XX + +If you are reading this file, you probably have already done this! + +2. Edit the Makefile + +3. make the software: + + For standalone: + + % make cygwin + +4. install the binaries and man pages. +There are some problems with install for CYGWIN. +Sorry... But you have to do it manualy + + % make install-cygwin + +5. You can remove the program binaries and object files from the +source code directory by typing + + % make clean + +NOTE: You can use APG without CYGWIN, you need only cygwin*.dll. +Copy APG.EXE to the directory you want and copy CYGWIN*.DLL +in the same directory. Now you can run APG.EXE in the MS-DOS Prompt +or just cliking on it. + +Adel I. Mirzazhanov +a-del@iname.com diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3b9bbb3 --- /dev/null +++ b/Makefile @@ -0,0 +1,85 @@ +# You can modify CC variable if you have compiler other than GCC +# But the code was designed and tested with GCC +CC = gcc + +# compilation flags +# You should comment the line below for AIX+native cc +FLAGS = -Wall + +# libraries +LIBS = -lcrypt + +# DO NOT EDIT THE LINE BELOW !!! +CRYPTED_PASS = APG_DONOTUSE_CRYPT +# Coment this if you do not want to use crypted passwords output +CRYPTED_PASS = APG_USE_CRYPT + +# Install dirs +INSTALL_PREFIX = /usr/local +APG_BIN_DIR = /bin +APG_MAN_DIR = /man/man1 +APGD_BIN_DIR = /sbin +APGD_MAN_DIR = /man/man8 + +# Find group ID for user root +FIND_GROUP = `grep '^root:' /etc/passwd | awk -F: '{ print $$4 }'` + +#################################################################### +# If you plan to install APG daemon you should look at lines below # +#################################################################### + +# Uncoment NOTHING for FreeBSD +# + +# Uncoment line below for LINUX +#CS_LIBS = -lnsl + +# Uncoment line below for Solaris +#CS_LIBS = -lnsl -lsocket + +# ====== YOU DO NOT NEED TO MODIFY ANYTHING BELOW THIS LINE ====== + +PROGNAME = apg +CS_PROGNAME = apgd +SOURCES = rnd.c ./cast/cast.c pronpass.c randpass.c restrict.c errors.c apg.c +HEADERS = owntypes.h pronpass.h randpass.h restrict.h errs.h rnd.h ./cast/cast.h ./cast/cast_sboxes.h +OBJECTS = rnd.o ./cast/cast.o pronpass.o randpass.o restrict.o apg.o errors.o + +all: cliserv standalone + +cygwin: standalone + +cliserv: ${SOURCES} ${HEADERS} + ${CC} ${FLAGS} ${CS_LIBS} -DCLISERV -o ${CS_PROGNAME} ${SOURCES} + +standalone: ${SOURCES} ${HEADERS} + ${CC} ${FLAGS} ${LIBS} -D${CRYPTED_PASS} -o ${PROGNAME} ${SOURCES} + +strip: + strip ${PROGNAME} + strip ${CS_PROGNAME} + +install: + if test -x ./apg; then \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_MAN_DIR}; \ +./install-sh -c -m 0755 -o root -g ${FIND_GROUP} ./apg ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./install-sh -c -m 0444 ./doc/man/apg.1 ${INSTALL_PREFIX}${APG_MAN_DIR}; \ +fi + if test -x ./apgd; then \ +./mkinstalldirs ${INSTALL_PREFIX}${APGD_BIN_DIR}; \ +./mkinstalldirs ${INSTALL_PREFIX}${APGD_MAN_DIR}; \ +./install-sh -c -m 0755 -o root -g ${FIND_GROUP} ./apgd ${INSTALL_PREFIX}${APGD_BIN_DIR}; \ +./install-sh -c -m 0444 ./doc/man/apgd.8 ${INSTALL_PREFIX}${APGD_MAN_DIR}; \ +fi + +install-cygwin: + if test -x ./apg.exe; then \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./mkinstalldirs ${INSTALL_PREFIX}${APG_MAN_DIR}; \ +./install-sh -c -m 0755 ./apg.exe ${INSTALL_PREFIX}${APG_BIN_DIR}; \ +./install-sh -c -m 0444 ./doc/man/apg.1 ${INSTALL_PREFIX}${APG_MAN_DIR}; \ +fi + +clean: + rm -f ${CS_PROGNAME} ${PROGNAME} ${OBJECTS} core* diff --git a/README b/README new file mode 100644 index 0000000..10ea634 --- /dev/null +++ b/README @@ -0,0 +1,28 @@ +APG v1.2.12 was tested and found working on: + + i386 FreeBSD 4.0-RELEASE + i386 Linux-Mandrake 6.0 + i386 Linux-Redhat 7.0 + i386 Linux-Mandrake 7.2 (reported by Andrew J. Caird ) + Intel Solaris 8 gcc-2.95.2 + SPARC Solaris 8 gcc-2.95.2 + Intel Windows 2000+CYGWIN v1.1.4 + HP-UX 10.20 HP ANSI C Compilier (reported by Alexander J Pierce ) + HP-UX 11.00 HP ANSI C Compilier (reported by Alexander J Pierce ) + HP-UX 11.00 gcc-2.95.2 (reported by Andrew J. Caird ) + IRIX 6.5.8 gcc-2.95.2 (reported by Andrew J. Caird ) + AIX 4.3.3+native cc (reported by Philip Le Riche ) + AIX 4.3.3+gcc (reported by Philip Le Riche ) + +Any compatibility reports are welcom + + * For installation instructions see INSTALL + * For usage instructions see manpages + * For copying information see COPYING + +See also APG Homepage at: http://www.adel.nursat.kz/apg/ + +ANY PATCHES OR SUGGESTIONS ARE WELCOME + +Adel I. Mirzazhanov +E-mail: a-del@iname.com diff --git a/README.CYGWIN b/README.CYGWIN new file mode 100644 index 0000000..d646fe8 --- /dev/null +++ b/README.CYGWIN @@ -0,0 +1,11 @@ +APG is now supports CYGWIN +(thanks to Graham Bloice ) + + * For installation instructions see INSTALL.CYGWIN + * For usage instructions see manpages + * For copying information see COPYING + +See also APG Homepage at: http://www.adel.nursat.kz/apg/ + +Adel I. Mirzazhanov +E-mail: a-del@iname.com \ No newline at end of file diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..8f318d8 --- /dev/null +++ b/THANKS @@ -0,0 +1,10 @@ +Graham Bloice +Rainer Wichmann +Andreas Ehliar +Chris Foote +Robert Kovacs +Peter Pentchev +Adrian Ho +Andrew J. Caird +Alexander J Pierce +Philip Le Riche \ No newline at end of file diff --git a/TODO b/TODO new file mode 100644 index 0000000..8e90992 --- /dev/null +++ b/TODO @@ -0,0 +1,20 @@ +TODO +---- + +Priority Hi: + +* Fix some code style or other errors if any. + +* Make some kind of configuration file to avoid command + line parameter typing. + +Priority Medium: + +* Include support for some other random number generation + algorithms (Blum-Blum-Shub, FIPS 186-3) + +* Make some interfase for plug-in language modules + for pronounceable password generation. + +* Make some interface ( language ) to describe + restriction rules for passwords. diff --git a/apg.c b/apg.c new file mode 100644 index 0000000..52fd4e7 --- /dev/null +++ b/apg.c @@ -0,0 +1,562 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +** Main Module of apg programm +*/ +#include +#include +#include +#include +#include +#define MAX_MODE_LENGTH 5 + +#ifndef _XOPEN_SOURCE +#define _XOPEN_SOURCE +#endif + +#include +/*#include */ +#ifdef __CYGWIN__ +#include +#undef APG_USE_CRYPT +#endif /* __CYGWIN__ */ + +#ifdef CLISERV +# include +# include +# include +# include +# define MAXSOCKADDDR 128 +#endif /* CLISERV */ + +#include "owntypes.h" +#include "pronpass.h" +#include "randpass.h" +#include "restrict.h" +#include "rnd.h" +#include "errs.h" + +#ifndef CLISERV +UINT32 get_user_seq (void); +UINT32 com_line_user_seq (char * seq); +char *crypt_passstring (const char *p); /*!!*/ +void print_help (void); +#endif /* CLISERV */ + +int main (int argc, char *argv[]); +void checkopt(char *opt); +unsigned int construct_mode(char *str_mode); + +int +main (int argc, char *argv[]) +{ + int i = 0; + int restrict_res = 0; + + char *pass_string; + char *hyph_pass_string; + time_t tme; + + + int option = 0; /* programm option */ + + int algorithm = 0; /* algorithm for generation */ + int restrictions_present = FALSE; /* restrictions flag */ + char *restrictions_file; /* dictionary file name */ + unsigned int pass_mode = 0; /* password generation mode */ + unsigned int pass_mode_present = FALSE; /* password generation mode flag */ + USHORT min_pass_length = 6; /* min password length */ + USHORT max_pass_length = 8; /* max password length */ + int number_of_pass = 6; /* number of passwords to generate */ + UINT32 user_defined_seed = 0L; /* user defined random seed */ + int user_defined_seed_present = FALSE; /* user defined random seed flag */ + char *str_mode; /* string mode pointer */ +#ifndef CLISERV + char *com_line_seq; + unsigned int delimiter_flag_present = FALSE; +#ifdef APG_USE_CRYPT + char *crypt_string; + unsigned int show_crypt_text = FALSE; /* display crypt(3)'d text flag */ +#endif /* APG_USE_CRYPT */ +#endif /* CLISERV */ +#ifdef CLISERV +#ifdef sgi /* Thanks to Andrew J. Caird */ + typedef unsigned int socklen_t; +#endif + socklen_t len; + struct sockaddr_in *cliaddr; + char delim[2]={0x0d,0x0a}; + char *out_pass; + char *peer_ip_unknown = "UNKNOWN"; + char *peer_ip; + + openlog(argv[0], LOG_PID, LOG_DAEMON); + cliaddr = (struct sockaddr_in *)calloc(1,MAXSOCKADDDR); + len = MAXSOCKADDDR; + if( getpeername(0, (struct sockaddr *)cliaddr, &len) != 0) + { + err_sys("getpeername"); + peer_ip = peer_ip_unknown; + } + else + { + peer_ip = inet_ntoa(cliaddr->sin_addr); + } + syslog (LOG_INFO, "password generation request from %s.%d\n", peer_ip, htons(cliaddr->sin_port)); +#endif /* CLISERV */ + + /* + ** Analize options + */ +#ifndef CLISERV +#ifdef APG_USE_CRYPT + while ((option = getopt (argc, argv, "SNCLRM:a:r:sdc:n:m:x:hvy")) != -1) +#else /* APG_USE_CRYPT */ + while ((option = getopt (argc, argv, "SNCLRM:a:r:sdc:n:m:x:hv")) != -1) +#endif /* APG_USE_CRYPT */ +#else /* CLISERV */ + while ((option = getopt (argc, argv, "SNCLRM:a:r:n:m:x:v")) != -1) +#endif /* CLISERV */ + { + switch (option) + { + case 'S': /* special symbols required */ + pass_mode = pass_mode | S_SS; + pass_mode_present = TRUE; + break; + case 'R': /* special symbols required */ + pass_mode = pass_mode | S_SS; + pass_mode = pass_mode | S_RS; + pass_mode_present = TRUE; + break; + case 'N': /* numbers required */ + pass_mode = pass_mode | S_NB; + pass_mode_present = TRUE; + break; + case 'C': /* capital letters required */ + pass_mode = pass_mode | S_CL; + pass_mode_present = TRUE; + break; + case 'L': /* small letters required */ + pass_mode = pass_mode | S_SL; + pass_mode_present = TRUE; + break; + case 'M': + str_mode = optarg; + if( (pass_mode = construct_mode(str_mode)) == 0xFFFF) + err_app_fatal("construct_mode","wrong parameter"); + pass_mode_present = TRUE; + break; + case 'a': /* algorithm specification */ + checkopt(optarg); + algorithm = atoi (optarg); + break; + case 'r': /* restrictions */ + restrictions_present = TRUE; + restrictions_file = optarg; + break; +#ifndef CLISERV + case 's': /* user random seed required */ + user_defined_seed = get_user_seq (); + user_defined_seed_present = TRUE; + break; + case 'c': /* user random seed given in command line */ + com_line_seq = optarg; + user_defined_seed = com_line_user_seq (com_line_seq); + user_defined_seed_present = TRUE; + break; + case 'd': /* No delinmiters option */ + delimiter_flag_present = TRUE; + break; +#ifdef APG_USE_CRYPT + case 'y': /* display crypt(3)'d text next to passwords */ /*!!*/ + show_crypt_text = TRUE; + break; +#endif /* APG_USE_CRYPT */ +#endif /* CLISERV */ + case 'n': /* number of password specification */ + checkopt(optarg); + number_of_pass = atoi (optarg); + break; + case 'm': /* min password length */ + checkopt(optarg); + min_pass_length = (USHORT) atoi (optarg); + break; + case 'x': /* max password length */ + checkopt(optarg); + max_pass_length = (USHORT) atoi (optarg); + break; +#ifndef CLISERV + case 'h': /* print help */ + print_help (); + return (0); +#endif /* CLISERV */ + case 'v': /* print version */ + printf ("APG (Automated Password Generator)"); + printf ("\nversion 1.2.11"); + printf ("\nCopyright (c) 1999, 2000, 2001 Adel I. Mirzazhanov\n"); + return (0); + default: /* print help end exit */ +#ifndef CLISERV + print_help (); +#endif /* CLISERV */ + exit (-1); + } + } + if (pass_mode_present != TRUE) + pass_mode = S_SS | S_NB | S_CL | S_SL; + if( (tme = time(NULL)) == ( (time_t)-1)) + err_sys("time"); + if (user_defined_seed_present != TRUE) + x917cast_setseed ( (UINT32)tme); + else + x917cast_setseed (user_defined_seed ^ (UINT32)tme); + if (min_pass_length > max_pass_length) + max_pass_length = min_pass_length; + /* main code section */ + + /* + ** reserv space for password and hyphenated password and report of errors + */ + if ( (pass_string = (char *)calloc (1, (size_t)(max_pass_length + 1)))==NULL || + (hyph_pass_string = (char *)calloc (1, (size_t)(max_pass_length*2)))==NULL) + err_sys_fatal("calloc"); +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text == TRUE) + if ((crypt_string = (char *)calloc (1, 255))==NULL) + err_sys_fatal("calloc"); +#endif /* APG_USE_CRYPT */ +#endif /* CLISERV */ +#ifdef CLISERV + if ( (out_pass = (char *)calloc(1, (size_t)(max_pass_length*3 + 4))) == NULL) + err_sys_fatal("calloc"); +#endif /* CLISERV */ + /* + ** generate required amount of passwords using specified algorithm + ** and check for restrictions if specified with command line parameters + */ + while (i < number_of_pass) + { + if (algorithm == 0) + { + if (gen_pron_pass(pass_string, hyph_pass_string, + min_pass_length, max_pass_length, pass_mode) == -1) + err_app_fatal("apg","wrong password length parameter"); +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text == TRUE) + bcopy ((void *)crypt_passstring (pass_string), + (void *)crypt_string, 255); +#endif /* APG_USE_CRYPT */ +#endif /* CLISERV */ + if (restrictions_present == 1) + { + restrict_res = check_pass(pass_string, restrictions_file); + switch (restrict_res) + { + case 0: +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text == TRUE) + fprintf (stdout, "%s (%s) %s", pass_string, hyph_pass_string, + crypt_string); + else +#endif /* APG_USE_CRYPT */ + fprintf (stdout, "%s (%s)", pass_string, hyph_pass_string); + if ( delimiter_flag_present == FALSE ) + fprintf (stdout, "\n"); + fflush (stdout); +#else /* CLISERV */ + snprintf(out_pass, max_pass_length*3 + 4, + "%s (%s)", pass_string, hyph_pass_string); + write (0, (void*) out_pass, strlen(out_pass)); + write (0, (void*)&delim[0],2); +#endif /* CLISERV */ + i++; + break; + case 1: + break; + case -1: + err_sys_fatal ("check_pass"); + default: + break; + } /* switch */ + } + else /* if (restrictions_present == 0) */ + { +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text == TRUE) + fprintf (stdout, "%s (%s) %s", pass_string, hyph_pass_string, + crypt_string); + else +#endif /* APG_USE_CRYPT */ + fprintf (stdout, "%s (%s)", pass_string, hyph_pass_string); + if ( delimiter_flag_present == FALSE ) + fprintf (stdout, "\n"); + fflush (stdout); +#else /* CLISERV */ + snprintf(out_pass, max_pass_length*3 + 4, + "%s (%s)", pass_string, hyph_pass_string); + write (0, (void*) out_pass, strlen(out_pass)); + write (0, (void*)&delim[0],2); +#endif /* CLISERV */ + i++; + } + } /* end of if (algorithm == 0) */ + else if (algorithm == 1) + { + if (gen_rand_pass(pass_string, min_pass_length, + max_pass_length, pass_mode) == -1) + err_app_fatal("apg","wrong password length parameter"); +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text == TRUE) + bcopy ((void *)crypt_passstring(pass_string), + (void *)crypt_string, 255); +#endif /* APG_USE_CRYPT */ +#endif /* CLISERV */ + if (restrictions_present == 1) + { + restrict_res = check_pass(pass_string, restrictions_file); + switch (restrict_res) + { + case 0: +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text==TRUE) + fprintf (stdout, "%s %s", pass_string, crypt_string); + else +#endif /* APG_USE_CRYPT */ + fprintf (stdout, "%s", pass_string); + if ( delimiter_flag_present == FALSE ) + fprintf (stdout, "\n"); + fflush (stdout); +#else /* CLISERV */ + write (0, (void*)pass_string, strlen(pass_string)); + write (0, (void*)&delim[0],2); +#endif /* CLISERV */ + i++; + break; + case 1: + break; + case -1: + err_sys_fatal ("check_pass"); + default: + break; + } /* switch */ + } + else /* if (restrictions_present == 0) */ + { +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text==TRUE) + fprintf (stdout, "%s %s", pass_string, crypt_string); + else +#endif /* APG_USE_CRYPT */ + fprintf (stdout, "%s", pass_string); + if ( delimiter_flag_present == FALSE ) + fprintf (stdout, "\n"); + fflush (stdout); +#else /* CLISERV */ + write (0, (void*)pass_string, strlen(pass_string)); + write (0, (void*)&delim[0],2); +#endif /* CLISERV */ + i++; + } + } /* end of if (algorithm == 1) */ + else + err_app_fatal ("apg","wrong algorithm type"); + + restrict_res = 0; + } /* end of while (i <= number_of_pass) */ + free((void*)pass_string); + free((void*)hyph_pass_string); +#ifndef CLISERV +#ifdef APG_USE_CRYPT + if (show_crypt_text==TRUE) + free((void*)crypt_string); +#endif /* APG_USE_CRYPT */ +#endif /* CLISERV */ +#ifdef CLISERV + free ((void *)out_pass); + free ((void *)cliaddr); + close (0); + closelog(); +#endif /* CLISERV */ + return(0); +} /* end of main */ + +#ifndef CLISERV +/* +** Routine that gets user random sequense and generates +** sutable random seed according to it +*/ +UINT32 +get_user_seq (void) +{ + char * seq; + UINT32 prom[2] = { 0L, 0L }; + UINT32 sdres = 0L; + printf ("\nPlease enter some random data (only first %d are significant)\n", sizeof(prom)); + seq = (char *)getpass("(eg. your old password):>"); + if (strlen(seq) < sizeof(prom)) + bcopy((void *)seq, (void *)&prom[0], (int)strlen(seq)); + else + bcopy((void *)seq, (void *)&prom[0], sizeof(prom)); + sdres = prom[0]^prom[1]; + return (sdres); +} + +/* +** Routine that gets user random sequense from command line and generates +** sutable random seed according to it +*/ +UINT32 +com_line_user_seq (char * seq) +{ + UINT32 prom[2] = { 0L, 0L }; + UINT32 sdres = 0L; + if (strlen(seq) < sizeof (prom)) + bcopy((void *)seq, (void *)&prom[0], (int)strlen(seq)); + else + bcopy((void *)seq, (void *)&prom[0], sizeof(prom)); + sdres = prom[0]^prom[1]; + return (sdres); +} + +void +print_help (void) +{ + printf ("\napg Automated Password Generator\n"); + printf (" Copyright (c) Adel I. Mirzazhanov\n"); + printf ("\napg [-a algorithm] [-r file] [-S] [-C] [-L] [-R]\n"); + printf (" [-N] [-M mode] [-n num_of_pass] [-m min_pass_len]\n"); + printf (" [-x max_pass_len] [-c cl_seed] [-d] [-s] [-h] [-y]\n"); + printf ("\n-S -N -C -L -R password modes\n"); + printf ("-M mode new style pasword modes\n"); + printf ("-r file apply dictionary check against file\n"); + printf ("-a algorithm choose algorithm\n"); + printf (" 1 - random password generation according to\n"); + printf (" password modes\n"); + printf (" 0 - pronounceable password generation\n"); + printf ("-n num_of_pass generate num_of_pass passwords\n"); + printf ("-m min_pass_len minimum password length\n"); + printf ("-x max_pass_len maximum password length\n"); + printf ("-s ask user for a random seed for password\n"); + printf (" generation\n"); + printf ("-c cl_seed use cl_seed as a random seed for password\n"); + printf ("-d do NOT use any delimiters between generated passwords\n"); +#ifdef APG_USE_CRYPT + printf ("-y print crypted passwords\n"); +#endif /* APG_USE_CRYPT */ + printf ("-h print this help screen\n"); + printf ("-v print version information\n"); +} + +#ifdef APG_USE_CRYPT +char * crypt_passstring (const char *p) +{ + char salt[10]; + gen_rand_pass (salt, 10, 10, S_SL|S_CL|S_NB); + return (crypt(p, salt)); +} +#endif /* APG_USE_CRYPT */ +#endif /* CLISERV */ + +void +checkopt(char *opt) +{ + int i; + + for(i=0; i < strlen(opt);i++) + if(opt[i] != '0' && opt[i] != '1' && opt[i] != '2' && opt[i] != '3' && + opt[i] != '4' && opt[i] != '5' && opt[i] != '6' && opt[i] != '7' && + opt[i] != '8' && opt[i] != '9') + err_app_fatal ("checkopt", "wrong option format"); +} + +unsigned int construct_mode(char *s_mode) +{ + unsigned int mode = 0; + int ch = 0; + int i = 0; + int str_length = 0; + + str_length = strlen(s_mode); + + if (str_length > MAX_MODE_LENGTH) + return(0xFFFF); + for (i=0; i < str_length; i++) + { + ch = (int)*s_mode; + switch(ch) + { + case 'S': + mode = mode | S_SS; + break; + case 'N': + mode = mode | S_NB; + break; + case 'C': + mode = mode | S_CL; + break; + case 'L': + mode = mode | S_SL; + break; + case 'R': + mode = mode | S_SS; + mode = mode | S_RS; + break; + case 's': + mode = mode | S_SS; + break; + case 'n': + mode = mode | S_NB; + break; + case 'c': + mode = mode | S_CL; + break; + case 'l': + mode = mode | S_SL; + break; + case 'r': + mode = mode | S_SS; + mode = mode | S_RS; + break; + default: + mode = mode | 0xFFFF; + break; + } + s_mode++; + } + return (mode); +} diff --git a/cast/cast.c b/cast/cast.c new file mode 100644 index 0000000..0159cb8 --- /dev/null +++ b/cast/cast.c @@ -0,0 +1,239 @@ +/* + * CAST-128 in C + * Written by Steve Reid + * 100% Public Domain - no warranty + * Released 1997.10.11 + */ + +#include "cast.h" +#include "cast_sboxes.h" + +/* Macros to access 8-bit bytes out of a 32-bit word */ +#define U8a(x) ( (u8) (x>>24) ) +#define U8b(x) ( (u8) ((x>>16)&255) ) +#define U8c(x) ( (u8) ((x>>8)&255) ) +#define U8d(x) ( (u8) ((x)&255) ) + +/* Circular left shift */ +#define ROL(x, n) ( ((x)<<(n)) | ((x)>>(32-(n))) ) + +/* CAST-128 uses three different round functions */ +#define F1(l, r, i) \ + t = ROL(key->xkey[i] + r, key->xkey[i+16]); \ + l ^= ((cast_sbox1[U8a(t)] ^ cast_sbox2[U8b(t)]) - \ + cast_sbox3[U8c(t)]) + cast_sbox4[U8d(t)]; +#define F2(l, r, i) \ + t = ROL(key->xkey[i] ^ r, key->xkey[i+16]); \ + l ^= ((cast_sbox1[U8a(t)] - cast_sbox2[U8b(t)]) + \ + cast_sbox3[U8c(t)]) ^ cast_sbox4[U8d(t)]; +#define F3(l, r, i) \ + t = ROL(key->xkey[i] - r, key->xkey[i+16]); \ + l ^= ((cast_sbox1[U8a(t)] + cast_sbox2[U8b(t)]) ^ \ + cast_sbox3[U8c(t)]) - cast_sbox4[U8d(t)]; + + +/***** Encryption Function *****/ + +void cast_encrypt(cast_key* key, u8* inblock, u8* outblock) +{ +u32 t, l, r; + + /* Get inblock into l,r */ + l = ((u32)inblock[0] << 24) | ((u32)inblock[1] << 16) | + ((u32)inblock[2] << 8) | (u32)inblock[3]; + r = ((u32)inblock[4] << 24) | ((u32)inblock[5] << 16) | + ((u32)inblock[6] << 8) | (u32)inblock[7]; + /* Do the work */ + F1(l, r, 0); + F2(r, l, 1); + F3(l, r, 2); + F1(r, l, 3); + F2(l, r, 4); + F3(r, l, 5); + F1(l, r, 6); + F2(r, l, 7); + F3(l, r, 8); + F1(r, l, 9); + F2(l, r, 10); + F3(r, l, 11); + /* Only do full 16 rounds if key length > 80 bits */ + if (key->rounds > 12) { + F1(l, r, 12); + F2(r, l, 13); + F3(l, r, 14); + F1(r, l, 15); + } + /* Put l,r into outblock */ + outblock[0] = U8a(r); + outblock[1] = U8b(r); + outblock[2] = U8c(r); + outblock[3] = U8d(r); + outblock[4] = U8a(l); + outblock[5] = U8b(l); + outblock[6] = U8c(l); + outblock[7] = U8d(l); + /* Wipe clean */ + t = l = r = 0; +} + + +/***** Decryption Function *****/ + +void cast_decrypt(cast_key* key, u8* inblock, u8* outblock) +{ +u32 t, l, r; + + /* Get inblock into l,r */ + r = ((u32)inblock[0] << 24) | ((u32)inblock[1] << 16) | + ((u32)inblock[2] << 8) | (u32)inblock[3]; + l = ((u32)inblock[4] << 24) | ((u32)inblock[5] << 16) | + ((u32)inblock[6] << 8) | (u32)inblock[7]; + /* Do the work */ + /* Only do full 16 rounds if key length > 80 bits */ + if (key->rounds > 12) { + F1(r, l, 15); + F3(l, r, 14); + F2(r, l, 13); + F1(l, r, 12); + } + F3(r, l, 11); + F2(l, r, 10); + F1(r, l, 9); + F3(l, r, 8); + F2(r, l, 7); + F1(l, r, 6); + F3(r, l, 5); + F2(l, r, 4); + F1(r, l, 3); + F3(l, r, 2); + F2(r, l, 1); + F1(l, r, 0); + /* Put l,r into outblock */ + outblock[0] = U8a(l); + outblock[1] = U8b(l); + outblock[2] = U8c(l); + outblock[3] = U8d(l); + outblock[4] = U8a(r); + outblock[5] = U8b(r); + outblock[6] = U8c(r); + outblock[7] = U8d(r); + /* Wipe clean */ + t = l = r = 0; +} + + +/***** Key Schedual *****/ + +void cast_setkey(cast_key* key, u8* rawkey, int keybytes) +{ +u32 t[4], z[4], x[4]; +int i; + + /* Set number of rounds to 12 or 16, depending on key length */ + key->rounds = (keybytes <= 10 ? 12 : 16); + + /* Copy key to workspace x */ + for (i = 0; i < 4; i++) { + x[i] = 0; + if ((i*4+0) < keybytes) x[i] = (u32)rawkey[i*4+0] << 24; + if ((i*4+1) < keybytes) x[i] |= (u32)rawkey[i*4+1] << 16; + if ((i*4+2) < keybytes) x[i] |= (u32)rawkey[i*4+2] << 8; + if ((i*4+3) < keybytes) x[i] |= (u32)rawkey[i*4+3]; + } + /* Generate 32 subkeys, four at a time */ + for (i = 0; i < 32; i+=4) { + switch (i & 4) { + case 0: + t[0] = z[0] = x[0] ^ cast_sbox5[U8b(x[3])] ^ + cast_sbox6[U8d(x[3])] ^ cast_sbox7[U8a(x[3])] ^ + cast_sbox8[U8c(x[3])] ^ cast_sbox7[U8a(x[2])]; + t[1] = z[1] = x[2] ^ cast_sbox5[U8a(z[0])] ^ + cast_sbox6[U8c(z[0])] ^ cast_sbox7[U8b(z[0])] ^ + cast_sbox8[U8d(z[0])] ^ cast_sbox8[U8c(x[2])]; + t[2] = z[2] = x[3] ^ cast_sbox5[U8d(z[1])] ^ + cast_sbox6[U8c(z[1])] ^ cast_sbox7[U8b(z[1])] ^ + cast_sbox8[U8a(z[1])] ^ cast_sbox5[U8b(x[2])]; + t[3] = z[3] = x[1] ^ cast_sbox5[U8c(z[2])] ^ + cast_sbox6[U8b(z[2])] ^ cast_sbox7[U8d(z[2])] ^ + cast_sbox8[U8a(z[2])] ^ cast_sbox6[U8d(x[2])]; + break; + case 4: + t[0] = x[0] = z[2] ^ cast_sbox5[U8b(z[1])] ^ + cast_sbox6[U8d(z[1])] ^ cast_sbox7[U8a(z[1])] ^ + cast_sbox8[U8c(z[1])] ^ cast_sbox7[U8a(z[0])]; + t[1] = x[1] = z[0] ^ cast_sbox5[U8a(x[0])] ^ + cast_sbox6[U8c(x[0])] ^ cast_sbox7[U8b(x[0])] ^ + cast_sbox8[U8d(x[0])] ^ cast_sbox8[U8c(z[0])]; + t[2] = x[2] = z[1] ^ cast_sbox5[U8d(x[1])] ^ + cast_sbox6[U8c(x[1])] ^ cast_sbox7[U8b(x[1])] ^ + cast_sbox8[U8a(x[1])] ^ cast_sbox5[U8b(z[0])]; + t[3] = x[3] = z[3] ^ cast_sbox5[U8c(x[2])] ^ + cast_sbox6[U8b(x[2])] ^ cast_sbox7[U8d(x[2])] ^ + cast_sbox8[U8a(x[2])] ^ cast_sbox6[U8d(z[0])]; + break; + } + switch (i & 12) { + case 0: + case 12: + key->xkey[i+0] = cast_sbox5[U8a(t[2])] ^ cast_sbox6[U8b(t[2])] ^ + cast_sbox7[U8d(t[1])] ^ cast_sbox8[U8c(t[1])]; + key->xkey[i+1] = cast_sbox5[U8c(t[2])] ^ cast_sbox6[U8d(t[2])] ^ + cast_sbox7[U8b(t[1])] ^ cast_sbox8[U8a(t[1])]; + key->xkey[i+2] = cast_sbox5[U8a(t[3])] ^ cast_sbox6[U8b(t[3])] ^ + cast_sbox7[U8d(t[0])] ^ cast_sbox8[U8c(t[0])]; + key->xkey[i+3] = cast_sbox5[U8c(t[3])] ^ cast_sbox6[U8d(t[3])] ^ + cast_sbox7[U8b(t[0])] ^ cast_sbox8[U8a(t[0])]; + break; + case 4: + case 8: + key->xkey[i+0] = cast_sbox5[U8d(t[0])] ^ cast_sbox6[U8c(t[0])] ^ + cast_sbox7[U8a(t[3])] ^ cast_sbox8[U8b(t[3])]; + key->xkey[i+1] = cast_sbox5[U8b(t[0])] ^ cast_sbox6[U8a(t[0])] ^ + cast_sbox7[U8c(t[3])] ^ cast_sbox8[U8d(t[3])]; + key->xkey[i+2] = cast_sbox5[U8d(t[1])] ^ cast_sbox6[U8c(t[1])] ^ + cast_sbox7[U8a(t[2])] ^ cast_sbox8[U8b(t[2])]; + key->xkey[i+3] = cast_sbox5[U8b(t[1])] ^ cast_sbox6[U8a(t[1])] ^ + cast_sbox7[U8c(t[2])] ^ cast_sbox8[U8d(t[2])]; + break; + } + switch (i & 12) { + case 0: + key->xkey[i+0] ^= cast_sbox5[U8c(z[0])]; + key->xkey[i+1] ^= cast_sbox6[U8c(z[1])]; + key->xkey[i+2] ^= cast_sbox7[U8b(z[2])]; + key->xkey[i+3] ^= cast_sbox8[U8a(z[3])]; + break; + case 4: + key->xkey[i+0] ^= cast_sbox5[U8a(x[2])]; + key->xkey[i+1] ^= cast_sbox6[U8b(x[3])]; + key->xkey[i+2] ^= cast_sbox7[U8d(x[0])]; + key->xkey[i+3] ^= cast_sbox8[U8d(x[1])]; + break; + case 8: + key->xkey[i+0] ^= cast_sbox5[U8b(z[2])]; + key->xkey[i+1] ^= cast_sbox6[U8a(z[3])]; + key->xkey[i+2] ^= cast_sbox7[U8c(z[0])]; + key->xkey[i+3] ^= cast_sbox8[U8c(z[1])]; + break; + case 12: + key->xkey[i+0] ^= cast_sbox5[U8d(x[0])]; + key->xkey[i+1] ^= cast_sbox6[U8d(x[1])]; + key->xkey[i+2] ^= cast_sbox7[U8a(x[2])]; + key->xkey[i+3] ^= cast_sbox8[U8b(x[3])]; + break; + } + if (i >= 16) { + key->xkey[i+0] &= 31; + key->xkey[i+1] &= 31; + key->xkey[i+2] &= 31; + key->xkey[i+3] &= 31; + } + } + /* Wipe clean */ + for (i = 0; i < 4; i++) { + t[i] = x[i] = z[i] = 0; + } +} + +/* Made in Canada */ + diff --git a/cast/cast.h b/cast/cast.h new file mode 100644 index 0000000..328f38a --- /dev/null +++ b/cast/cast.h @@ -0,0 +1,24 @@ +/* + * CAST-128 in C + * Written by Steve Reid + * 100% Public Domain - no warranty + * Released 1997.10.11 + */ + +#ifndef _CAST_H_ +#define _CAST_H_ + +typedef unsigned char u8; /* 8-bit unsigned */ +typedef unsigned long u32; /* 32-bit unsigned */ + +typedef struct { + u32 xkey[32]; /* Key, after expansion */ + int rounds; /* Number of rounds to use, 12 or 16 */ +} cast_key; + +void cast_setkey(cast_key* key, u8* rawkey, int keybytes); +void cast_encrypt(cast_key* key, u8* inblock, u8* outblock); +void cast_decrypt(cast_key* key, u8* inblock, u8* outblock); + +#endif /* ifndef _CAST_H_ */ + diff --git a/cast/cast_sboxes.h b/cast/cast_sboxes.h new file mode 100644 index 0000000..24908a3 --- /dev/null +++ b/cast/cast_sboxes.h @@ -0,0 +1,543 @@ +/* + * CAST-128 in C + * Written by Steve Reid + * 100% Public Domain - no warranty + * Released 1997.10.11 + */ + +static const u32 cast_sbox1[256] = { + 0x30FB40D4, 0x9FA0FF0B, 0x6BECCD2F, 0x3F258C7A, + 0x1E213F2F, 0x9C004DD3, 0x6003E540, 0xCF9FC949, + 0xBFD4AF27, 0x88BBBDB5, 0xE2034090, 0x98D09675, + 0x6E63A0E0, 0x15C361D2, 0xC2E7661D, 0x22D4FF8E, + 0x28683B6F, 0xC07FD059, 0xFF2379C8, 0x775F50E2, + 0x43C340D3, 0xDF2F8656, 0x887CA41A, 0xA2D2BD2D, + 0xA1C9E0D6, 0x346C4819, 0x61B76D87, 0x22540F2F, + 0x2ABE32E1, 0xAA54166B, 0x22568E3A, 0xA2D341D0, + 0x66DB40C8, 0xA784392F, 0x004DFF2F, 0x2DB9D2DE, + 0x97943FAC, 0x4A97C1D8, 0x527644B7, 0xB5F437A7, + 0xB82CBAEF, 0xD751D159, 0x6FF7F0ED, 0x5A097A1F, + 0x827B68D0, 0x90ECF52E, 0x22B0C054, 0xBC8E5935, + 0x4B6D2F7F, 0x50BB64A2, 0xD2664910, 0xBEE5812D, + 0xB7332290, 0xE93B159F, 0xB48EE411, 0x4BFF345D, + 0xFD45C240, 0xAD31973F, 0xC4F6D02E, 0x55FC8165, + 0xD5B1CAAD, 0xA1AC2DAE, 0xA2D4B76D, 0xC19B0C50, + 0x882240F2, 0x0C6E4F38, 0xA4E4BFD7, 0x4F5BA272, + 0x564C1D2F, 0xC59C5319, 0xB949E354, 0xB04669FE, + 0xB1B6AB8A, 0xC71358DD, 0x6385C545, 0x110F935D, + 0x57538AD5, 0x6A390493, 0xE63D37E0, 0x2A54F6B3, + 0x3A787D5F, 0x6276A0B5, 0x19A6FCDF, 0x7A42206A, + 0x29F9D4D5, 0xF61B1891, 0xBB72275E, 0xAA508167, + 0x38901091, 0xC6B505EB, 0x84C7CB8C, 0x2AD75A0F, + 0x874A1427, 0xA2D1936B, 0x2AD286AF, 0xAA56D291, + 0xD7894360, 0x425C750D, 0x93B39E26, 0x187184C9, + 0x6C00B32D, 0x73E2BB14, 0xA0BEBC3C, 0x54623779, + 0x64459EAB, 0x3F328B82, 0x7718CF82, 0x59A2CEA6, + 0x04EE002E, 0x89FE78E6, 0x3FAB0950, 0x325FF6C2, + 0x81383F05, 0x6963C5C8, 0x76CB5AD6, 0xD49974C9, + 0xCA180DCF, 0x380782D5, 0xC7FA5CF6, 0x8AC31511, + 0x35E79E13, 0x47DA91D0, 0xF40F9086, 0xA7E2419E, + 0x31366241, 0x051EF495, 0xAA573B04, 0x4A805D8D, + 0x548300D0, 0x00322A3C, 0xBF64CDDF, 0xBA57A68E, + 0x75C6372B, 0x50AFD341, 0xA7C13275, 0x915A0BF5, + 0x6B54BFAB, 0x2B0B1426, 0xAB4CC9D7, 0x449CCD82, + 0xF7FBF265, 0xAB85C5F3, 0x1B55DB94, 0xAAD4E324, + 0xCFA4BD3F, 0x2DEAA3E2, 0x9E204D02, 0xC8BD25AC, + 0xEADF55B3, 0xD5BD9E98, 0xE31231B2, 0x2AD5AD6C, + 0x954329DE, 0xADBE4528, 0xD8710F69, 0xAA51C90F, + 0xAA786BF6, 0x22513F1E, 0xAA51A79B, 0x2AD344CC, + 0x7B5A41F0, 0xD37CFBAD, 0x1B069505, 0x41ECE491, + 0xB4C332E6, 0x032268D4, 0xC9600ACC, 0xCE387E6D, + 0xBF6BB16C, 0x6A70FB78, 0x0D03D9C9, 0xD4DF39DE, + 0xE01063DA, 0x4736F464, 0x5AD328D8, 0xB347CC96, + 0x75BB0FC3, 0x98511BFB, 0x4FFBCC35, 0xB58BCF6A, + 0xE11F0ABC, 0xBFC5FE4A, 0xA70AEC10, 0xAC39570A, + 0x3F04442F, 0x6188B153, 0xE0397A2E, 0x5727CB79, + 0x9CEB418F, 0x1CACD68D, 0x2AD37C96, 0x0175CB9D, + 0xC69DFF09, 0xC75B65F0, 0xD9DB40D8, 0xEC0E7779, + 0x4744EAD4, 0xB11C3274, 0xDD24CB9E, 0x7E1C54BD, + 0xF01144F9, 0xD2240EB1, 0x9675B3FD, 0xA3AC3755, + 0xD47C27AF, 0x51C85F4D, 0x56907596, 0xA5BB15E6, + 0x580304F0, 0xCA042CF1, 0x011A37EA, 0x8DBFAADB, + 0x35BA3E4A, 0x3526FFA0, 0xC37B4D09, 0xBC306ED9, + 0x98A52666, 0x5648F725, 0xFF5E569D, 0x0CED63D0, + 0x7C63B2CF, 0x700B45E1, 0xD5EA50F1, 0x85A92872, + 0xAF1FBDA7, 0xD4234870, 0xA7870BF3, 0x2D3B4D79, + 0x42E04198, 0x0CD0EDE7, 0x26470DB8, 0xF881814C, + 0x474D6AD7, 0x7C0C5E5C, 0xD1231959, 0x381B7298, + 0xF5D2F4DB, 0xAB838653, 0x6E2F1E23, 0x83719C9E, + 0xBD91E046, 0x9A56456E, 0xDC39200C, 0x20C8C571, + 0x962BDA1C, 0xE1E696FF, 0xB141AB08, 0x7CCA89B9, + 0x1A69E783, 0x02CC4843, 0xA2F7C579, 0x429EF47D, + 0x427B169C, 0x5AC9F049, 0xDD8F0F00, 0x5C8165BF +}; + +static const u32 cast_sbox2[256] = { + 0x1F201094, 0xEF0BA75B, 0x69E3CF7E, 0x393F4380, + 0xFE61CF7A, 0xEEC5207A, 0x55889C94, 0x72FC0651, + 0xADA7EF79, 0x4E1D7235, 0xD55A63CE, 0xDE0436BA, + 0x99C430EF, 0x5F0C0794, 0x18DCDB7D, 0xA1D6EFF3, + 0xA0B52F7B, 0x59E83605, 0xEE15B094, 0xE9FFD909, + 0xDC440086, 0xEF944459, 0xBA83CCB3, 0xE0C3CDFB, + 0xD1DA4181, 0x3B092AB1, 0xF997F1C1, 0xA5E6CF7B, + 0x01420DDB, 0xE4E7EF5B, 0x25A1FF41, 0xE180F806, + 0x1FC41080, 0x179BEE7A, 0xD37AC6A9, 0xFE5830A4, + 0x98DE8B7F, 0x77E83F4E, 0x79929269, 0x24FA9F7B, + 0xE113C85B, 0xACC40083, 0xD7503525, 0xF7EA615F, + 0x62143154, 0x0D554B63, 0x5D681121, 0xC866C359, + 0x3D63CF73, 0xCEE234C0, 0xD4D87E87, 0x5C672B21, + 0x071F6181, 0x39F7627F, 0x361E3084, 0xE4EB573B, + 0x602F64A4, 0xD63ACD9C, 0x1BBC4635, 0x9E81032D, + 0x2701F50C, 0x99847AB4, 0xA0E3DF79, 0xBA6CF38C, + 0x10843094, 0x2537A95E, 0xF46F6FFE, 0xA1FF3B1F, + 0x208CFB6A, 0x8F458C74, 0xD9E0A227, 0x4EC73A34, + 0xFC884F69, 0x3E4DE8DF, 0xEF0E0088, 0x3559648D, + 0x8A45388C, 0x1D804366, 0x721D9BFD, 0xA58684BB, + 0xE8256333, 0x844E8212, 0x128D8098, 0xFED33FB4, + 0xCE280AE1, 0x27E19BA5, 0xD5A6C252, 0xE49754BD, + 0xC5D655DD, 0xEB667064, 0x77840B4D, 0xA1B6A801, + 0x84DB26A9, 0xE0B56714, 0x21F043B7, 0xE5D05860, + 0x54F03084, 0x066FF472, 0xA31AA153, 0xDADC4755, + 0xB5625DBF, 0x68561BE6, 0x83CA6B94, 0x2D6ED23B, + 0xECCF01DB, 0xA6D3D0BA, 0xB6803D5C, 0xAF77A709, + 0x33B4A34C, 0x397BC8D6, 0x5EE22B95, 0x5F0E5304, + 0x81ED6F61, 0x20E74364, 0xB45E1378, 0xDE18639B, + 0x881CA122, 0xB96726D1, 0x8049A7E8, 0x22B7DA7B, + 0x5E552D25, 0x5272D237, 0x79D2951C, 0xC60D894C, + 0x488CB402, 0x1BA4FE5B, 0xA4B09F6B, 0x1CA815CF, + 0xA20C3005, 0x8871DF63, 0xB9DE2FCB, 0x0CC6C9E9, + 0x0BEEFF53, 0xE3214517, 0xB4542835, 0x9F63293C, + 0xEE41E729, 0x6E1D2D7C, 0x50045286, 0x1E6685F3, + 0xF33401C6, 0x30A22C95, 0x31A70850, 0x60930F13, + 0x73F98417, 0xA1269859, 0xEC645C44, 0x52C877A9, + 0xCDFF33A6, 0xA02B1741, 0x7CBAD9A2, 0x2180036F, + 0x50D99C08, 0xCB3F4861, 0xC26BD765, 0x64A3F6AB, + 0x80342676, 0x25A75E7B, 0xE4E6D1FC, 0x20C710E6, + 0xCDF0B680, 0x17844D3B, 0x31EEF84D, 0x7E0824E4, + 0x2CCB49EB, 0x846A3BAE, 0x8FF77888, 0xEE5D60F6, + 0x7AF75673, 0x2FDD5CDB, 0xA11631C1, 0x30F66F43, + 0xB3FAEC54, 0x157FD7FA, 0xEF8579CC, 0xD152DE58, + 0xDB2FFD5E, 0x8F32CE19, 0x306AF97A, 0x02F03EF8, + 0x99319AD5, 0xC242FA0F, 0xA7E3EBB0, 0xC68E4906, + 0xB8DA230C, 0x80823028, 0xDCDEF3C8, 0xD35FB171, + 0x088A1BC8, 0xBEC0C560, 0x61A3C9E8, 0xBCA8F54D, + 0xC72FEFFA, 0x22822E99, 0x82C570B4, 0xD8D94E89, + 0x8B1C34BC, 0x301E16E6, 0x273BE979, 0xB0FFEAA6, + 0x61D9B8C6, 0x00B24869, 0xB7FFCE3F, 0x08DC283B, + 0x43DAF65A, 0xF7E19798, 0x7619B72F, 0x8F1C9BA4, + 0xDC8637A0, 0x16A7D3B1, 0x9FC393B7, 0xA7136EEB, + 0xC6BCC63E, 0x1A513742, 0xEF6828BC, 0x520365D6, + 0x2D6A77AB, 0x3527ED4B, 0x821FD216, 0x095C6E2E, + 0xDB92F2FB, 0x5EEA29CB, 0x145892F5, 0x91584F7F, + 0x5483697B, 0x2667A8CC, 0x85196048, 0x8C4BACEA, + 0x833860D4, 0x0D23E0F9, 0x6C387E8A, 0x0AE6D249, + 0xB284600C, 0xD835731D, 0xDCB1C647, 0xAC4C56EA, + 0x3EBD81B3, 0x230EABB0, 0x6438BC87, 0xF0B5B1FA, + 0x8F5EA2B3, 0xFC184642, 0x0A036B7A, 0x4FB089BD, + 0x649DA589, 0xA345415E, 0x5C038323, 0x3E5D3BB9, + 0x43D79572, 0x7E6DD07C, 0x06DFDF1E, 0x6C6CC4EF, + 0x7160A539, 0x73BFBE70, 0x83877605, 0x4523ECF1 +}; + +static const u32 cast_sbox3[256] = { + 0x8DEFC240, 0x25FA5D9F, 0xEB903DBF, 0xE810C907, + 0x47607FFF, 0x369FE44B, 0x8C1FC644, 0xAECECA90, + 0xBEB1F9BF, 0xEEFBCAEA, 0xE8CF1950, 0x51DF07AE, + 0x920E8806, 0xF0AD0548, 0xE13C8D83, 0x927010D5, + 0x11107D9F, 0x07647DB9, 0xB2E3E4D4, 0x3D4F285E, + 0xB9AFA820, 0xFADE82E0, 0xA067268B, 0x8272792E, + 0x553FB2C0, 0x489AE22B, 0xD4EF9794, 0x125E3FBC, + 0x21FFFCEE, 0x825B1BFD, 0x9255C5ED, 0x1257A240, + 0x4E1A8302, 0xBAE07FFF, 0x528246E7, 0x8E57140E, + 0x3373F7BF, 0x8C9F8188, 0xA6FC4EE8, 0xC982B5A5, + 0xA8C01DB7, 0x579FC264, 0x67094F31, 0xF2BD3F5F, + 0x40FFF7C1, 0x1FB78DFC, 0x8E6BD2C1, 0x437BE59B, + 0x99B03DBF, 0xB5DBC64B, 0x638DC0E6, 0x55819D99, + 0xA197C81C, 0x4A012D6E, 0xC5884A28, 0xCCC36F71, + 0xB843C213, 0x6C0743F1, 0x8309893C, 0x0FEDDD5F, + 0x2F7FE850, 0xD7C07F7E, 0x02507FBF, 0x5AFB9A04, + 0xA747D2D0, 0x1651192E, 0xAF70BF3E, 0x58C31380, + 0x5F98302E, 0x727CC3C4, 0x0A0FB402, 0x0F7FEF82, + 0x8C96FDAD, 0x5D2C2AAE, 0x8EE99A49, 0x50DA88B8, + 0x8427F4A0, 0x1EAC5790, 0x796FB449, 0x8252DC15, + 0xEFBD7D9B, 0xA672597D, 0xADA840D8, 0x45F54504, + 0xFA5D7403, 0xE83EC305, 0x4F91751A, 0x925669C2, + 0x23EFE941, 0xA903F12E, 0x60270DF2, 0x0276E4B6, + 0x94FD6574, 0x927985B2, 0x8276DBCB, 0x02778176, + 0xF8AF918D, 0x4E48F79E, 0x8F616DDF, 0xE29D840E, + 0x842F7D83, 0x340CE5C8, 0x96BBB682, 0x93B4B148, + 0xEF303CAB, 0x984FAF28, 0x779FAF9B, 0x92DC560D, + 0x224D1E20, 0x8437AA88, 0x7D29DC96, 0x2756D3DC, + 0x8B907CEE, 0xB51FD240, 0xE7C07CE3, 0xE566B4A1, + 0xC3E9615E, 0x3CF8209D, 0x6094D1E3, 0xCD9CA341, + 0x5C76460E, 0x00EA983B, 0xD4D67881, 0xFD47572C, + 0xF76CEDD9, 0xBDA8229C, 0x127DADAA, 0x438A074E, + 0x1F97C090, 0x081BDB8A, 0x93A07EBE, 0xB938CA15, + 0x97B03CFF, 0x3DC2C0F8, 0x8D1AB2EC, 0x64380E51, + 0x68CC7BFB, 0xD90F2788, 0x12490181, 0x5DE5FFD4, + 0xDD7EF86A, 0x76A2E214, 0xB9A40368, 0x925D958F, + 0x4B39FFFA, 0xBA39AEE9, 0xA4FFD30B, 0xFAF7933B, + 0x6D498623, 0x193CBCFA, 0x27627545, 0x825CF47A, + 0x61BD8BA0, 0xD11E42D1, 0xCEAD04F4, 0x127EA392, + 0x10428DB7, 0x8272A972, 0x9270C4A8, 0x127DE50B, + 0x285BA1C8, 0x3C62F44F, 0x35C0EAA5, 0xE805D231, + 0x428929FB, 0xB4FCDF82, 0x4FB66A53, 0x0E7DC15B, + 0x1F081FAB, 0x108618AE, 0xFCFD086D, 0xF9FF2889, + 0x694BCC11, 0x236A5CAE, 0x12DECA4D, 0x2C3F8CC5, + 0xD2D02DFE, 0xF8EF5896, 0xE4CF52DA, 0x95155B67, + 0x494A488C, 0xB9B6A80C, 0x5C8F82BC, 0x89D36B45, + 0x3A609437, 0xEC00C9A9, 0x44715253, 0x0A874B49, + 0xD773BC40, 0x7C34671C, 0x02717EF6, 0x4FEB5536, + 0xA2D02FFF, 0xD2BF60C4, 0xD43F03C0, 0x50B4EF6D, + 0x07478CD1, 0x006E1888, 0xA2E53F55, 0xB9E6D4BC, + 0xA2048016, 0x97573833, 0xD7207D67, 0xDE0F8F3D, + 0x72F87B33, 0xABCC4F33, 0x7688C55D, 0x7B00A6B0, + 0x947B0001, 0x570075D2, 0xF9BB88F8, 0x8942019E, + 0x4264A5FF, 0x856302E0, 0x72DBD92B, 0xEE971B69, + 0x6EA22FDE, 0x5F08AE2B, 0xAF7A616D, 0xE5C98767, + 0xCF1FEBD2, 0x61EFC8C2, 0xF1AC2571, 0xCC8239C2, + 0x67214CB8, 0xB1E583D1, 0xB7DC3E62, 0x7F10BDCE, + 0xF90A5C38, 0x0FF0443D, 0x606E6DC6, 0x60543A49, + 0x5727C148, 0x2BE98A1D, 0x8AB41738, 0x20E1BE24, + 0xAF96DA0F, 0x68458425, 0x99833BE5, 0x600D457D, + 0x282F9350, 0x8334B362, 0xD91D1120, 0x2B6D8DA0, + 0x642B1E31, 0x9C305A00, 0x52BCE688, 0x1B03588A, + 0xF7BAEFD5, 0x4142ED9C, 0xA4315C11, 0x83323EC5, + 0xDFEF4636, 0xA133C501, 0xE9D3531C, 0xEE353783 +}; + +static const u32 cast_sbox4[256] = { + 0x9DB30420, 0x1FB6E9DE, 0xA7BE7BEF, 0xD273A298, + 0x4A4F7BDB, 0x64AD8C57, 0x85510443, 0xFA020ED1, + 0x7E287AFF, 0xE60FB663, 0x095F35A1, 0x79EBF120, + 0xFD059D43, 0x6497B7B1, 0xF3641F63, 0x241E4ADF, + 0x28147F5F, 0x4FA2B8CD, 0xC9430040, 0x0CC32220, + 0xFDD30B30, 0xC0A5374F, 0x1D2D00D9, 0x24147B15, + 0xEE4D111A, 0x0FCA5167, 0x71FF904C, 0x2D195FFE, + 0x1A05645F, 0x0C13FEFE, 0x081B08CA, 0x05170121, + 0x80530100, 0xE83E5EFE, 0xAC9AF4F8, 0x7FE72701, + 0xD2B8EE5F, 0x06DF4261, 0xBB9E9B8A, 0x7293EA25, + 0xCE84FFDF, 0xF5718801, 0x3DD64B04, 0xA26F263B, + 0x7ED48400, 0x547EEBE6, 0x446D4CA0, 0x6CF3D6F5, + 0x2649ABDF, 0xAEA0C7F5, 0x36338CC1, 0x503F7E93, + 0xD3772061, 0x11B638E1, 0x72500E03, 0xF80EB2BB, + 0xABE0502E, 0xEC8D77DE, 0x57971E81, 0xE14F6746, + 0xC9335400, 0x6920318F, 0x081DBB99, 0xFFC304A5, + 0x4D351805, 0x7F3D5CE3, 0xA6C866C6, 0x5D5BCCA9, + 0xDAEC6FEA, 0x9F926F91, 0x9F46222F, 0x3991467D, + 0xA5BF6D8E, 0x1143C44F, 0x43958302, 0xD0214EEB, + 0x022083B8, 0x3FB6180C, 0x18F8931E, 0x281658E6, + 0x26486E3E, 0x8BD78A70, 0x7477E4C1, 0xB506E07C, + 0xF32D0A25, 0x79098B02, 0xE4EABB81, 0x28123B23, + 0x69DEAD38, 0x1574CA16, 0xDF871B62, 0x211C40B7, + 0xA51A9EF9, 0x0014377B, 0x041E8AC8, 0x09114003, + 0xBD59E4D2, 0xE3D156D5, 0x4FE876D5, 0x2F91A340, + 0x557BE8DE, 0x00EAE4A7, 0x0CE5C2EC, 0x4DB4BBA6, + 0xE756BDFF, 0xDD3369AC, 0xEC17B035, 0x06572327, + 0x99AFC8B0, 0x56C8C391, 0x6B65811C, 0x5E146119, + 0x6E85CB75, 0xBE07C002, 0xC2325577, 0x893FF4EC, + 0x5BBFC92D, 0xD0EC3B25, 0xB7801AB7, 0x8D6D3B24, + 0x20C763EF, 0xC366A5FC, 0x9C382880, 0x0ACE3205, + 0xAAC9548A, 0xECA1D7C7, 0x041AFA32, 0x1D16625A, + 0x6701902C, 0x9B757A54, 0x31D477F7, 0x9126B031, + 0x36CC6FDB, 0xC70B8B46, 0xD9E66A48, 0x56E55A79, + 0x026A4CEB, 0x52437EFF, 0x2F8F76B4, 0x0DF980A5, + 0x8674CDE3, 0xEDDA04EB, 0x17A9BE04, 0x2C18F4DF, + 0xB7747F9D, 0xAB2AF7B4, 0xEFC34D20, 0x2E096B7C, + 0x1741A254, 0xE5B6A035, 0x213D42F6, 0x2C1C7C26, + 0x61C2F50F, 0x6552DAF9, 0xD2C231F8, 0x25130F69, + 0xD8167FA2, 0x0418F2C8, 0x001A96A6, 0x0D1526AB, + 0x63315C21, 0x5E0A72EC, 0x49BAFEFD, 0x187908D9, + 0x8D0DBD86, 0x311170A7, 0x3E9B640C, 0xCC3E10D7, + 0xD5CAD3B6, 0x0CAEC388, 0xF73001E1, 0x6C728AFF, + 0x71EAE2A1, 0x1F9AF36E, 0xCFCBD12F, 0xC1DE8417, + 0xAC07BE6B, 0xCB44A1D8, 0x8B9B0F56, 0x013988C3, + 0xB1C52FCA, 0xB4BE31CD, 0xD8782806, 0x12A3A4E2, + 0x6F7DE532, 0x58FD7EB6, 0xD01EE900, 0x24ADFFC2, + 0xF4990FC5, 0x9711AAC5, 0x001D7B95, 0x82E5E7D2, + 0x109873F6, 0x00613096, 0xC32D9521, 0xADA121FF, + 0x29908415, 0x7FBB977F, 0xAF9EB3DB, 0x29C9ED2A, + 0x5CE2A465, 0xA730F32C, 0xD0AA3FE8, 0x8A5CC091, + 0xD49E2CE7, 0x0CE454A9, 0xD60ACD86, 0x015F1919, + 0x77079103, 0xDEA03AF6, 0x78A8565E, 0xDEE356DF, + 0x21F05CBE, 0x8B75E387, 0xB3C50651, 0xB8A5C3EF, + 0xD8EEB6D2, 0xE523BE77, 0xC2154529, 0x2F69EFDF, + 0xAFE67AFB, 0xF470C4B2, 0xF3E0EB5B, 0xD6CC9876, + 0x39E4460C, 0x1FDA8538, 0x1987832F, 0xCA007367, + 0xA99144F8, 0x296B299E, 0x492FC295, 0x9266BEAB, + 0xB5676E69, 0x9BD3DDDA, 0xDF7E052F, 0xDB25701C, + 0x1B5E51EE, 0xF65324E6, 0x6AFCE36C, 0x0316CC04, + 0x8644213E, 0xB7DC59D0, 0x7965291F, 0xCCD6FD43, + 0x41823979, 0x932BCDF6, 0xB657C34D, 0x4EDFD282, + 0x7AE5290C, 0x3CB9536B, 0x851E20FE, 0x9833557E, + 0x13ECF0B0, 0xD3FFB372, 0x3F85C5C1, 0x0AEF7ED2 +}; + +static const u32 cast_sbox5[256] = { + 0x7EC90C04, 0x2C6E74B9, 0x9B0E66DF, 0xA6337911, + 0xB86A7FFF, 0x1DD358F5, 0x44DD9D44, 0x1731167F, + 0x08FBF1FA, 0xE7F511CC, 0xD2051B00, 0x735ABA00, + 0x2AB722D8, 0x386381CB, 0xACF6243A, 0x69BEFD7A, + 0xE6A2E77F, 0xF0C720CD, 0xC4494816, 0xCCF5C180, + 0x38851640, 0x15B0A848, 0xE68B18CB, 0x4CAADEFF, + 0x5F480A01, 0x0412B2AA, 0x259814FC, 0x41D0EFE2, + 0x4E40B48D, 0x248EB6FB, 0x8DBA1CFE, 0x41A99B02, + 0x1A550A04, 0xBA8F65CB, 0x7251F4E7, 0x95A51725, + 0xC106ECD7, 0x97A5980A, 0xC539B9AA, 0x4D79FE6A, + 0xF2F3F763, 0x68AF8040, 0xED0C9E56, 0x11B4958B, + 0xE1EB5A88, 0x8709E6B0, 0xD7E07156, 0x4E29FEA7, + 0x6366E52D, 0x02D1C000, 0xC4AC8E05, 0x9377F571, + 0x0C05372A, 0x578535F2, 0x2261BE02, 0xD642A0C9, + 0xDF13A280, 0x74B55BD2, 0x682199C0, 0xD421E5EC, + 0x53FB3CE8, 0xC8ADEDB3, 0x28A87FC9, 0x3D959981, + 0x5C1FF900, 0xFE38D399, 0x0C4EFF0B, 0x062407EA, + 0xAA2F4FB1, 0x4FB96976, 0x90C79505, 0xB0A8A774, + 0xEF55A1FF, 0xE59CA2C2, 0xA6B62D27, 0xE66A4263, + 0xDF65001F, 0x0EC50966, 0xDFDD55BC, 0x29DE0655, + 0x911E739A, 0x17AF8975, 0x32C7911C, 0x89F89468, + 0x0D01E980, 0x524755F4, 0x03B63CC9, 0x0CC844B2, + 0xBCF3F0AA, 0x87AC36E9, 0xE53A7426, 0x01B3D82B, + 0x1A9E7449, 0x64EE2D7E, 0xCDDBB1DA, 0x01C94910, + 0xB868BF80, 0x0D26F3FD, 0x9342EDE7, 0x04A5C284, + 0x636737B6, 0x50F5B616, 0xF24766E3, 0x8ECA36C1, + 0x136E05DB, 0xFEF18391, 0xFB887A37, 0xD6E7F7D4, + 0xC7FB7DC9, 0x3063FCDF, 0xB6F589DE, 0xEC2941DA, + 0x26E46695, 0xB7566419, 0xF654EFC5, 0xD08D58B7, + 0x48925401, 0xC1BACB7F, 0xE5FF550F, 0xB6083049, + 0x5BB5D0E8, 0x87D72E5A, 0xAB6A6EE1, 0x223A66CE, + 0xC62BF3CD, 0x9E0885F9, 0x68CB3E47, 0x086C010F, + 0xA21DE820, 0xD18B69DE, 0xF3F65777, 0xFA02C3F6, + 0x407EDAC3, 0xCBB3D550, 0x1793084D, 0xB0D70EBA, + 0x0AB378D5, 0xD951FB0C, 0xDED7DA56, 0x4124BBE4, + 0x94CA0B56, 0x0F5755D1, 0xE0E1E56E, 0x6184B5BE, + 0x580A249F, 0x94F74BC0, 0xE327888E, 0x9F7B5561, + 0xC3DC0280, 0x05687715, 0x646C6BD7, 0x44904DB3, + 0x66B4F0A3, 0xC0F1648A, 0x697ED5AF, 0x49E92FF6, + 0x309E374F, 0x2CB6356A, 0x85808573, 0x4991F840, + 0x76F0AE02, 0x083BE84D, 0x28421C9A, 0x44489406, + 0x736E4CB8, 0xC1092910, 0x8BC95FC6, 0x7D869CF4, + 0x134F616F, 0x2E77118D, 0xB31B2BE1, 0xAA90B472, + 0x3CA5D717, 0x7D161BBA, 0x9CAD9010, 0xAF462BA2, + 0x9FE459D2, 0x45D34559, 0xD9F2DA13, 0xDBC65487, + 0xF3E4F94E, 0x176D486F, 0x097C13EA, 0x631DA5C7, + 0x445F7382, 0x175683F4, 0xCDC66A97, 0x70BE0288, + 0xB3CDCF72, 0x6E5DD2F3, 0x20936079, 0x459B80A5, + 0xBE60E2DB, 0xA9C23101, 0xEBA5315C, 0x224E42F2, + 0x1C5C1572, 0xF6721B2C, 0x1AD2FFF3, 0x8C25404E, + 0x324ED72F, 0x4067B7FD, 0x0523138E, 0x5CA3BC78, + 0xDC0FD66E, 0x75922283, 0x784D6B17, 0x58EBB16E, + 0x44094F85, 0x3F481D87, 0xFCFEAE7B, 0x77B5FF76, + 0x8C2302BF, 0xAAF47556, 0x5F46B02A, 0x2B092801, + 0x3D38F5F7, 0x0CA81F36, 0x52AF4A8A, 0x66D5E7C0, + 0xDF3B0874, 0x95055110, 0x1B5AD7A8, 0xF61ED5AD, + 0x6CF6E479, 0x20758184, 0xD0CEFA65, 0x88F7BE58, + 0x4A046826, 0x0FF6F8F3, 0xA09C7F70, 0x5346ABA0, + 0x5CE96C28, 0xE176EDA3, 0x6BAC307F, 0x376829D2, + 0x85360FA9, 0x17E3FE2A, 0x24B79767, 0xF5A96B20, + 0xD6CD2595, 0x68FF1EBF, 0x7555442C, 0xF19F06BE, + 0xF9E0659A, 0xEEB9491D, 0x34010718, 0xBB30CAB8, + 0xE822FE15, 0x88570983, 0x750E6249, 0xDA627E55, + 0x5E76FFA8, 0xB1534546, 0x6D47DE08, 0xEFE9E7D4 +}; + +static const u32 cast_sbox6[256] = { + 0xF6FA8F9D, 0x2CAC6CE1, 0x4CA34867, 0xE2337F7C, + 0x95DB08E7, 0x016843B4, 0xECED5CBC, 0x325553AC, + 0xBF9F0960, 0xDFA1E2ED, 0x83F0579D, 0x63ED86B9, + 0x1AB6A6B8, 0xDE5EBE39, 0xF38FF732, 0x8989B138, + 0x33F14961, 0xC01937BD, 0xF506C6DA, 0xE4625E7E, + 0xA308EA99, 0x4E23E33C, 0x79CBD7CC, 0x48A14367, + 0xA3149619, 0xFEC94BD5, 0xA114174A, 0xEAA01866, + 0xA084DB2D, 0x09A8486F, 0xA888614A, 0x2900AF98, + 0x01665991, 0xE1992863, 0xC8F30C60, 0x2E78EF3C, + 0xD0D51932, 0xCF0FEC14, 0xF7CA07D2, 0xD0A82072, + 0xFD41197E, 0x9305A6B0, 0xE86BE3DA, 0x74BED3CD, + 0x372DA53C, 0x4C7F4448, 0xDAB5D440, 0x6DBA0EC3, + 0x083919A7, 0x9FBAEED9, 0x49DBCFB0, 0x4E670C53, + 0x5C3D9C01, 0x64BDB941, 0x2C0E636A, 0xBA7DD9CD, + 0xEA6F7388, 0xE70BC762, 0x35F29ADB, 0x5C4CDD8D, + 0xF0D48D8C, 0xB88153E2, 0x08A19866, 0x1AE2EAC8, + 0x284CAF89, 0xAA928223, 0x9334BE53, 0x3B3A21BF, + 0x16434BE3, 0x9AEA3906, 0xEFE8C36E, 0xF890CDD9, + 0x80226DAE, 0xC340A4A3, 0xDF7E9C09, 0xA694A807, + 0x5B7C5ECC, 0x221DB3A6, 0x9A69A02F, 0x68818A54, + 0xCEB2296F, 0x53C0843A, 0xFE893655, 0x25BFE68A, + 0xB4628ABC, 0xCF222EBF, 0x25AC6F48, 0xA9A99387, + 0x53BDDB65, 0xE76FFBE7, 0xE967FD78, 0x0BA93563, + 0x8E342BC1, 0xE8A11BE9, 0x4980740D, 0xC8087DFC, + 0x8DE4BF99, 0xA11101A0, 0x7FD37975, 0xDA5A26C0, + 0xE81F994F, 0x9528CD89, 0xFD339FED, 0xB87834BF, + 0x5F04456D, 0x22258698, 0xC9C4C83B, 0x2DC156BE, + 0x4F628DAA, 0x57F55EC5, 0xE2220ABE, 0xD2916EBF, + 0x4EC75B95, 0x24F2C3C0, 0x42D15D99, 0xCD0D7FA0, + 0x7B6E27FF, 0xA8DC8AF0, 0x7345C106, 0xF41E232F, + 0x35162386, 0xE6EA8926, 0x3333B094, 0x157EC6F2, + 0x372B74AF, 0x692573E4, 0xE9A9D848, 0xF3160289, + 0x3A62EF1D, 0xA787E238, 0xF3A5F676, 0x74364853, + 0x20951063, 0x4576698D, 0xB6FAD407, 0x592AF950, + 0x36F73523, 0x4CFB6E87, 0x7DA4CEC0, 0x6C152DAA, + 0xCB0396A8, 0xC50DFE5D, 0xFCD707AB, 0x0921C42F, + 0x89DFF0BB, 0x5FE2BE78, 0x448F4F33, 0x754613C9, + 0x2B05D08D, 0x48B9D585, 0xDC049441, 0xC8098F9B, + 0x7DEDE786, 0xC39A3373, 0x42410005, 0x6A091751, + 0x0EF3C8A6, 0x890072D6, 0x28207682, 0xA9A9F7BE, + 0xBF32679D, 0xD45B5B75, 0xB353FD00, 0xCBB0E358, + 0x830F220A, 0x1F8FB214, 0xD372CF08, 0xCC3C4A13, + 0x8CF63166, 0x061C87BE, 0x88C98F88, 0x6062E397, + 0x47CF8E7A, 0xB6C85283, 0x3CC2ACFB, 0x3FC06976, + 0x4E8F0252, 0x64D8314D, 0xDA3870E3, 0x1E665459, + 0xC10908F0, 0x513021A5, 0x6C5B68B7, 0x822F8AA0, + 0x3007CD3E, 0x74719EEF, 0xDC872681, 0x073340D4, + 0x7E432FD9, 0x0C5EC241, 0x8809286C, 0xF592D891, + 0x08A930F6, 0x957EF305, 0xB7FBFFBD, 0xC266E96F, + 0x6FE4AC98, 0xB173ECC0, 0xBC60B42A, 0x953498DA, + 0xFBA1AE12, 0x2D4BD736, 0x0F25FAAB, 0xA4F3FCEB, + 0xE2969123, 0x257F0C3D, 0x9348AF49, 0x361400BC, + 0xE8816F4A, 0x3814F200, 0xA3F94043, 0x9C7A54C2, + 0xBC704F57, 0xDA41E7F9, 0xC25AD33A, 0x54F4A084, + 0xB17F5505, 0x59357CBE, 0xEDBD15C8, 0x7F97C5AB, + 0xBA5AC7B5, 0xB6F6DEAF, 0x3A479C3A, 0x5302DA25, + 0x653D7E6A, 0x54268D49, 0x51A477EA, 0x5017D55B, + 0xD7D25D88, 0x44136C76, 0x0404A8C8, 0xB8E5A121, + 0xB81A928A, 0x60ED5869, 0x97C55B96, 0xEAEC991B, + 0x29935913, 0x01FDB7F1, 0x088E8DFA, 0x9AB6F6F5, + 0x3B4CBF9F, 0x4A5DE3AB, 0xE6051D35, 0xA0E1D855, + 0xD36B4CF1, 0xF544EDEB, 0xB0E93524, 0xBEBB8FBD, + 0xA2D762CF, 0x49C92F54, 0x38B5F331, 0x7128A454, + 0x48392905, 0xA65B1DB8, 0x851C97BD, 0xD675CF2F +}; + +static const u32 cast_sbox7[256] = { + 0x85E04019, 0x332BF567, 0x662DBFFF, 0xCFC65693, + 0x2A8D7F6F, 0xAB9BC912, 0xDE6008A1, 0x2028DA1F, + 0x0227BCE7, 0x4D642916, 0x18FAC300, 0x50F18B82, + 0x2CB2CB11, 0xB232E75C, 0x4B3695F2, 0xB28707DE, + 0xA05FBCF6, 0xCD4181E9, 0xE150210C, 0xE24EF1BD, + 0xB168C381, 0xFDE4E789, 0x5C79B0D8, 0x1E8BFD43, + 0x4D495001, 0x38BE4341, 0x913CEE1D, 0x92A79C3F, + 0x089766BE, 0xBAEEADF4, 0x1286BECF, 0xB6EACB19, + 0x2660C200, 0x7565BDE4, 0x64241F7A, 0x8248DCA9, + 0xC3B3AD66, 0x28136086, 0x0BD8DFA8, 0x356D1CF2, + 0x107789BE, 0xB3B2E9CE, 0x0502AA8F, 0x0BC0351E, + 0x166BF52A, 0xEB12FF82, 0xE3486911, 0xD34D7516, + 0x4E7B3AFF, 0x5F43671B, 0x9CF6E037, 0x4981AC83, + 0x334266CE, 0x8C9341B7, 0xD0D854C0, 0xCB3A6C88, + 0x47BC2829, 0x4725BA37, 0xA66AD22B, 0x7AD61F1E, + 0x0C5CBAFA, 0x4437F107, 0xB6E79962, 0x42D2D816, + 0x0A961288, 0xE1A5C06E, 0x13749E67, 0x72FC081A, + 0xB1D139F7, 0xF9583745, 0xCF19DF58, 0xBEC3F756, + 0xC06EBA30, 0x07211B24, 0x45C28829, 0xC95E317F, + 0xBC8EC511, 0x38BC46E9, 0xC6E6FA14, 0xBAE8584A, + 0xAD4EBC46, 0x468F508B, 0x7829435F, 0xF124183B, + 0x821DBA9F, 0xAFF60FF4, 0xEA2C4E6D, 0x16E39264, + 0x92544A8B, 0x009B4FC3, 0xABA68CED, 0x9AC96F78, + 0x06A5B79A, 0xB2856E6E, 0x1AEC3CA9, 0xBE838688, + 0x0E0804E9, 0x55F1BE56, 0xE7E5363B, 0xB3A1F25D, + 0xF7DEBB85, 0x61FE033C, 0x16746233, 0x3C034C28, + 0xDA6D0C74, 0x79AAC56C, 0x3CE4E1AD, 0x51F0C802, + 0x98F8F35A, 0x1626A49F, 0xEED82B29, 0x1D382FE3, + 0x0C4FB99A, 0xBB325778, 0x3EC6D97B, 0x6E77A6A9, + 0xCB658B5C, 0xD45230C7, 0x2BD1408B, 0x60C03EB7, + 0xB9068D78, 0xA33754F4, 0xF430C87D, 0xC8A71302, + 0xB96D8C32, 0xEBD4E7BE, 0xBE8B9D2D, 0x7979FB06, + 0xE7225308, 0x8B75CF77, 0x11EF8DA4, 0xE083C858, + 0x8D6B786F, 0x5A6317A6, 0xFA5CF7A0, 0x5DDA0033, + 0xF28EBFB0, 0xF5B9C310, 0xA0EAC280, 0x08B9767A, + 0xA3D9D2B0, 0x79D34217, 0x021A718D, 0x9AC6336A, + 0x2711FD60, 0x438050E3, 0x069908A8, 0x3D7FEDC4, + 0x826D2BEF, 0x4EEB8476, 0x488DCF25, 0x36C9D566, + 0x28E74E41, 0xC2610ACA, 0x3D49A9CF, 0xBAE3B9DF, + 0xB65F8DE6, 0x92AEAF64, 0x3AC7D5E6, 0x9EA80509, + 0xF22B017D, 0xA4173F70, 0xDD1E16C3, 0x15E0D7F9, + 0x50B1B887, 0x2B9F4FD5, 0x625ABA82, 0x6A017962, + 0x2EC01B9C, 0x15488AA9, 0xD716E740, 0x40055A2C, + 0x93D29A22, 0xE32DBF9A, 0x058745B9, 0x3453DC1E, + 0xD699296E, 0x496CFF6F, 0x1C9F4986, 0xDFE2ED07, + 0xB87242D1, 0x19DE7EAE, 0x053E561A, 0x15AD6F8C, + 0x66626C1C, 0x7154C24C, 0xEA082B2A, 0x93EB2939, + 0x17DCB0F0, 0x58D4F2AE, 0x9EA294FB, 0x52CF564C, + 0x9883FE66, 0x2EC40581, 0x763953C3, 0x01D6692E, + 0xD3A0C108, 0xA1E7160E, 0xE4F2DFA6, 0x693ED285, + 0x74904698, 0x4C2B0EDD, 0x4F757656, 0x5D393378, + 0xA132234F, 0x3D321C5D, 0xC3F5E194, 0x4B269301, + 0xC79F022F, 0x3C997E7E, 0x5E4F9504, 0x3FFAFBBD, + 0x76F7AD0E, 0x296693F4, 0x3D1FCE6F, 0xC61E45BE, + 0xD3B5AB34, 0xF72BF9B7, 0x1B0434C0, 0x4E72B567, + 0x5592A33D, 0xB5229301, 0xCFD2A87F, 0x60AEB767, + 0x1814386B, 0x30BCC33D, 0x38A0C07D, 0xFD1606F2, + 0xC363519B, 0x589DD390, 0x5479F8E6, 0x1CB8D647, + 0x97FD61A9, 0xEA7759F4, 0x2D57539D, 0x569A58CF, + 0xE84E63AD, 0x462E1B78, 0x6580F87E, 0xF3817914, + 0x91DA55F4, 0x40A230F3, 0xD1988F35, 0xB6E318D2, + 0x3FFA50BC, 0x3D40F021, 0xC3C0BDAE, 0x4958C24C, + 0x518F36B2, 0x84B1D370, 0x0FEDCE83, 0x878DDADA, + 0xF2A279C7, 0x94E01BE8, 0x90716F4B, 0x954B8AA3 +}; + +static const u32 cast_sbox8[256] = { + 0xE216300D, 0xBBDDFFFC, 0xA7EBDABD, 0x35648095, + 0x7789F8B7, 0xE6C1121B, 0x0E241600, 0x052CE8B5, + 0x11A9CFB0, 0xE5952F11, 0xECE7990A, 0x9386D174, + 0x2A42931C, 0x76E38111, 0xB12DEF3A, 0x37DDDDFC, + 0xDE9ADEB1, 0x0A0CC32C, 0xBE197029, 0x84A00940, + 0xBB243A0F, 0xB4D137CF, 0xB44E79F0, 0x049EEDFD, + 0x0B15A15D, 0x480D3168, 0x8BBBDE5A, 0x669DED42, + 0xC7ECE831, 0x3F8F95E7, 0x72DF191B, 0x7580330D, + 0x94074251, 0x5C7DCDFA, 0xABBE6D63, 0xAA402164, + 0xB301D40A, 0x02E7D1CA, 0x53571DAE, 0x7A3182A2, + 0x12A8DDEC, 0xFDAA335D, 0x176F43E8, 0x71FB46D4, + 0x38129022, 0xCE949AD4, 0xB84769AD, 0x965BD862, + 0x82F3D055, 0x66FB9767, 0x15B80B4E, 0x1D5B47A0, + 0x4CFDE06F, 0xC28EC4B8, 0x57E8726E, 0x647A78FC, + 0x99865D44, 0x608BD593, 0x6C200E03, 0x39DC5FF6, + 0x5D0B00A3, 0xAE63AFF2, 0x7E8BD632, 0x70108C0C, + 0xBBD35049, 0x2998DF04, 0x980CF42A, 0x9B6DF491, + 0x9E7EDD53, 0x06918548, 0x58CB7E07, 0x3B74EF2E, + 0x522FFFB1, 0xD24708CC, 0x1C7E27CD, 0xA4EB215B, + 0x3CF1D2E2, 0x19B47A38, 0x424F7618, 0x35856039, + 0x9D17DEE7, 0x27EB35E6, 0xC9AFF67B, 0x36BAF5B8, + 0x09C467CD, 0xC18910B1, 0xE11DBF7B, 0x06CD1AF8, + 0x7170C608, 0x2D5E3354, 0xD4DE495A, 0x64C6D006, + 0xBCC0C62C, 0x3DD00DB3, 0x708F8F34, 0x77D51B42, + 0x264F620F, 0x24B8D2BF, 0x15C1B79E, 0x46A52564, + 0xF8D7E54E, 0x3E378160, 0x7895CDA5, 0x859C15A5, + 0xE6459788, 0xC37BC75F, 0xDB07BA0C, 0x0676A3AB, + 0x7F229B1E, 0x31842E7B, 0x24259FD7, 0xF8BEF472, + 0x835FFCB8, 0x6DF4C1F2, 0x96F5B195, 0xFD0AF0FC, + 0xB0FE134C, 0xE2506D3D, 0x4F9B12EA, 0xF215F225, + 0xA223736F, 0x9FB4C428, 0x25D04979, 0x34C713F8, + 0xC4618187, 0xEA7A6E98, 0x7CD16EFC, 0x1436876C, + 0xF1544107, 0xBEDEEE14, 0x56E9AF27, 0xA04AA441, + 0x3CF7C899, 0x92ECBAE6, 0xDD67016D, 0x151682EB, + 0xA842EEDF, 0xFDBA60B4, 0xF1907B75, 0x20E3030F, + 0x24D8C29E, 0xE139673B, 0xEFA63FB8, 0x71873054, + 0xB6F2CF3B, 0x9F326442, 0xCB15A4CC, 0xB01A4504, + 0xF1E47D8D, 0x844A1BE5, 0xBAE7DFDC, 0x42CBDA70, + 0xCD7DAE0A, 0x57E85B7A, 0xD53F5AF6, 0x20CF4D8C, + 0xCEA4D428, 0x79D130A4, 0x3486EBFB, 0x33D3CDDC, + 0x77853B53, 0x37EFFCB5, 0xC5068778, 0xE580B3E6, + 0x4E68B8F4, 0xC5C8B37E, 0x0D809EA2, 0x398FEB7C, + 0x132A4F94, 0x43B7950E, 0x2FEE7D1C, 0x223613BD, + 0xDD06CAA2, 0x37DF932B, 0xC4248289, 0xACF3EBC3, + 0x5715F6B7, 0xEF3478DD, 0xF267616F, 0xC148CBE4, + 0x9052815E, 0x5E410FAB, 0xB48A2465, 0x2EDA7FA4, + 0xE87B40E4, 0xE98EA084, 0x5889E9E1, 0xEFD390FC, + 0xDD07D35B, 0xDB485694, 0x38D7E5B2, 0x57720101, + 0x730EDEBC, 0x5B643113, 0x94917E4F, 0x503C2FBA, + 0x646F1282, 0x7523D24A, 0xE0779695, 0xF9C17A8F, + 0x7A5B2121, 0xD187B896, 0x29263A4D, 0xBA510CDF, + 0x81F47C9F, 0xAD1163ED, 0xEA7B5965, 0x1A00726E, + 0x11403092, 0x00DA6D77, 0x4A0CDD61, 0xAD1F4603, + 0x605BDFB0, 0x9EEDC364, 0x22EBE6A8, 0xCEE7D28A, + 0xA0E736A0, 0x5564A6B9, 0x10853209, 0xC7EB8F37, + 0x2DE705CA, 0x8951570F, 0xDF09822B, 0xBD691A6C, + 0xAA12E4F2, 0x87451C0F, 0xE0F6A27A, 0x3ADA4819, + 0x4CF1764F, 0x0D771C2B, 0x67CDB156, 0x350D8384, + 0x5938FA0F, 0x42399EF3, 0x36997B07, 0x0E84093D, + 0x4AA93E61, 0x8360D87B, 0x1FA98B0C, 0x1149382C, + 0xE97625A5, 0x0614D1B7, 0x0E25244B, 0x0C768347, + 0x589E8D82, 0x0D2059D1, 0xA466BB1E, 0xF8DA0A82, + 0x04F19130, 0xBA6E4EC0, 0x99265164, 0x1EE7230D, + 0x50B2AD80, 0xEAEE6801, 0x8DB2A283, 0xEA8BF59E +}; + diff --git a/doc/man/apg.1 b/doc/man/apg.1 new file mode 100644 index 0000000..133f71a --- /dev/null +++ b/doc/man/apg.1 @@ -0,0 +1,227 @@ +.\" Man page for apg. +.\" Licensed under BSD-like License. +.\" Created by Adel I. Mirzazhanov +.\" +.TH APG 1 "2001 Feb 13" "Automated Password Generator" "User Manual" +.SH NAME +apg +\- generates several random passwords + +.SH SYNOPSIS +.B apg +[\fB-r\fP \fIdictfile\fP] +[\fB-a algorithm\fP] [\fB-C\fP] [\fB-L\fP] [\fB-S\fP] [\fB-N\fP] [\fB-R\fP] +[\fB-M mode\fP] [\fB-m min_pass_len\fP] [\fB-x max_pass_len\fP] [\fB-n num_of_pass\fP] +[\fB-s\fP] [\fB-c cl_seed\fP] [\fB-d\fP] [\fB-y\fP] [\fB-h\fP] [\fB-v\fP] +.PP +.SH DESCRIPTION +.B apg +generates several random passwords. It uses several password generation +algorithms (currently two) and a built-in pseudo random number generator. +.PP +Default algorithm is pronounceable password generation algorithm +designed by +.B Morrie Gasser +and described in +.B "A Random Word Generator For Pronounceable Passwords" +.I National Technical Information Service (NTIS) +.B AD-A-017676. +The original paper is very old and had never been put online, +so I have to use +.I NIST +implementation described in +.B FIPS-181. +.PP +Another algorithm is simple random character generation algorithm, but it +uses four user-defined symbol sets to produce random password. It means that +user can choose type of symbols that should appear in password. Symbol sets +are: numeric symbol set +.I (0,...,9) +, capital letters symbol set +.I (A,...,Z) +, small letters symbol set +.I (a,...,z) +and special symbols symbol set +.I (#,@,!,...). +.PP +Built-in pseudo random number generator is an implementation of algorithm +described in +.B Appendix C of ANSI X9.17 +or +.B RFC1750 +with exception that it uses +.I CAST +instead of +.I Triple DES. +It uses local time with precision of microseconds (see +\fBgettimeofday\fP(2)) and \fI/dev/random\fP (if available) to produce +initial random seed. +.PP +.B apg +also have the ability to check generated password quality using +dictionary. You can use this ability if you specify command-line option +.B -r +.I dictfile +where \fIdictfile\fP is dictionary file name. In that dictionary you may place words +(one per line) that should not appear as generated passwords. For example: user names, +common words, etc. You even can use one of the dictionaries that come with +.I dictionary password crackers. +This check is case sensitive. For example, if you want to reject word 'root', +you should insert in \fIdictfile\fP words: root, Root, RoOt, ... , ROOT. +It is not the easiest way to check password quality, but +it is the most powerful way. In future releases I plan to implement some other +techniques to check passwords (like pattern check) just to make life easier. +.sp +.SH "OPTIONS" +.TP +.B -M mode +Use symbolsets specified with \fBmode\fP for password generation. +\fBmode\fP is a text string consisting of characters \fBS[s]\fP, \fBN[n]\fP, +\fBC[c]\fP, \fBL[l]\fP,\fBR[r]\fP. Where: +.RS +.TP +.B S[s] +use special symbol set (for random character password generation algorithm only). +.TP +.B N[n] +use numeral symbol set. +.TP +.B C[c] +use capital symbol set. +.TP +.B L[l] +use small letters symbol set (always present if pronounceable password +generation algorithm is used). +.TP +.B R[r] +the same as \fBS[s]\fP but it does not generate symbols \fB`\fP, \fB'\fP, +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +a shell script. (For random character password generation algorithm only). +.RE +.RS +.br +\fBmode\fP can not be more then 5 characters in +length. +.PP +.B Examples: +.br +\fB-M sncl\fP or \fB-M SNCL\fP or \fB-M Cn\fP +.PP +\fB-M mode\fP is the new style password generation mode definition, but the old style +options(-C, -N, -S, -L, -R) are also supported. +.RE +.TP +.B -S +use special symbol set. For random character password generation algorithm only. +(old style - use \fB-M mode\fP instead). +.TP +.B -R +the same as \fB-S\fP but it does not generate symbols \fB`\fP, \fB'\fP, +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +a shell script. For random character password generation algorithm only. +(old style - use \fB-M mode\fP instead). +.TP +.B -N +use numeral symbol set. +(old style - use \fB-M mode\fP instead). +.TP +.B -C +use capital symbol set. +(old style - use \fB-M mode\fP instead). +.TP +.B -L +use small letters symbol set. Always present if pronounceable password +generation algorithm is used. +(old style - use \fB-M mode\fP instead). +.TP +.B -a algorithm +use +.B algorithm +for password generation. +.RS +.B 0 +- (default) pronounceable password generation +.br +.B 1 +- random character password generation +.RE +.TP +.B -r \fIdictfile\fP +check generated passwords for their appearance in +.B dictfile +.TP +.B -s +ask user for random sequence for password generation +.TP +.B -c cl_seed +use +.B cl_seed +as a random seed for password generation. I use it when i have to generate +passwords in a shell script. +.TP +.B -d +do NOT use any delimiters between generated passwords. I use it when i have to generate +passwords in a shell script. +.TP +.B -n num_of_pass +generate +.B num_of_pass +number of passwords. Default is 6. +.TP +.B -m min_pass_len +generate password with minimum length +.B min_pass_len. +If \fBmin_pass_len > max_pass_len\fP then \fBmax_pass_len = min_pass_len\fP. +Default minimum password length is 6. +.TP +.B -x max_pass_len +generate password with maximum length +.B max_pass_len. +If \fBmin_pass_len > max_pass_len\fP then \fBmax_pass_len = min_pass_len\fP. +Default maximum password length is 8. +.TP +.B -y +print generated passwords and crypted passwords (see man \fBcrypt\fP(3)) +.TP +.B -h +print help information and exit +.TP +.B -v +print version information and exit +.SH "DEFAULT OPTIONS" +\fBapg -a 0 -N -C -L -n 6 -x 8 -m 6\fP (old style) +.br +\fBapg -a 0 -M NCL -n 6 -x 8 -m 6\fP (new style) +.PP +If you want to generate realy secure passwords, +you should use option \fB-s\fP. To simlify +.B apg +usage, you can write a small shell script. For example: +.br +\fB[begin]----> pwgen.sh\fP +.br +\fB#!/bin/sh\fP +.br +\fB/usr/local/bin/apg -m 8 -x 12 -s\fP +.br +\fB[ end ]----> pwgen.sh\fP +.SH "EXIT CODE" +On successful completion of its task, +.B apg +will complete with exit code 0. An exit code of -1 indicates an error +occurred. Textual errors are written to the standard error stream. +.SH "DIAGNOSTICS" +If \fI/dev/random\fP is not available, \fBapg\fP will display a +message about it. +.SH "FILES" +.B None. +.SH "BUGS" +.B None. +If you've found one, please send bug description to the author. +.SH "SEE ALSO" +.B apgd +(8) +.SH "AUTHOR" +Adel I. Mirzazhanov, +.br +Project home page: http://www.adel.nursat.kz/apg/ diff --git a/doc/man/apgd.8 b/doc/man/apgd.8 new file mode 100644 index 0000000..1b9710a --- /dev/null +++ b/doc/man/apgd.8 @@ -0,0 +1,229 @@ +.\" Man page for apgd. +.\" Licensed under BSD-like License. +.\" Created by Adel I. Mirzazhanov +.\" +.TH APGD 8 "2001 Jan 8" "Automated Password Generator" "User Manual" +.SH NAME +apgd +\- server that generates several random passwords + +.SH SYNOPSIS +.B apgd +[\fB-r\fP \fIdictfile\fP] +[\fB-a algorithm\fP] [\fB-C\fP] [\fB-L\fP] [\fB-S\fP] [\fB-N\fP] +[\fB-m min_pass_len\fP] [\fB-x max_pass_len\fP] [\fB-n num_of_pass\fP] +.PP +.SH DESCRIPTION +.B apgd +program is a server that supports +.B "Password Generation Protocol" +described in +.B RFC972. +It uses several password generation algorithms (currently two) and a built-in +pseudo random number generator. +.PP +.B apgd +is normally invoked by the Internet superserver (see +.B inetd +(8)) for requests to connect to the pwdgen port (pwdgen port is 129 according to +.B RFC1700 +) as indicated by the +.I /etc/services +file (see +.B services +(5)). +.PP +Default algorithm is pronounceable password generation algorithm +designed by +.B Morrie Gasser +and described in +.B """A Random Word Generator For Pronounceable Passwords""" +.I National Technical Information Service (NTIS) +.B AD-A-017676. +The original paper is very old and had never been put online, +so I have to use +.I NIST +implementation described in +.B FIPS-181. +.PP +Another algorithm is simple random character generation algorithm, but it +uses four user-defined symbol sets to produce random password. It means that +user can choose type of symbols that should appear in password. Symbol sets +are: numeric symbol set +.I (0,...,9) +, capital letters symbol set +.I (A,...,Z) +, small letters symbol set +.I (a,...,z) +and special symbols symbol set +.I (#,@,!,...). +.PP +Built-in pseudo random number generator is an implementation of algorithm +described in +.B Appendix C of ANSI X9.17 +or +.B RFC1750 +with exception that it uses +.I CAST +instead of +.I Triple DES. +It uses local time with precision of microseconds (see +\fBgettimeofday\fP(2)) and \fI/dev/random\fP (if available) to produce +initial random seed. +.PP +.B apgd +also have the ability to check generated password quality using +dictionary. You can use this ability if you specify command-line option +.B -r +.I dictfile +where \fIdictfile\fP is dictionary file name. In that dictionary you may place words +(one per line) that should not appear as generated passwords. For example: user names +common words, etc. You even can use one of the dictionaries that come with +.I dictionary password crackers. +This check is case sensitive. For example, if you want to reject word 'root', +you should insert in \fIdictfile\fP words: root, Root, RoOt, ... , ROOT. +It is not the easiest way to check password quality, but +it is the most powerful way. In future releases I plan to implement some other +techniques to check passwords just to make life easier. +.PP +.B apgd +has the ability log user password generation activity and internal debug information. It does this +using +.br +.I facility += +.I daemon +.RS +.br +.I priority += +.I info +for user password generation activity logging +.br +.I priority += +.I debug +for internal debug information +.br +.RE +See the \fBsyslogd\fP(8) and \fBsyslog.conf\fP(5) man pages for information on how to configure your syslog daemon. +.sp +.SH "OPTIONS" +.TP +.B -M mode +Use symbolsets specified with \fBmode\fP for password generation. +\fBmode\fP is a text string consisting of characters \fBS[s]\fP, \fBN[n]\fP, +\fBC[c]\fP, \fBL[l]\fP,\fBR[r]\fP. Where: +.RS +.TP +.B S[s] +use special symbol set (for random character password generation algorithm only). +.TP +.B N[n] +use numeral symbol set. +.TP +.B C[c] +use capital symbol set. +.TP +.B L[l] +use small letters symbol set (always present if pronounceable password +generation algorithm is used). +.TP +.B R[r] +the same as \fBS[s]\fP but it does not generate symbols \fB`\fP, \fB'\fP, +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +a shell script. (For random character password generation algorithm only). +.RE +.RS +.br +\fBmode\fP can not be more then 5 characters in +length. +.PP +.B Examples: +.br +\fB-M sncl\fP or \fB-M SNCL\fP or \fB-M Cn\fP +.PP +\fB-M mode\fP is the new style password generation mode definition, but the old style +options(-C, -N, -S, -L, -R) are also supported. +.RE +.TP +.B -S +use special symbol set. For random character password generation algorithm only. +(old style - use \fB-M mode\fP instead). +.TP +.B -R +the same as \fB-S\fP but it does not generate symbols \fB`\fP, \fB'\fP, +\fB"\fP, \fB|\fP, \fB$\fP, \fBbackslash\fP, \fB?\fP. Usefull for password generation in +a shell script. For random character password generation algorithm only. +(old style - use \fB-M mode\fP instead). +.TP +.B -N +use numeral symbol set. +(old style - use \fB-M mode\fP instead). +.TP +.B -C +use capital symbol set. +(old style - use \fB-M mode\fP instead). +.TP +.B -L +use small letters symbol set. Always present if pronounceable password +generation algorithm is used. +(old style - use \fB-M mode\fP instead). +.TP +.B -a algorithm +use +.B algorithm +for password generation. +.RS +.B 0 +- (default) pronounceable password generation +.br +.B 1 +- random character password generation +.RE +.TP +.B -r \fIdictfile\fP +check generated passwords for their appearance in +.B dictfile +.TP +.B -n num_of_pass +generate +.B num_of_pass +number of passwords. Default is 6. +.TP +.B -m min_pass_len +generate password with minimum length +.B min_pass_len. +If \fBmin_pass_len > max_pass_len\fP then \fBmax_pass_len = min_pass_len\fP. +Default minimum password length is 6. +.TP +.B -x max_pass_len +generate password with maximum length +.B max_pass_len +If \fBmin_pass_len > max_pass_len\fP then \fBmax_pass_len = min_pass_len\fP. +Default maximum password length is 8. +.SH "DEFAULT OPTIONS" +\fBapgd -a 0 -N -C -L -n 6 -m 6 -x 8\fP (old style) +.br +\fBapgd -a 0 -M NCL -n 6 -x 8 -m 6\fP (new style) +.SH "EXIT CODE" +On successful completion of its task, +.B apgd +will complete with exit code 0. An exit code of -1 indicates an error +occurred. Textual errors are written to the +.B syslogd +(8). +.SH "DIAGNOSTICS" +All textual info is written to the +\fBsyslogd\fP(8). +.SH "FILES" +.B None. +.SH "BUGS" +.B None. +If you've found one, please send bug description to the author. +.SH "SEE ALSO" +\fBapg\fP(1) +.SH "AUTHOR" +Adel I. Mirzazhanov, +.br +Project home page: http://www.adel.nursat.kz/apg/ diff --git a/doc/rfc0972.txt b/doc/rfc0972.txt new file mode 100644 index 0000000..7ab2bb8 --- /dev/null +++ b/doc/rfc0972.txt @@ -0,0 +1,114 @@ + + +Network Working Group F. Wancho +Request for Comments: 972 WSMR + January 1986 + + Password Generator Protocol + + +STATUS OF THIS MEMO + + This RFC specifies a standard for the ARPA Internet community. Hosts + on the ARPA Internet that choose to implement a Password Generator + Protocol (PWDGEN) are expected to adopt and implement this standard. + Distribution of this memo is unlimited. + +BACKGROUND + + Many security-conscious host administrators are becoming increasingly + aware that user-selected login passwords are too easy to guess for + even casual penetration attempts. Some sites have implemented + dictionary lookup techniques in their password programs to prevent + ordinary words from being used. Others have implemented some variant + of a randomly generated password with mixed success. The problem + arises from the fact that such passwords are difficult to remember + because they cannot be pronounced or are based on a relatively short + cycle pseudo-random number generator. + + A version of the PWDGEN algorithm briefly described below has been in + use for several years at a small number of sites in the Internet. + Interest has recently been expressed at porting this algorithm to + other sites. However, the relatively short cycle and the resulting + randomness of the pseudo-random number generator available on these + sites tends to interfere with the intended result of minimizing the + potential duplication of passwords both within a site and across + sites when a user has access to more than one site. + + The PWDGEN Service described herein provides a means for sites to + offer a list of possible passwords for the user to choose one from + the first set, or optionally select from another set. With more than + one site offering this service, it is then possible to randomly + select which site to use and have multiple fallback sites should that + site be unavailable. + + Description + + The PWDGEN Service provides a set of six randomly generated + eight-character CRLF-delimited "words" with a reasonable level of + pronounceability, using a multi-level algorithm. An + implementation of the algorithm is available in FORTRAN-77 for + examination and possible implementation by system administrators + only. + + + +Wancho [Page 1] + + + +RFC 972 January 1986 +Password Generator Protocol + + + The uniqueness of the generated words is highly dependent on the + randomness of the initial seed value used. The availability of a + single system-wide seed, updated after each access is highly + desireable. Seeds based on a time-of-day clock are unacceptable. + Seed values should be stored as values in excess of 32 bits for + best performance. + + TCP Based PWDGEN Service + + One PWDGEN service is defined as a connection based application on + TCP. A server listens for TCP connections on TCP port 129. Once + a connection is established, the six CRLF-delimited words are + generated and sent to the caller, and the connection is closed by + the server. No dialog is used or required. + + UDP Based PWDGEN Service + + Another possible PWDGEN service is defined as a datagram based + application on UDP. A server listens for UDP datagrams on UDP + port 129. When a datagram is received, the six CRLF-delimited + words are sent back in an answering datagram. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Wancho [Page 2] + diff --git a/doc/rfc1750.txt b/doc/rfc1750.txt new file mode 100644 index 0000000..56d478c --- /dev/null +++ b/doc/rfc1750.txt @@ -0,0 +1,1683 @@ + + + + + + +Network Working Group D. Eastlake, 3rd +Request for Comments: 1750 DEC +Category: Informational S. Crocker + Cybercash + J. Schiller + MIT + December 1994 + + + Randomness Recommendations for Security + +Status of this Memo + + This memo provides information for the Internet community. This memo + does not specify an Internet standard of any kind. Distribution of + this memo is unlimited. + +Abstract + + Security systems today are built on increasingly strong cryptographic + algorithms that foil pattern analysis attempts. However, the security + of these systems is dependent on generating secret quantities for + passwords, cryptographic keys, and similar quantities. The use of + pseudo-random processes to generate secret quantities can result in + pseudo-security. The sophisticated attacker of these security + systems may find it easier to reproduce the environment that produced + the secret quantities, searching the resulting small set of + possibilities, than to locate the quantities in the whole of the + number space. + + Choosing random quantities to foil a resourceful and motivated + adversary is surprisingly difficult. This paper points out many + pitfalls in using traditional pseudo-random number generation + techniques for choosing such quantities. It recommends the use of + truly random hardware techniques and shows that the existing hardware + on many systems can be used for this purpose. It provides + suggestions to ameliorate the problem when a hardware solution is not + available. And it gives examples of how large such quantities need + to be for some particular applications. + + + + + + + + + + + + +Eastlake, Crocker & Schiller [Page 1] + +RFC 1750 Randomness Recommendations for Security December 1994 + + +Acknowledgements + + Comments on this document that have been incorporated were received + from (in alphabetic order) the following: + + David M. Balenson (TIS) + Don Coppersmith (IBM) + Don T. Davis (consultant) + Carl Ellison (Stratus) + Marc Horowitz (MIT) + Christian Huitema (INRIA) + Charlie Kaufman (IRIS) + Steve Kent (BBN) + Hal Murray (DEC) + Neil Haller (Bellcore) + Richard Pitkin (DEC) + Tim Redmond (TIS) + Doug Tygar (CMU) + +Table of Contents + + 1. Introduction........................................... 3 + 2. Requirements........................................... 4 + 3. Traditional Pseudo-Random Sequences.................... 5 + 4. Unpredictability....................................... 7 + 4.1 Problems with Clocks and Serial Numbers............... 7 + 4.2 Timing and Content of External Events................ 8 + 4.3 The Fallacy of Complex Manipulation.................. 8 + 4.4 The Fallacy of Selection from a Large Database....... 9 + 5. Hardware for Randomness............................... 10 + 5.1 Volume Required...................................... 10 + 5.2 Sensitivity to Skew.................................. 10 + 5.2.1 Using Stream Parity to De-Skew..................... 11 + 5.2.2 Using Transition Mappings to De-Skew............... 12 + 5.2.3 Using FFT to De-Skew............................... 13 + 5.2.4 Using Compression to De-Skew....................... 13 + 5.3 Existing Hardware Can Be Used For Randomness......... 14 + 5.3.1 Using Existing Sound/Video Input................... 14 + 5.3.2 Using Existing Disk Drives......................... 14 + 6. Recommended Non-Hardware Strategy..................... 14 + 6.1 Mixing Functions..................................... 15 + 6.1.1 A Trivial Mixing Function.......................... 15 + 6.1.2 Stronger Mixing Functions.......................... 16 + 6.1.3 Diff-Hellman as a Mixing Function.................. 17 + 6.1.4 Using a Mixing Function to Stretch Random Bits..... 17 + 6.1.5 Other Factors in Choosing a Mixing Function........ 18 + 6.2 Non-Hardware Sources of Randomness................... 19 + 6.3 Cryptographically Strong Sequences................... 19 + + + +Eastlake, Crocker & Schiller [Page 2] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + 6.3.1 Traditional Strong Sequences....................... 20 + 6.3.2 The Blum Blum Shub Sequence Generator.............. 21 + 7. Key Generation Standards.............................. 22 + 7.1 US DoD Recommendations for Password Generation....... 23 + 7.2 X9.17 Key Generation................................. 23 + 8. Examples of Randomness Required....................... 24 + 8.1 Password Generation................................. 24 + 8.2 A Very High Security Cryptographic Key............... 25 + 8.2.1 Effort per Key Trial............................... 25 + 8.2.2 Meet in the Middle Attacks......................... 26 + 8.2.3 Other Considerations............................... 26 + 9. Conclusion............................................ 27 + 10. Security Considerations.............................. 27 + References............................................... 28 + Authors' Addresses....................................... 30 + +1. Introduction + + Software cryptography is coming into wider use. Systems like + Kerberos, PEM, PGP, etc. are maturing and becoming a part of the + network landscape [PEM]. These systems provide substantial + protection against snooping and spoofing. However, there is a + potential flaw. At the heart of all cryptographic systems is the + generation of secret, unguessable (i.e., random) numbers. + + For the present, the lack of generally available facilities for + generating such unpredictable numbers is an open wound in the design + of cryptographic software. For the software developer who wants to + build a key or password generation procedure that runs on a wide + range of hardware, the only safe strategy so far has been to force + the local installation to supply a suitable routine to generate + random numbers. To say the least, this is an awkward, error-prone + and unpalatable solution. + + It is important to keep in mind that the requirement is for data that + an adversary has a very low probability of guessing or determining. + This will fail if pseudo-random data is used which only meets + traditional statistical tests for randomness or which is based on + limited range sources, such as clocks. Frequently such random + quantities are determinable by an adversary searching through an + embarrassingly small space of possibilities. + + This informational document suggests techniques for producing random + quantities that will be resistant to such attack. It recommends that + future systems include hardware random number generation or provide + access to existing hardware that can be used for this purpose. It + suggests methods for use if such hardware is not available. And it + gives some estimates of the number of random bits required for sample + + + +Eastlake, Crocker & Schiller [Page 3] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + applications. + +2. Requirements + + Probably the most commonly encountered randomness requirement today + is the user password. This is usually a simple character string. + Obviously, if a password can be guessed, it does not provide + security. (For re-usable passwords, it is desirable that users be + able to remember the password. This may make it advisable to use + pronounceable character strings or phrases composed on ordinary + words. But this only affects the format of the password information, + not the requirement that the password be very hard to guess.) + + Many other requirements come from the cryptographic arena. + Cryptographic techniques can be used to provide a variety of services + including confidentiality and authentication. Such services are + based on quantities, traditionally called "keys", that are unknown to + and unguessable by an adversary. + + In some cases, such as the use of symmetric encryption with the one + time pads [CRYPTO*] or the US Data Encryption Standard [DES], the + parties who wish to communicate confidentially and/or with + authentication must all know the same secret key. In other cases, + using what are called asymmetric or "public key" cryptographic + techniques, keys come in pairs. One key of the pair is private and + must be kept secret by one party, the other is public and can be + published to the world. It is computationally infeasible to + determine the private key from the public key [ASYMMETRIC, CRYPTO*]. + + The frequency and volume of the requirement for random quantities + differs greatly for different cryptographic systems. Using pure RSA + [CRYPTO*], random quantities are required when the key pair is + generated, but thereafter any number of messages can be signed + without any further need for randomness. The public key Digital + Signature Algorithm that has been proposed by the US National + Institute of Standards and Technology (NIST) requires good random + numbers for each signature. And encrypting with a one time pad, in + principle the strongest possible encryption technique, requires a + volume of randomness equal to all the messages to be processed. + + In most of these cases, an adversary can try to determine the + "secret" key by trial and error. (This is possible as long as the + key is enough smaller than the message that the correct key can be + uniquely identified.) The probability of an adversary succeeding at + this must be made acceptably low, depending on the particular + application. The size of the space the adversary must search is + related to the amount of key "information" present in the information + theoretic sense [SHANNON]. This depends on the number of different + + + +Eastlake, Crocker & Schiller [Page 4] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + secret values possible and the probability of each value as follows: + + ----- + \ + Bits-of-info = \ - p * log ( p ) + / i 2 i + / + ----- + + where i varies from 1 to the number of possible secret values and p + sub i is the probability of the value numbered i. (Since p sub i is + less than one, the log will be negative so each term in the sum will + be non-negative.) + + If there are 2^n different values of equal probability, then n bits + of information are present and an adversary would, on the average, + have to try half of the values, or 2^(n-1) , before guessing the + secret quantity. If the probability of different values is unequal, + then there is less information present and fewer guesses will, on + average, be required by an adversary. In particular, any values that + the adversary can know are impossible, or are of low probability, can + be initially ignored by an adversary, who will search through the + more probable values first. + + For example, consider a cryptographic system that uses 56 bit keys. + If these 56 bit keys are derived by using a fixed pseudo-random + number generator that is seeded with an 8 bit seed, then an adversary + needs to search through only 256 keys (by running the pseudo-random + number generator with every possible seed), not the 2^56 keys that + may at first appear to be the case. Only 8 bits of "information" are + in these 56 bit keys. + +3. Traditional Pseudo-Random Sequences + + Most traditional sources of random numbers use deterministic sources + of "pseudo-random" numbers. These typically start with a "seed" + quantity and use numeric or logical operations to produce a sequence + of values. + + [KNUTH] has a classic exposition on pseudo-random numbers. + Applications he mentions are simulation of natural phenomena, + sampling, numerical analysis, testing computer programs, decision + making, and games. None of these have the same characteristics as + the sort of security uses we are talking about. Only in the last two + could there be an adversary trying to find the random quantity. + However, in these cases, the adversary normally has only a single + chance to use a guessed value. In guessing passwords or attempting + to break an encryption scheme, the adversary normally has many, + + + +Eastlake, Crocker & Schiller [Page 5] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + perhaps unlimited, chances at guessing the correct value and should + be assumed to be aided by a computer. + + For testing the "randomness" of numbers, Knuth suggests a variety of + measures including statistical and spectral. These tests check + things like autocorrelation between different parts of a "random" + sequence or distribution of its values. They could be met by a + constant stored random sequence, such as the "random" sequence + printed in the CRC Standard Mathematical Tables [CRC]. + + A typical pseudo-random number generation technique, known as a + linear congruence pseudo-random number generator, is modular + arithmetic where the N+1th value is calculated from the Nth value by + + V = ( V * a + b )(Mod c) + N+1 N + + The above technique has a strong relationship to linear shift + register pseudo-random number generators, which are well understood + cryptographically [SHIFT*]. In such generators bits are introduced + at one end of a shift register as the Exclusive Or (binary sum + without carry) of bits from selected fixed taps into the register. + + For example: + + +----+ +----+ +----+ +----+ + | B | <-- | B | <-- | B | <-- . . . . . . <-- | B | <-+ + | 0 | | 1 | | 2 | | n | | + +----+ +----+ +----+ +----+ | + | | | | + | | V +-----+ + | V +----------------> | | + V +-----------------------------> | XOR | + +---------------------------------------------------> | | + +-----+ + + + V = ( ( V * 2 ) + B .xor. B ... )(Mod 2^n) + N+1 N 0 2 + + The goodness of traditional pseudo-random number generator algorithms + is measured by statistical tests on such sequences. Carefully chosen + values of the initial V and a, b, and c or the placement of shift + register tap in the above simple processes can produce excellent + statistics. + + + + + + +Eastlake, Crocker & Schiller [Page 6] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + These sequences may be adequate in simulations (Monte Carlo + experiments) as long as the sequence is orthogonal to the structure + of the space being explored. Even there, subtle patterns may cause + problems. However, such sequences are clearly bad for use in + security applications. They are fully predictable if the initial + state is known. Depending on the form of the pseudo-random number + generator, the sequence may be determinable from observation of a + short portion of the sequence [CRYPTO*, STERN]. For example, with + the generators above, one can determine V(n+1) given knowledge of + V(n). In fact, it has been shown that with these techniques, even if + only one bit of the pseudo-random values is released, the seed can be + determined from short sequences. + + Not only have linear congruent generators been broken, but techniques + are now known for breaking all polynomial congruent generators + [KRAWCZYK]. + +4. Unpredictability + + Randomness in the traditional sense described in section 3 is NOT the + same as the unpredictability required for security use. + + For example, use of a widely available constant sequence, such as + that from the CRC tables, is very weak against an adversary. Once + they learn of or guess it, they can easily break all security, future + and past, based on the sequence [CRC]. Yet the statistical + properties of these tables are good. + + The following sections describe the limitations of some randomness + generation techniques and sources. + +4.1 Problems with Clocks and Serial Numbers + + Computer clocks, or similar operating system or hardware values, + provide significantly fewer real bits of unpredictability than might + appear from their specifications. + + Tests have been done on clocks on numerous systems and it was found + that their behavior can vary widely and in unexpected ways. One + version of an operating system running on one set of hardware may + actually provide, say, microsecond resolution in a clock while a + different configuration of the "same" system may always provide the + same lower bits and only count in the upper bits at much lower + resolution. This means that successive reads on the clock may + produce identical values even if enough time has passed that the + value "should" change based on the nominal clock resolution. There + are also cases where frequently reading a clock can produce + artificial sequential values because of extra code that checks for + + + +Eastlake, Crocker & Schiller [Page 7] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + the clock being unchanged between two reads and increases it by one! + Designing portable application code to generate unpredictable numbers + based on such system clocks is particularly challenging because the + system designer does not always know the properties of the system + clocks that the code will execute on. + + Use of a hardware serial number such as an Ethernet address may also + provide fewer bits of uniqueness than one would guess. Such + quantities are usually heavily structured and subfields may have only + a limited range of possible values or values easily guessable based + on approximate date of manufacture or other data. For example, it is + likely that most of the Ethernet cards installed on Digital Equipment + Corporation (DEC) hardware within DEC were manufactured by DEC + itself, which significantly limits the range of built in addresses. + + Problems such as those described above related to clocks and serial + numbers make code to produce unpredictable quantities difficult if + the code is to be ported across a variety of computer platforms and + systems. + +4.2 Timing and Content of External Events + + It is possible to measure the timing and content of mouse movement, + key strokes, and similar user events. This is a reasonable source of + unguessable data with some qualifications. On some machines, inputs + such as key strokes are buffered. Even though the user's inter- + keystroke timing may have sufficient variation and unpredictability, + there might not be an easy way to access that variation. Another + problem is that no standard method exists to sample timing details. + This makes it hard to build standard software intended for + distribution to a large range of machines based on this technique. + + The amount of mouse movement or the keys actually hit are usually + easier to access than timings but may yield less unpredictability as + the user may provide highly repetitive input. + + Other external events, such as network packet arrival times, can also + be used with care. In particular, the possibility of manipulation of + such times by an adversary must be considered. + +4.3 The Fallacy of Complex Manipulation + + One strategy which may give a misleading appearance of + unpredictability is to take a very complex algorithm (or an excellent + traditional pseudo-random number generator with good statistical + properties) and calculate a cryptographic key by starting with the + current value of a computer system clock as the seed. An adversary + who knew roughly when the generator was started would have a + + + +Eastlake, Crocker & Schiller [Page 8] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + relatively small number of seed values to test as they would know + likely values of the system clock. Large numbers of pseudo-random + bits could be generated but the search space an adversary would need + to check could be quite small. + + Thus very strong and/or complex manipulation of data will not help if + the adversary can learn what the manipulation is and there is not + enough unpredictability in the starting seed value. Even if they can + not learn what the manipulation is, they may be able to use the + limited number of results stemming from a limited number of seed + values to defeat security. + + Another serious strategy error is to assume that a very complex + pseudo-random number generation algorithm will produce strong random + numbers when there has been no theory behind or analysis of the + algorithm. There is a excellent example of this fallacy right near + the beginning of chapter 3 in [KNUTH] where the author describes a + complex algorithm. It was intended that the machine language program + corresponding to the algorithm would be so complicated that a person + trying to read the code without comments wouldn't know what the + program was doing. Unfortunately, actual use of this algorithm + showed that it almost immediately converged to a single repeated + value in one case and a small cycle of values in another case. + + Not only does complex manipulation not help you if you have a limited + range of seeds but blindly chosen complex manipulation can destroy + the randomness in a good seed! + +4.4 The Fallacy of Selection from a Large Database + + Another strategy that can give a misleading appearance of + unpredictability is selection of a quantity randomly from a database + and assume that its strength is related to the total number of bits + in the database. For example, typical USENET servers as of this date + process over 35 megabytes of information per day. Assume a random + quantity was selected by fetching 32 bytes of data from a random + starting point in this data. This does not yield 32*8 = 256 bits + worth of unguessability. Even after allowing that much of the data + is human language and probably has more like 2 or 3 bits of + information per byte, it doesn't yield 32*2.5 = 80 bits of + unguessability. For an adversary with access to the same 35 + megabytes the unguessability rests only on the starting point of the + selection. That is, at best, about 25 bits of unguessability in this + case. + + The same argument applies to selecting sequences from the data on a + CD ROM or Audio CD recording or any other large public database. If + the adversary has access to the same database, this "selection from a + + + +Eastlake, Crocker & Schiller [Page 9] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + large volume of data" step buys very little. However, if a selection + can be made from data to which the adversary has no access, such as + system buffers on an active multi-user system, it may be of some + help. + +5. Hardware for Randomness + + Is there any hope for strong portable randomness in the future? + There might be. All that's needed is a physical source of + unpredictable numbers. + + A thermal noise or radioactive decay source and a fast, free-running + oscillator would do the trick directly [GIFFORD]. This is a trivial + amount of hardware, and could easily be included as a standard part + of a computer system's architecture. Furthermore, any system with a + spinning disk or the like has an adequate source of randomness + [DAVIS]. All that's needed is the common perception among computer + vendors that this small additional hardware and the software to + access it is necessary and useful. + +5.1 Volume Required + + How much unpredictability is needed? Is it possible to quantify the + requirement in, say, number of random bits per second? + + The answer is not very much is needed. For DES, the key is 56 bits + and, as we show in an example in Section 8, even the highest security + system is unlikely to require a keying material of over 200 bits. If + a series of keys are needed, it can be generated from a strong random + seed using a cryptographically strong sequence as explained in + Section 6.3. A few hundred random bits generated once a day would be + enough using such techniques. Even if the random bits are generated + as slowly as one per second and it is not possible to overlap the + generation process, it should be tolerable in high security + applications to wait 200 seconds occasionally. + + These numbers are trivial to achieve. It could be done by a person + repeatedly tossing a coin. Almost any hardware process is likely to + be much faster. + +5.2 Sensitivity to Skew + + Is there any specific requirement on the shape of the distribution of + the random numbers? The good news is the distribution need not be + uniform. All that is needed is a conservative estimate of how non- + uniform it is to bound performance. Two simple techniques to de-skew + the bit stream are given below and stronger techniques are mentioned + in Section 6.1.2 below. + + + +Eastlake, Crocker & Schiller [Page 10] + +RFC 1750 Randomness Recommendations for Security December 1994 + + +5.2.1 Using Stream Parity to De-Skew + + Consider taking a sufficiently long string of bits and map the string + to "zero" or "one". The mapping will not yield a perfectly uniform + distribution, but it can be as close as desired. One mapping that + serves the purpose is to take the parity of the string. This has the + advantages that it is robust across all degrees of skew up to the + estimated maximum skew and is absolutely trivial to implement in + hardware. + + The following analysis gives the number of bits that must be sampled: + + Suppose the ratio of ones to zeros is 0.5 + e : 0.5 - e, where e is + between 0 and 0.5 and is a measure of the "eccentricity" of the + distribution. Consider the distribution of the parity function of N + bit samples. The probabilities that the parity will be one or zero + will be the sum of the odd or even terms in the binomial expansion of + (p + q)^N, where p = 0.5 + e, the probability of a one, and q = 0.5 - + e, the probability of a zero. + + These sums can be computed easily as + + N N + 1/2 * ( ( p + q ) + ( p - q ) ) + and + N N + 1/2 * ( ( p + q ) - ( p - q ) ). + + (Which one corresponds to the probability the parity will be 1 + depends on whether N is odd or even.) + + Since p + q = 1 and p - q = 2e, these expressions reduce to + + N + 1/2 * [1 + (2e) ] + and + N + 1/2 * [1 - (2e) ]. + + Neither of these will ever be exactly 0.5 unless e is zero, but we + can bring them arbitrarily close to 0.5. If we want the + probabilities to be within some delta d of 0.5, i.e. then + + N + ( 0.5 + ( 0.5 * (2e) ) ) < 0.5 + d. + + + + + + +Eastlake, Crocker & Schiller [Page 11] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + Solving for N yields N > log(2d)/log(2e). (Note that 2e is less than + 1, so its log is negative. Division by a negative number reverses + the sense of an inequality.) + + The following table gives the length of the string which must be + sampled for various degrees of skew in order to come within 0.001 of + a 50/50 distribution. + + +---------+--------+-------+ + | Prob(1) | e | N | + +---------+--------+-------+ + | 0.5 | 0.00 | 1 | + | 0.6 | 0.10 | 4 | + | 0.7 | 0.20 | 7 | + | 0.8 | 0.30 | 13 | + | 0.9 | 0.40 | 28 | + | 0.95 | 0.45 | 59 | + | 0.99 | 0.49 | 308 | + +---------+--------+-------+ + + The last entry shows that even if the distribution is skewed 99% in + favor of ones, the parity of a string of 308 samples will be within + 0.001 of a 50/50 distribution. + +5.2.2 Using Transition Mappings to De-Skew + + Another technique, originally due to von Neumann [VON NEUMANN], is to + examine a bit stream as a sequence of non-overlapping pairs. You + could then discard any 00 or 11 pairs found, interpret 01 as a 0 and + 10 as a 1. Assume the probability of a 1 is 0.5+e and the + probability of a 0 is 0.5-e where e is the eccentricity of the source + and described in the previous section. Then the probability of each + pair is as follows: + + +------+-----------------------------------------+ + | pair | probability | + +------+-----------------------------------------+ + | 00 | (0.5 - e)^2 = 0.25 - e + e^2 | + | 01 | (0.5 - e)*(0.5 + e) = 0.25 - e^2 | + | 10 | (0.5 + e)*(0.5 - e) = 0.25 - e^2 | + | 11 | (0.5 + e)^2 = 0.25 + e + e^2 | + +------+-----------------------------------------+ + + This technique will completely eliminate any bias but at the expense + of taking an indeterminate number of input bits for any particular + desired number of output bits. The probability of any particular + pair being discarded is 0.5 + 2e^2 so the expected number of input + bits to produce X output bits is X/(0.25 - e^2). + + + +Eastlake, Crocker & Schiller [Page 12] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + This technique assumes that the bits are from a stream where each bit + has the same probability of being a 0 or 1 as any other bit in the + stream and that bits are not correlated, i.e., that the bits are + identical independent distributions. If alternate bits were from two + correlated sources, for example, the above analysis breaks down. + + The above technique also provides another illustration of how a + simple statistical analysis can mislead if one is not always on the + lookout for patterns that could be exploited by an adversary. If the + algorithm were mis-read slightly so that overlapping successive bits + pairs were used instead of non-overlapping pairs, the statistical + analysis given is the same; however, instead of provided an unbiased + uncorrelated series of random 1's and 0's, it instead produces a + totally predictable sequence of exactly alternating 1's and 0's. + +5.2.3 Using FFT to De-Skew + + When real world data consists of strongly biased or correlated bits, + it may still contain useful amounts of randomness. This randomness + can be extracted through use of the discrete Fourier transform or its + optimized variant, the FFT. + + Using the Fourier transform of the data, strong correlations can be + discarded. If adequate data is processed and remaining correlations + decay, spectral lines approaching statistical independence and + normally distributed randomness can be produced [BRILLINGER]. + +5.2.4 Using Compression to De-Skew + + Reversible compression techniques also provide a crude method of de- + skewing a skewed bit stream. This follows directly from the + definition of reversible compression and the formula in Section 2 + above for the amount of information in a sequence. Since the + compression is reversible, the same amount of information must be + present in the shorter output than was present in the longer input. + By the Shannon information equation, this is only possible if, on + average, the probabilities of the different shorter sequences are + more uniformly distributed than were the probabilities of the longer + sequences. Thus the shorter sequences are de-skewed relative to the + input. + + However, many compression techniques add a somewhat predicatable + preface to their output stream and may insert such a sequence again + periodically in their output or otherwise introduce subtle patterns + of their own. They should be considered only a rough technique + compared with those described above or in Section 6.1.2. At a + minimum, the beginning of the compressed sequence should be skipped + and only later bits used for applications requiring random bits. + + + +Eastlake, Crocker & Schiller [Page 13] + +RFC 1750 Randomness Recommendations for Security December 1994 + + +5.3 Existing Hardware Can Be Used For Randomness + + As described below, many computers come with hardware that can, with + care, be used to generate truly random quantities. + +5.3.1 Using Existing Sound/Video Input + + Increasingly computers are being built with inputs that digitize some + real world analog source, such as sound from a microphone or video + input from a camera. Under appropriate circumstances, such input can + provide reasonably high quality random bits. The "input" from a + sound digitizer with no source plugged in or a camera with the lens + cap on, if the system has enough gain to detect anything, is + essentially thermal noise. + + For example, on a SPARCstation, one can read from the /dev/audio + device with nothing plugged into the microphone jack. Such data is + essentially random noise although it should not be trusted without + some checking in case of hardware failure. It will, in any case, + need to be de-skewed as described elsewhere. + + Combining this with compression to de-skew one can, in UNIXese, + generate a huge amount of medium quality random data by doing + + cat /dev/audio | compress - >random-bits-file + +5.3.2 Using Existing Disk Drives + + Disk drives have small random fluctuations in their rotational speed + due to chaotic air turbulence [DAVIS]. By adding low level disk seek + time instrumentation to a system, a series of measurements can be + obtained that include this randomness. Such data is usually highly + correlated so that significant processing is needed, including FFT + (see section 5.2.3). Nevertheless experimentation has shown that, + with such processing, disk drives easily produce 100 bits a minute or + more of excellent random data. + + Partly offsetting this need for processing is the fact that disk + drive failure will normally be rapidly noticed. Thus, problems with + this method of random number generation due to hardware failure are + very unlikely. + +6. Recommended Non-Hardware Strategy + + What is the best overall strategy for meeting the requirement for + unguessable random numbers in the absence of a reliable hardware + source? It is to obtain random input from a large number of + uncorrelated sources and to mix them with a strong mixing function. + + + +Eastlake, Crocker & Schiller [Page 14] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + Such a function will preserve the randomness present in any of the + sources even if other quantities being combined are fixed or easily + guessable. This may be advisable even with a good hardware source as + hardware can also fail, though this should be weighed against any + increase in the chance of overall failure due to added software + complexity. + +6.1 Mixing Functions + + A strong mixing function is one which combines two or more inputs and + produces an output where each output bit is a different complex non- + linear function of all the input bits. On average, changing any + input bit will change about half the output bits. But because the + relationship is complex and non-linear, no particular output bit is + guaranteed to change when any particular input bit is changed. + + Consider the problem of converting a stream of bits that is skewed + towards 0 or 1 to a shorter stream which is more random, as discussed + in Section 5.2 above. This is simply another case where a strong + mixing function is desired, mixing the input bits to produce a + smaller number of output bits. The technique given in Section 5.2.1 + of using the parity of a number of bits is simply the result of + successively Exclusive Or'ing them which is examined as a trivial + mixing function immediately below. Use of stronger mixing functions + to extract more of the randomness in a stream of skewed bits is + examined in Section 6.1.2. + +6.1.1 A Trivial Mixing Function + + A trivial example for single bit inputs is the Exclusive Or function, + which is equivalent to addition without carry, as show in the table + below. This is a degenerate case in which the one output bit always + changes for a change in either input bit. But, despite its + simplicity, it will still provide a useful illustration. + + +-----------+-----------+----------+ + | input 1 | input 2 | output | + +-----------+-----------+----------+ + | 0 | 0 | 0 | + | 0 | 1 | 1 | + | 1 | 0 | 1 | + | 1 | 1 | 0 | + +-----------+-----------+----------+ + + If inputs 1 and 2 are uncorrelated and combined in this fashion then + the output will be an even better (less skewed) random bit than the + inputs. If we assume an "eccentricity" e as defined in Section 5.2 + above, then the output eccentricity relates to the input eccentricity + + + +Eastlake, Crocker & Schiller [Page 15] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + as follows: + + e = 2 * e * e + output input 1 input 2 + + Since e is never greater than 1/2, the eccentricity is always + improved except in the case where at least one input is a totally + skewed constant. This is illustrated in the following table where + the top and left side values are the two input eccentricities and the + entries are the output eccentricity: + + +--------+--------+--------+--------+--------+--------+--------+ + | e | 0.00 | 0.10 | 0.20 | 0.30 | 0.40 | 0.50 | + +--------+--------+--------+--------+--------+--------+--------+ + | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | 0.00 | + | 0.10 | 0.00 | 0.02 | 0.04 | 0.06 | 0.08 | 0.10 | + | 0.20 | 0.00 | 0.04 | 0.08 | 0.12 | 0.16 | 0.20 | + | 0.30 | 0.00 | 0.06 | 0.12 | 0.18 | 0.24 | 0.30 | + | 0.40 | 0.00 | 0.08 | 0.16 | 0.24 | 0.32 | 0.40 | + | 0.50 | 0.00 | 0.10 | 0.20 | 0.30 | 0.40 | 0.50 | + +--------+--------+--------+--------+--------+--------+--------+ + + However, keep in mind that the above calculations assume that the + inputs are not correlated. If the inputs were, say, the parity of + the number of minutes from midnight on two clocks accurate to a few + seconds, then each might appear random if sampled at random intervals + much longer than a minute. Yet if they were both sampled and + combined with xor, the result would be zero most of the time. + +6.1.2 Stronger Mixing Functions + + The US Government Data Encryption Standard [DES] is an example of a + strong mixing function for multiple bit quantities. It takes up to + 120 bits of input (64 bits of "data" and 56 bits of "key") and + produces 64 bits of output each of which is dependent on a complex + non-linear function of all input bits. Other strong encryption + functions with this characteristic can also be used by considering + them to mix all of their key and data input bits. + + Another good family of mixing functions are the "message digest" or + hashing functions such as The US Government Secure Hash Standard + [SHS] and the MD2, MD4, MD5 [MD2, MD4, MD5] series. These functions + all take an arbitrary amount of input and produce an output mixing + all the input bits. The MD* series produce 128 bits of output and SHS + produces 160 bits. + + + + + + +Eastlake, Crocker & Schiller [Page 16] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + Although the message digest functions are designed for variable + amounts of input, DES and other encryption functions can also be used + to combine any number of inputs. If 64 bits of output is adequate, + the inputs can be packed into a 64 bit data quantity and successive + 56 bit keys, padding with zeros if needed, which are then used to + successively encrypt using DES in Electronic Codebook Mode [DES + MODES]. If more than 64 bits of output are needed, use more complex + mixing. For example, if inputs are packed into three quantities, A, + B, and C, use DES to encrypt A with B as a key and then with C as a + key to produce the 1st part of the output, then encrypt B with C and + then A for more output and, if necessary, encrypt C with A and then B + for yet more output. Still more output can be produced by reversing + the order of the keys given above to stretch things. The same can be + done with the hash functions by hashing various subsets of the input + data to produce multiple outputs. But keep in mind that it is + impossible to get more bits of "randomness" out than are put in. + + An example of using a strong mixing function would be to reconsider + the case of a string of 308 bits each of which is biased 99% towards + zero. The parity technique given in Section 5.2.1 above reduced this + to one bit with only a 1/1000 deviance from being equally likely a + zero or one. But, applying the equation for information given in + Section 2, this 308 bit sequence has 5 bits of information in it. + Thus hashing it with SHS or MD5 and taking the bottom 5 bits of the + result would yield 5 unbiased random bits as opposed to the single + bit given by calculating the parity of the string. + +6.1.3 Diffie-Hellman as a Mixing Function + + Diffie-Hellman exponential key exchange is a technique that yields a + shared secret between two parties that can be made computationally + infeasible for a third party to determine even if they can observe + all the messages between the two communicating parties. This shared + secret is a mixture of initial quantities generated by each of them + [D-H]. If these initial quantities are random, then the shared + secret contains the combined randomness of them both, assuming they + are uncorrelated. + +6.1.4 Using a Mixing Function to Stretch Random Bits + + While it is not necessary for a mixing function to produce the same + or fewer bits than its inputs, mixing bits cannot "stretch" the + amount of random unpredictability present in the inputs. Thus four + inputs of 32 bits each where there is 12 bits worth of + unpredicatability (such as 4,096 equally probable values) in each + input cannot produce more than 48 bits worth of unpredictable output. + The output can be expanded to hundreds or thousands of bits by, for + example, mixing with successive integers, but the clever adversary's + + + +Eastlake, Crocker & Schiller [Page 17] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + search space is still 2^48 possibilities. Furthermore, mixing to + fewer bits than are input will tend to strengthen the randomness of + the output the way using Exclusive Or to produce one bit from two did + above. + + The last table in Section 6.1.1 shows that mixing a random bit with a + constant bit with Exclusive Or will produce a random bit. While this + is true, it does not provide a way to "stretch" one random bit into + more than one. If, for example, a random bit is mixed with a 0 and + then with a 1, this produces a two bit sequence but it will always be + either 01 or 10. Since there are only two possible values, there is + still only the one bit of original randomness. + +6.1.5 Other Factors in Choosing a Mixing Function + + For local use, DES has the advantages that it has been widely tested + for flaws, is widely documented, and is widely implemented with + hardware and software implementations available all over the world + including source code available by anonymous FTP. The SHS and MD* + family are younger algorithms which have been less tested but there + is no particular reason to believe they are flawed. Both MD5 and SHS + were derived from the earlier MD4 algorithm. They all have source + code available by anonymous FTP [SHS, MD2, MD4, MD5]. + + DES and SHS have been vouched for the the US National Security Agency + (NSA) on the basis of criteria that primarily remain secret. While + this is the cause of much speculation and doubt, investigation of DES + over the years has indicated that NSA involvement in modifications to + its design, which originated with IBM, was primarily to strengthen + it. No concealed or special weakness has been found in DES. It is + almost certain that the NSA modification to MD4 to produce the SHS + similarly strengthened the algorithm, possibly against threats not + yet known in the public cryptographic community. + + DES, SHS, MD4, and MD5 are royalty free for all purposes. MD2 has + been freely licensed only for non-profit use in connection with + Privacy Enhanced Mail [PEM]. Between the MD* algorithms, some people + believe that, as with "Goldilocks and the Three Bears", MD2 is strong + but too slow, MD4 is fast but too weak, and MD5 is just right. + + Another advantage of the MD* or similar hashing algorithms over + encryption algorithms is that they are not subject to the same + regulations imposed by the US Government prohibiting the unlicensed + export or import of encryption/decryption software and hardware. The + same should be true of DES rigged to produce an irreversible hash + code but most DES packages are oriented to reversible encryption. + + + + + +Eastlake, Crocker & Schiller [Page 18] + +RFC 1750 Randomness Recommendations for Security December 1994 + + +6.2 Non-Hardware Sources of Randomness + + The best source of input for mixing would be a hardware randomness + such as disk drive timing affected by air turbulence, audio input + with thermal noise, or radioactive decay. However, if that is not + available there are other possibilities. These include system + clocks, system or input/output buffers, user/system/hardware/network + serial numbers and/or addresses and timing, and user input. + Unfortunately, any of these sources can produce limited or + predicatable values under some circumstances. + + Some of the sources listed above would be quite strong on multi-user + systems where, in essence, each user of the system is a source of + randomness. However, on a small single user system, such as a + typical IBM PC or Apple Macintosh, it might be possible for an + adversary to assemble a similar configuration. This could give the + adversary inputs to the mixing process that were sufficiently + correlated to those used originally as to make exhaustive search + practical. + + The use of multiple random inputs with a strong mixing function is + recommended and can overcome weakness in any particular input. For + example, the timing and content of requested "random" user keystrokes + can yield hundreds of random bits but conservative assumptions need + to be made. For example, assuming a few bits of randomness if the + inter-keystroke interval is unique in the sequence up to that point + and a similar assumption if the key hit is unique but assuming that + no bits of randomness are present in the initial key value or if the + timing or key value duplicate previous values. The results of mixing + these timings and characters typed could be further combined with + clock values and other inputs. + + This strategy may make practical portable code to produce good random + numbers for security even if some of the inputs are very weak on some + of the target systems. However, it may still fail against a high + grade attack on small single user systems, especially if the + adversary has ever been able to observe the generation process in the + past. A hardware based random source is still preferable. + +6.3 Cryptographically Strong Sequences + + In cases where a series of random quantities must be generated, an + adversary may learn some values in the sequence. In general, they + should not be able to predict other values from the ones that they + know. + + + + + + +Eastlake, Crocker & Schiller [Page 19] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + The correct technique is to start with a strong random seed, take + cryptographically strong steps from that seed [CRYPTO2, CRYPTO3], and + do not reveal the complete state of the generator in the sequence + elements. If each value in the sequence can be calculated in a fixed + way from the previous value, then when any value is compromised, all + future values can be determined. This would be the case, for + example, if each value were a constant function of the previously + used values, even if the function were a very strong, non-invertible + message digest function. + + It should be noted that if your technique for generating a sequence + of key values is fast enough, it can trivially be used as the basis + for a confidentiality system. If two parties use the same sequence + generating technique and start with the same seed material, they will + generate identical sequences. These could, for example, be xor'ed at + one end with data being send, encrypting it, and xor'ed with this + data as received, decrypting it due to the reversible properties of + the xor operation. + +6.3.1 Traditional Strong Sequences + + A traditional way to achieve a strong sequence has been to have the + values be produced by hashing the quantities produced by + concatenating the seed with successive integers or the like and then + mask the values obtained so as to limit the amount of generator state + available to the adversary. + + It may also be possible to use an "encryption" algorithm with a + random key and seed value to encrypt and feedback some or all of the + output encrypted value into the value to be encrypted for the next + iteration. Appropriate feedback techniques will usually be + recommended with the encryption algorithm. An example is shown below + where shifting and masking are used to combine the cypher output + feedback. This type of feedback is recommended by the US Government + in connection with DES [DES MODES]. + + + + + + + + + + + + + + + + +Eastlake, Crocker & Schiller [Page 20] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + +---------------+ + | V | + | | n | + +--+------------+ + | | +---------+ + | +---------> | | +-----+ + +--+ | Encrypt | <--- | Key | + | +-------- | | +-----+ + | | +---------+ + V V + +------------+--+ + | V | | + | n+1 | + +---------------+ + + Note that if a shift of one is used, this is the same as the shift + register technique described in Section 3 above but with the all + important difference that the feedback is determined by a complex + non-linear function of all bits rather than a simple linear or + polynomial combination of output from a few bit position taps. + + It has been shown by Donald W. Davies that this sort of shifted + partial output feedback significantly weakens an algorithm compared + will feeding all of the output bits back as input. In particular, + for DES, repeated encrypting a full 64 bit quantity will give an + expected repeat in about 2^63 iterations. Feeding back anything less + than 64 (and more than 0) bits will give an expected repeat in + between 2**31 and 2**32 iterations! + + To predict values of a sequence from others when the sequence was + generated by these techniques is equivalent to breaking the + cryptosystem or inverting the "non-invertible" hashing involved with + only partial information available. The less information revealed + each iteration, the harder it will be for an adversary to predict the + sequence. Thus it is best to use only one bit from each value. It + has been shown that in some cases this makes it impossible to break a + system even when the cryptographic system is invertible and can be + broken if all of each generated value was revealed. + +6.3.2 The Blum Blum Shub Sequence Generator + + Currently the generator which has the strongest public proof of + strength is called the Blum Blum Shub generator after its inventors + [BBS]. It is also very simple and is based on quadratic residues. + It's only disadvantage is that is is computationally intensive + compared with the traditional techniques give in 6.3.1 above. This + is not a serious draw back if it is used for moderately infrequent + purposes, such as generating session keys. + + + +Eastlake, Crocker & Schiller [Page 21] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + Simply choose two large prime numbers, say p and q, which both have + the property that you get a remainder of 3 if you divide them by 4. + Let n = p * q. Then you choose a random number x relatively prime to + n. The initial seed for the generator and the method for calculating + subsequent values are then + + 2 + s = ( x )(Mod n) + 0 + + 2 + s = ( s )(Mod n) + i+1 i + + You must be careful to use only a few bits from the bottom of each s. + It is always safe to use only the lowest order bit. If you use no + more than the + + log ( log ( s ) ) + 2 2 i + + low order bits, then predicting any additional bits from a sequence + generated in this manner is provable as hard as factoring n. As long + as the initial x is secret, you can even make n public if you want. + + An intersting characteristic of this generator is that you can + directly calculate any of the s values. In particular + + i + ( ( 2 )(Mod (( p - 1 ) * ( q - 1 )) ) ) + s = ( s )(Mod n) + i 0 + + This means that in applications where many keys are generated in this + fashion, it is not necessary to save them all. Each key can be + effectively indexed and recovered from that small index and the + initial s and n. + +7. Key Generation Standards + + Several public standards are now in place for the generation of keys. + Two of these are described below. Both use DES but any equally + strong or stronger mixing function could be substituted. + + + + + + + + +Eastlake, Crocker & Schiller [Page 22] + +RFC 1750 Randomness Recommendations for Security December 1994 + + +7.1 US DoD Recommendations for Password Generation + + The United States Department of Defense has specific recommendations + for password generation [DoD]. They suggest using the US Data + Encryption Standard [DES] in Output Feedback Mode [DES MODES] as + follows: + + use an initialization vector determined from + the system clock, + system ID, + user ID, and + date and time; + use a key determined from + system interrupt registers, + system status registers, and + system counters; and, + as plain text, use an external randomly generated 64 bit + quantity such as 8 characters typed in by a system + administrator. + + The password can then be calculated from the 64 bit "cipher text" + generated in 64-bit Output Feedback Mode. As many bits as are needed + can be taken from these 64 bits and expanded into a pronounceable + word, phrase, or other format if a human being needs to remember the + password. + +7.2 X9.17 Key Generation + + The American National Standards Institute has specified a method for + generating a sequence of keys as follows: + + s is the initial 64 bit seed + 0 + + g is the sequence of generated 64 bit key quantities + n + + k is a random key reserved for generating this key sequence + + t is the time at which a key is generated to as fine a resolution + as is available (up to 64 bits). + + DES ( K, Q ) is the DES encryption of quantity Q with key K + + + + + + + + +Eastlake, Crocker & Schiller [Page 23] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + g = DES ( k, DES ( k, t ) .xor. s ) + n n + + s = DES ( k, DES ( k, t ) .xor. g ) + n+1 n + + If g sub n is to be used as a DES key, then every eighth bit should + be adjusted for parity for that use but the entire 64 bit unmodified + g should be used in calculating the next s. + +8. Examples of Randomness Required + + Below are two examples showing rough calculations of needed + randomness for security. The first is for moderate security + passwords while the second assumes a need for a very high security + cryptographic key. + +8.1 Password Generation + + Assume that user passwords change once a year and it is desired that + the probability that an adversary could guess the password for a + particular account be less than one in a thousand. Further assume + that sending a password to the system is the only way to try a + password. Then the crucial question is how often an adversary can + try possibilities. Assume that delays have been introduced into a + system so that, at most, an adversary can make one password try every + six seconds. That's 600 per hour or about 15,000 per day or about + 5,000,000 tries in a year. Assuming any sort of monitoring, it is + unlikely someone could actually try continuously for a year. In + fact, even if log files are only checked monthly, 500,000 tries is + more plausible before the attack is noticed and steps taken to change + passwords and make it harder to try more passwords. + + To have a one in a thousand chance of guessing the password in + 500,000 tries implies a universe of at least 500,000,000 passwords or + about 2^29. Thus 29 bits of randomness are needed. This can probably + be achieved using the US DoD recommended inputs for password + generation as it has 8 inputs which probably average over 5 bits of + randomness each (see section 7.1). Using a list of 1000 words, the + password could be expressed as a three word phrase (1,000,000,000 + possibilities) or, using case insensitive letters and digits, six + would suffice ((26+10)^6 = 2,176,782,336 possibilities). + + For a higher security password, the number of bits required goes up. + To decrease the probability by 1,000 requires increasing the universe + of passwords by the same factor which adds about 10 bits. Thus to + have only a one in a million chance of a password being guessed under + the above scenario would require 39 bits of randomness and a password + + + +Eastlake, Crocker & Schiller [Page 24] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + that was a four word phrase from a 1000 word list or eight + letters/digits. To go to a one in 10^9 chance, 49 bits of randomness + are needed implying a five word phrase or ten letter/digit password. + + In a real system, of course, there are also other factors. For + example, the larger and harder to remember passwords are, the more + likely users are to write them down resulting in an additional risk + of compromise. + +8.2 A Very High Security Cryptographic Key + + Assume that a very high security key is needed for symmetric + encryption / decryption between two parties. Assume an adversary can + observe communications and knows the algorithm being used. Within + the field of random possibilities, the adversary can try key values + in hopes of finding the one in use. Assume further that brute force + trial of keys is the best the adversary can do. + +8.2.1 Effort per Key Trial + + How much effort will it take to try each key? For very high security + applications it is best to assume a low value of effort. Even if it + would clearly take tens of thousands of computer cycles or more to + try a single key, there may be some pattern that enables huge blocks + of key values to be tested with much less effort per key. Thus it is + probably best to assume no more than a couple hundred cycles per key. + (There is no clear lower bound on this as computers operate in + parallel on a number of bits and a poor encryption algorithm could + allow many keys or even groups of keys to be tested in parallel. + However, we need to assume some value and can hope that a reasonably + strong algorithm has been chosen for our hypothetical high security + task.) + + If the adversary can command a highly parallel processor or a large + network of work stations, 2*10^10 cycles per second is probably a + minimum assumption for availability today. Looking forward just a + couple years, there should be at least an order of magnitude + improvement. Thus assuming 10^9 keys could be checked per second or + 3.6*10^11 per hour or 6*10^13 per week or 2.4*10^14 per month is + reasonable. This implies a need for a minimum of 51 bits of + randomness in keys to be sure they cannot be found in a month. Even + then it is possible that, a few years from now, a highly determined + and resourceful adversary could break the key in 2 weeks (on average + they need try only half the keys). + + + + + + + +Eastlake, Crocker & Schiller [Page 25] + +RFC 1750 Randomness Recommendations for Security December 1994 + + +8.2.2 Meet in the Middle Attacks + + If chosen or known plain text and the resulting encrypted text are + available, a "meet in the middle" attack is possible if the structure + of the encryption algorithm allows it. (In a known plain text + attack, the adversary knows all or part of the messages being + encrypted, possibly some standard header or trailer fields. In a + chosen plain text attack, the adversary can force some chosen plain + text to be encrypted, possibly by "leaking" an exciting text that + would then be sent by the adversary over an encrypted channel.) + + An oversimplified explanation of the meet in the middle attack is as + follows: the adversary can half-encrypt the known or chosen plain + text with all possible first half-keys, sort the output, then half- + decrypt the encoded text with all the second half-keys. If a match + is found, the full key can be assembled from the halves and used to + decrypt other parts of the message or other messages. At its best, + this type of attack can halve the exponent of the work required by + the adversary while adding a large but roughly constant factor of + effort. To be assured of safety against this, a doubling of the + amount of randomness in the key to a minimum of 102 bits is required. + + The meet in the middle attack assumes that the cryptographic + algorithm can be decomposed in this way but we can not rule that out + without a deep knowledge of the algorithm. Even if a basic algorithm + is not subject to a meet in the middle attack, an attempt to produce + a stronger algorithm by applying the basic algorithm twice (or two + different algorithms sequentially) with different keys may gain less + added security than would be expected. Such a composite algorithm + would be subject to a meet in the middle attack. + + Enormous resources may be required to mount a meet in the middle + attack but they are probably within the range of the national + security services of a major nation. Essentially all nations spy on + other nations government traffic and several nations are believed to + spy on commercial traffic for economic advantage. + +8.2.3 Other Considerations + + Since we have not even considered the possibilities of special + purpose code breaking hardware or just how much of a safety margin we + want beyond our assumptions above, probably a good minimum for a very + high security cryptographic key is 128 bits of randomness which + implies a minimum key length of 128 bits. If the two parties agree + on a key by Diffie-Hellman exchange [D-H], then in principle only + half of this randomness would have to be supplied by each party. + However, there is probably some correlation between their random + inputs so it is probably best to assume that each party needs to + + + +Eastlake, Crocker & Schiller [Page 26] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + provide at least 96 bits worth of randomness for very high security + if Diffie-Hellman is used. + + This amount of randomness is beyond the limit of that in the inputs + recommended by the US DoD for password generation and could require + user typing timing, hardware random number generation, or other + sources. + + It should be noted that key length calculations such at those above + are controversial and depend on various assumptions about the + cryptographic algorithms in use. In some cases, a professional with + a deep knowledge of code breaking techniques and of the strength of + the algorithm in use could be satisfied with less than half of the + key size derived above. + +9. Conclusion + + Generation of unguessable "random" secret quantities for security use + is an essential but difficult task. + + We have shown that hardware techniques to produce such randomness + would be relatively simple. In particular, the volume and quality + would not need to be high and existing computer hardware, such as + disk drives, can be used. Computational techniques are available to + process low quality random quantities from multiple sources or a + larger quantity of such low quality input from one source and produce + a smaller quantity of higher quality, less predictable key material. + In the absence of hardware sources of randomness, a variety of user + and software sources can frequently be used instead with care; + however, most modern systems already have hardware, such as disk + drives or audio input, that could be used to produce high quality + randomness. + + Once a sufficient quantity of high quality seed key material (a few + hundred bits) is available, strong computational techniques are + available to produce cryptographically strong sequences of + unpredicatable quantities from this seed material. + +10. Security Considerations + + The entirety of this document concerns techniques and recommendations + for generating unguessable "random" quantities for use as passwords, + cryptographic keys, and similar security uses. + + + + + + + + +Eastlake, Crocker & Schiller [Page 27] + +RFC 1750 Randomness Recommendations for Security December 1994 + + +References + + [ASYMMETRIC] - Secure Communications and Asymmetric Cryptosystems, + edited by Gustavus J. Simmons, AAAS Selected Symposium 69, Westview + Press, Inc. + + [BBS] - A Simple Unpredictable Pseudo-Random Number Generator, SIAM + Journal on Computing, v. 15, n. 2, 1986, L. Blum, M. Blum, & M. Shub. + + [BRILLINGER] - Time Series: Data Analysis and Theory, Holden-Day, + 1981, David Brillinger. + + [CRC] - C.R.C. Standard Mathematical Tables, Chemical Rubber + Publishing Company. + + [CRYPTO1] - Cryptography: A Primer, A Wiley-Interscience Publication, + John Wiley & Sons, 1981, Alan G. Konheim. + + [CRYPTO2] - Cryptography: A New Dimension in Computer Data Security, + A Wiley-Interscience Publication, John Wiley & Sons, 1982, Carl H. + Meyer & Stephen M. Matyas. + + [CRYPTO3] - Applied Cryptography: Protocols, Algorithms, and Source + Code in C, John Wiley & Sons, 1994, Bruce Schneier. + + [DAVIS] - Cryptographic Randomness from Air Turbulence in Disk + Drives, Advances in Cryptology - Crypto '94, Springer-Verlag Lecture + Notes in Computer Science #839, 1984, Don Davis, Ross Ihaka, and + Philip Fenstermacher. + + [DES] - Data Encryption Standard, United States of America, + Department of Commerce, National Institute of Standards and + Technology, Federal Information Processing Standard (FIPS) 46-1. + - Data Encryption Algorithm, American National Standards Institute, + ANSI X3.92-1981. + (See also FIPS 112, Password Usage, which includes FORTRAN code for + performing DES.) + + [DES MODES] - DES Modes of Operation, United States of America, + Department of Commerce, National Institute of Standards and + Technology, Federal Information Processing Standard (FIPS) 81. + - Data Encryption Algorithm - Modes of Operation, American National + Standards Institute, ANSI X3.106-1983. + + [D-H] - New Directions in Cryptography, IEEE Transactions on + Information Technology, November, 1976, Whitfield Diffie and Martin + E. Hellman. + + + + +Eastlake, Crocker & Schiller [Page 28] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + [DoD] - Password Management Guideline, United States of America, + Department of Defense, Computer Security Center, CSC-STD-002-85. + (See also FIPS 112, Password Usage, which incorporates CSC-STD-002-85 + as one of its appendices.) + + [GIFFORD] - Natural Random Number, MIT/LCS/TM-371, September 1988, + David K. Gifford + + [KNUTH] - The Art of Computer Programming, Volume 2: Seminumerical + Algorithms, Chapter 3: Random Numbers. Addison Wesley Publishing + Company, Second Edition 1982, Donald E. Knuth. + + [KRAWCZYK] - How to Predict Congruential Generators, Journal of + Algorithms, V. 13, N. 4, December 1992, H. Krawczyk + + [MD2] - The MD2 Message-Digest Algorithm, RFC1319, April 1992, B. + Kaliski + [MD4] - The MD4 Message-Digest Algorithm, RFC1320, April 1992, R. + Rivest + [MD5] - The MD5 Message-Digest Algorithm, RFC1321, April 1992, R. + Rivest + + [PEM] - RFCs 1421 through 1424: + - RFC 1424, Privacy Enhancement for Internet Electronic Mail: Part + IV: Key Certification and Related Services, 02/10/1993, B. Kaliski + - RFC 1423, Privacy Enhancement for Internet Electronic Mail: Part + III: Algorithms, Modes, and Identifiers, 02/10/1993, D. Balenson + - RFC 1422, Privacy Enhancement for Internet Electronic Mail: Part + II: Certificate-Based Key Management, 02/10/1993, S. Kent + - RFC 1421, Privacy Enhancement for Internet Electronic Mail: Part I: + Message Encryption and Authentication Procedures, 02/10/1993, J. Linn + + [SHANNON] - The Mathematical Theory of Communication, University of + Illinois Press, 1963, Claude E. Shannon. (originally from: Bell + System Technical Journal, July and October 1948) + + [SHIFT1] - Shift Register Sequences, Aegean Park Press, Revised + Edition 1982, Solomon W. Golomb. + + [SHIFT2] - Cryptanalysis of Shift-Register Generated Stream Cypher + Systems, Aegean Park Press, 1984, Wayne G. Barker. + + [SHS] - Secure Hash Standard, United States of American, National + Institute of Science and Technology, Federal Information Processing + Standard (FIPS) 180, April 1993. + + [STERN] - Secret Linear Congruential Generators are not + Cryptograhically Secure, Proceedings of IEEE STOC, 1987, J. Stern. + + + +Eastlake, Crocker & Schiller [Page 29] + +RFC 1750 Randomness Recommendations for Security December 1994 + + + [VON NEUMANN] - Various techniques used in connection with random + digits, von Neumann's Collected Works, Vol. 5, Pergamon Press, 1963, + J. von Neumann. + +Authors' Addresses + + Donald E. Eastlake 3rd + Digital Equipment Corporation + 550 King Street, LKG2-1/BB3 + Littleton, MA 01460 + + Phone: +1 508 486 6577(w) +1 508 287 4877(h) + EMail: dee@lkg.dec.com + + + Stephen D. Crocker + CyberCash Inc. + 2086 Hunters Crest Way + Vienna, VA 22181 + + Phone: +1 703-620-1222(w) +1 703-391-2651 (fax) + EMail: crocker@cybercash.com + + + Jeffrey I. Schiller + Massachusetts Institute of Technology + 77 Massachusetts Avenue + Cambridge, MA 02139 + + Phone: +1 617 253 0161(w) + EMail: jis@mit.edu + + + + + + + + + + + + + + + + + + + + +Eastlake, Crocker & Schiller [Page 30] + diff --git a/errors.c b/errors.c new file mode 100644 index 0000000..e0e7a20 --- /dev/null +++ b/errors.c @@ -0,0 +1,102 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include "errs.h" + +#ifdef CLISERV +# include +#endif + +/* +** routine that handles non-fatal system errors like calloc, open, etc. +*/ +void +err_sys(const char *string) +{ + +#ifndef CLISERV + perror(string); +#else + syslog (LOG_DEBUG, "%s: %s",string, (char *)strerror(errno)); +#endif +} + +/* +** routine that handles fatal system errors like calloc, open, etc. +*/ +void +err_sys_fatal(const char *string) +{ + +#ifndef CLISERV + perror(string); +#else + syslog (LOG_DEBUG, "%s: %s", string, (char *)strerror(errno)); + closelog(); + close(0); +#endif + exit (-1); +} + +/* +** routine that handles non-fatal application errors. +*/ +void +err_app(const char *string, const char * err) +{ +#ifndef CLISERV + fprintf (stderr, "%s: ", string); + fprintf (stderr, "%s\n", err); + fflush (stderr); +#else + syslog (LOG_DEBUG, "%s: %s",string, err); +#endif +} + +/* +** routine that handles fatal application errors. +*/ +void +err_app_fatal(const char *string, const char *err) +{ + +#ifndef CLISERV + fprintf (stderr, "%s: ", string); + fprintf (stderr, "%s\n", err); + fflush (stderr); +#else + syslog (LOG_DEBUG, "%s: %s",string, err); + closelog(); + close(0); +#endif + exit (-1); +} diff --git a/errs.h b/errs.h new file mode 100644 index 0000000..ce857ca --- /dev/null +++ b/errs.h @@ -0,0 +1,40 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef ERRS_H +#define ERRS_H 1 + +#include + +extern void err_sys(const char *string); +extern void err_sys_fatal(const char *string); +extern void err_app(const char *string, const char *err); +extern void err_app_fatal(const char *string, const char *err); + +#endif /* ERRS_H */ diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/mkinstalldirs b/mkinstalldirs new file mode 100755 index 0000000..4f58503 --- /dev/null +++ b/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# Created: 1993-05-16 +# Public domain + +# $Id: mkinstalldirs,v 1.13 1999/01/05 03:18:55 bje Exp $ + +errstatus=0 + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case "$pathcomp" in + -* ) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# mkinstalldirs ends here diff --git a/owntypes.h b/owntypes.h new file mode 100644 index 0000000..ee28646 --- /dev/null +++ b/owntypes.h @@ -0,0 +1,43 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef OWN_TYPES_H +#define OWN_TYPES_H 1 + +typedef unsigned char BYTE; +typedef unsigned int UINT; +typedef unsigned short USHORT; +typedef short int SHORT; +typedef int boolean; +typedef unsigned long int UINT32; + +#define TRUE 1 +#define FALSE 0 + +#endif /* OWN_TYPES_H */ diff --git a/perl/apgcli.pl b/perl/apgcli.pl new file mode 100755 index 0000000..4a10b98 --- /dev/null +++ b/perl/apgcli.pl @@ -0,0 +1,10 @@ +#!/usr/bin/perl -w +$host = "localhost"; +use IO::Socket; +$remote = IO::Socket::INET->new( + Proto => "tcp", + PeerAddr => $host, + PeerPort => "pwdgen(129)", + ) + or die "cannot connect to pwdgen port at $host"; +while ( <$remote> ) { print } diff --git a/pronpass.c b/pronpass.c new file mode 100644 index 0000000..5d02020 --- /dev/null +++ b/pronpass.c @@ -0,0 +1,2293 @@ +/* +** This module uses code from the NIST implementation of FIPS-181, +** but the algorythm is CHANGED and I think that I CAN +** copyright it. See copiright notes below. +*/ + +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include +#include +#include +#include +#include +#include +#include "pronpass.h" +#include "randpass.h" +#include "errs.h" + +struct unit +{ + char unit_code[5]; + USHORT 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 +}; + +/* +** gen_pron_pass 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 +gen_pron_pass (char *word, char *hyphenated_word, USHORT minlen, + USHORT maxlen, unsigned int pass_mode) +{ + + int pwlen; + + /* + * Check for minlen>maxlen. This is an error. + * and a length of 0. + */ + if (minlen > maxlen || minlen > 255 || maxlen > 255) + 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); + } + + /* + * Find password. + */ + pwlen = gen_word (word, hyphenated_word, get_random (minlen, maxlen), pass_mode); + 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. + */ +int +gen_word (char *word, char *hyphenated_word, USHORT pwlen, unsigned int pass_mode) +{ + USHORT word_length; + USHORT syllable_length; + char *new_syllable; + USHORT *syllable_units; + USHORT word_size; + USHORT word_place; + USHORT *word_units; + USHORT syllable_size; + UINT tries; + int ch_flag = FALSE; + + /* + * 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. + */ + if ( (word_units = (USHORT *) calloc (sizeof (USHORT), pwlen+1))==NULL || + (syllable_units = (USHORT *) calloc (sizeof (USHORT), pwlen+1))==NULL || + (new_syllable = (char *) calloc (sizeof (USHORT), pwlen+1)) ==NULL) + return(-1); + + /* + * Find syllables until the entire word is constructed. + */ + while (word_length < pwlen) + { + /* + * Get the syllable and find its length. + */ + (void) gen_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) + { + /* + ** Modify syllable for numeric or capital symbols required + ** Should be done after word quality check. + */ + if ( ((pass_mode & S_NB) > 0) && (syllable_length == 1)) + { + numerize(new_syllable); + ch_flag = TRUE; + } + if ( ( (pass_mode & S_CL) > 0) && (ch_flag != TRUE)) + capitalize(new_syllable); + ch_flag = FALSE; + /**/ + (void) strcpy (word, new_syllable); + (void) strcpy (hyphenated_word, new_syllable); + bzero ( (void *)new_syllable, (size_t)(pwlen * sizeof(USHORT)+1)); + } + else + { + /* + ** Modify syllable for numeric or capital symbols required + ** Should be done after word quality check. + */ + if ( ((pass_mode & S_NB) > 0) && (syllable_length == 1)) + { + numerize(new_syllable); + ch_flag = TRUE; + } + if ( ( (pass_mode & S_CL) > 0) && (ch_flag != TRUE)) + capitalize(new_syllable); + ch_flag = FALSE; + /**/ + (void) strcat (word, new_syllable); + (void) strcat (hyphenated_word, "-"); + (void) strcat (hyphenated_word, new_syllable); + bzero ( (void *)new_syllable, (size_t)(pwlen * sizeof(USHORT)+1)); + } + 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. + */ +boolean +improper_word (USHORT *units, USHORT word_size) +{ + USHORT unit_count; + boolean failure; + + failure = FALSE; + + for (unit_count = 0; !failure && (unit_count < word_size); + unit_count++) + { + /* + * Check for ILLEGAL_PAIR. This should have been caught + * for units within a syllable, but in some cases it + * would have gone unnoticed for units between syllables + * (e.g., when saved_unit's in gen_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. + */ +boolean +have_initial_y (USHORT *units, USHORT unit_size) +{ + USHORT unit_count; + USHORT vowel_count; + USHORT 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. + */ +boolean +have_final_split (USHORT *units, USHORT unit_size) +{ + USHORT unit_count; + USHORT 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". + */ +char * +gen_syllable (char *syllable, USHORT pwlen, USHORT *units_in_syllable, + USHORT *syllable_length) +{ + USHORT unit = 0; + SHORT current_unit = 0; + USHORT vowel_count = 0; + boolean rule_broken; + boolean want_vowel; + boolean want_another_unit; + UINT tries = 0; + USHORT last_unit = 0; + SHORT length_left = 0; + USHORT hold_saved_unit = 0; + static USHORT saved_unit; + static USHORT 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). + */ +boolean +illegal_placement (USHORT *units, USHORT pwlen) +{ + USHORT vowel_count; + USHORT unit_count; + boolean failure; + + vowel_count = 0; + failure = FALSE; + + for (unit_count = 0; !failure && (unit_count <= pwlen); + unit_count++) + { + if (unit_count >= 1) + { + /* + * Don't allow vowels to be split with consonants in + * a single syllable. If we find such a combination + * (except for the silent e) we have to discard the + * syllable). + */ + if ((!(rules[units[unit_count - 1]].flags & VOWEL) && + (rules[units[unit_count]].flags & VOWEL) && + !((rules[units[unit_count]].flags & NO_FINAL_SPLIT) && + (unit_count == pwlen)) && (vowel_count != 0)) || + /* + * Perform these checks when we have at least 3 units. + */ + ((unit_count >= 2) && + + /* + * Disallow 3 consecutive consonants. + */ + ((!(rules[units[unit_count - 2]].flags & VOWEL) && + !(rules[units[unit_count - 1]].flags & + VOWEL) && + !(rules[units[unit_count]].flags & + VOWEL)) || + + /* + * Disallow 3 consecutive vowels, where the first is + * not a y. + */ + (((rules[units[unit_count - 2]].flags & + VOWEL) && + !((rules[units[0]].flags & + ALTERNATE_VOWEL) && + (unit_count == 2))) && + (rules[units[unit_count - 1]].flags & + VOWEL) && + (rules[units[unit_count]].flags & + VOWEL))))) + failure = TRUE; + } + + /* + * Count the vowels in the syllable. As mentioned somewhere + * above, exclude the initial y of a syllable. Instead, + * treat it as a consonant. + */ + if ((rules[units[unit_count]].flags & VOWEL) && + !((rules[units[0]].flags & ALTERNATE_VOWEL) && + (unit_count == 0) && (pwlen != 0))) + vowel_count++; + } + + return (failure); +} + + + +/* + * This is the standard Random unit generating routine for + * gen_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 USHORT 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 USHORT 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. + */ +USHORT +random_unit (USHORT type) +{ + USHORT 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 (USHORT))-1)]; + else + /* + * Get any letter according to the English distribution. + */ + number = numbers[get_random (0, (sizeof (numbers) / sizeof (USHORT))-1)]; + return (number); +} + + +/* + * This routine should return a uniformly distributed Random number between + * minlen and maxlen inclusive. The Electronic Code Book form of CAST is + * used to produce the Random number. The inputs to CAST are the old pass- + * word and a pseudoRandom key generated according to the procedure out- + * lined in Appendix C of ANSI X9.17. +*/ + +USHORT +get_random (USHORT minlen, USHORT maxlen) +{ + USHORT ret = 0; + ret = minlen + (USHORT) randint ((int) (maxlen - minlen + 1)); + return (ret); +} + +/* +** This routine designed to modify sullable like this: +** adel ----> Adel +** dot ----> Dot +** etc. +*/ +void capitalize (char *syllable) +{ + char let[26] = + { + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'w', 'z' + }; + char clet[26] = + { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'W', 'Z' + }; + char tmp = 0x00; + int i = 0; + if ( randint(2) == TRUE) + { + bcopy ((void *)syllable, (void *)&tmp, sizeof(tmp)); + for(i=0; i < 26; i++) + if ( let[i] == tmp ) bcopy ((void *)&clet[i], (void *)syllable, 1); + } +} + +/* +** This routine designed to modify single-letter syllable like this: +** a ----> 1 or 2 or 3 etc. +** u ----> 1 or 2 or 3 etc. +** etc. +*/ +void numerize (char *syllable) +{ + char *tmp; + if ( (tmp = (char *)calloc(1, 4)) == NULL) + err_sys_fatal("calloc"); + if ( (randint(2) == TRUE) && (strlen (syllable) == 1) ) + { + sprintf(tmp, "%d", randint(10)); + bcopy ((void *)tmp, (void *)syllable, 1); + } + free ((void *)tmp); +} diff --git a/pronpass.h b/pronpass.h new file mode 100644 index 0000000..d660686 --- /dev/null +++ b/pronpass.h @@ -0,0 +1,86 @@ +/* +** This module uses code from the NIST implementation of FIPS-181, +** but the algorythm is CHANGED and I think that I CAN +** copyright it. See copiright notes below. +*/ + +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#ifndef PRONPASS_H +#define PRONPASS_H 1 + +#ifndef OWN_TYPES_H +#include "owntypes.h" +#endif /* OWN_TYPES_H */ + +#ifndef RND_H +#include "rnd.h" +#endif /* RND_H */ + +#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 + +extern int gen_pron_pass (char *word, char *hyphenated_word, USHORT minlen, + USHORT maxlen, unsigned int pass_mode); + +USHORT random_unit (USHORT type); +USHORT get_random (USHORT minlen, USHORT maxlen); +boolean have_initial_y (USHORT *units, USHORT unit_size); +boolean illegal_placement (USHORT *units, USHORT pwlen); +boolean improper_word (USHORT *units, USHORT word_size); +boolean have_final_split (USHORT *units, USHORT unit_size); +int gen_word (char *word, char *hyphenated_word, USHORT pwlen, + unsigned int pass_mode); +char *gen_syllable(char *syllable, USHORT pwlen, USHORT *units_in_syllable, + USHORT *syllable_length); +void capitalize (char *syllable); +void numerize (char *syllable); + +#endif /* PRONPASS_H */ diff --git a/randpass.c b/randpass.c new file mode 100644 index 0000000..366ea5a --- /dev/null +++ b/randpass.c @@ -0,0 +1,110 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +** randpass.c - Random password generation module of PWGEN program +*/ + +#include +#include +#include +#include +#include +#include "randpass.h" +#include "owntypes.h" +struct sym + { + char ch; + USHORT type; + }; +static struct sym smbl[94] = +{ + {'a', S_SL}, {'b', S_SL}, {'c', S_SL}, {'d', S_SL}, {'e', S_SL}, {'f', S_SL}, + {'g', S_SL}, {'h', S_SL}, {'i', S_SL}, {'j', S_SL}, {'k', S_SL}, {'l', S_SL}, + {'m', S_SL}, {'n', S_SL}, {'o', S_SL}, {'p', S_SL}, {'q', S_SL}, {'r', S_SL}, + {'s', S_SL}, {'t', S_SL}, {'u', S_SL}, {'v', S_SL}, {'w', S_SL}, {'x', S_SL}, + {'y', S_SL}, {'z', S_SL}, {'A', S_CL}, {'B', S_CL}, {'C', S_CL}, {'D', S_CL}, + {'E', S_CL}, {'F', S_CL}, {'G', S_CL}, {'H', S_CL}, {'I', S_CL}, {'I', S_CL}, + {'K', S_CL}, {'K', S_CL}, {'M', S_CL}, {'N', S_CL}, {'O', S_CL}, {'P', S_CL}, + {'Q', S_CL}, {'R', S_CL}, {'S', S_CL}, {'T', S_CL}, {'U', S_CL}, {'V', S_CL}, + {'W', S_CL}, {'X', S_CL}, {'Y', S_CL}, {'Z', S_CL}, {'1', S_NB}, {'2', S_NB}, + {'3', S_NB}, {'4', S_NB}, {'5', S_NB}, {'6', S_NB}, {'7', S_NB}, {'8', S_NB}, + {'9', S_NB}, {'0', S_NB}, {33 , S_SS}, {34 , S_SS|S_RS}, {35 , S_SS}, {36 , S_SS|S_RS}, + {37 , S_SS}, {38 , S_SS}, {39 , S_SS|S_RS}, {40 , S_SS}, {41 , S_SS}, {42 , S_SS}, + {43 , S_SS}, {44 , S_SS}, {45 , S_SS}, {46 , S_SS}, {47 , S_SS}, {58 , S_SS}, + {59 , S_SS}, {60 , S_SS}, {61 , S_SS}, {62 , S_SS}, {63 , S_SS|S_RS}, {64 , S_SS}, + {91 , S_SS}, {92 , S_SS|S_RS}, {93 , S_SS}, {94 , S_SS}, {95 , S_SS}, {96 , S_SS|S_RS}, + {123, S_SS}, {124, S_SS|S_RS}, {125, S_SS}, {126, S_SS} +}; + +/* +** gen_rand_pass - generates random password of specified type +*/ +int +gen_rand_pass (char *password_string, int minl, int maxl, unsigned int pass_mode) +{ + int i = 0; + int j = 0; + int length = 0; + char *str_pointer; + int random_weight[94]; + int max_weight = 0; + int max_weight_element_number = 0; + + if (minl > 256 || maxl > 256 || minl < 1 || maxl < 1 || minl > maxl) + return (-1); + for (i = 0; i <= 93; i++) random_weight[i] = 0; + length = minl + randint(maxl-minl+1); + str_pointer = password_string; + + for (i = 0; i < length; i++) + { +/* Asign random weight in weight array if mode is present*/ + for (j = 0; j <= 93 ; j++) +/*!!!*/ if ( ((pass_mode & smbl[j].type) > 0) && + !((pass_mode & smbl[j].type) == 0x12)) + random_weight[j] = 1 + randint(20000); + j = 0; +/* Find an element with maximum weight */ + for (j = 0; j <= 93; j++) + if (random_weight[j] > max_weight) + { + max_weight = random_weight[j]; + max_weight_element_number = j; + } +/* Get password symbol */ + *str_pointer = smbl[max_weight_element_number].ch; + str_pointer++; + max_weight = 0; + max_weight_element_number = 0; + for (j = 0; j <= 93; j++) random_weight[j] = 0; + } + *str_pointer = 0; + return (length); +} diff --git a/randpass.h b/randpass.h new file mode 100644 index 0000000..dcc6564 --- /dev/null +++ b/randpass.h @@ -0,0 +1,49 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +** randpass.h +*/ +#ifndef RANDPASS_H +#define RANDPASS_H 1 + +#ifndef RND_H +#include "rnd.h" +#endif + +#define S_NB 0x01 /* Numeric */ +#define S_SS 0x02 /* Special */ +#define S_CL 0x04 /* Capital */ +#define S_SL 0x08 /* Small */ +#define S_RS 0x10 /* Restricted Special*/ + +/* char gen_symbol(unsigned short int symbol_class); */ +extern int gen_rand_pass(char* password_string, int minl, + int maxl, unsigned int pass_mode); +#endif /* RANDPASS_H */ diff --git a/restrict.c b/restrict.c new file mode 100644 index 0000000..a24fba7 --- /dev/null +++ b/restrict.c @@ -0,0 +1,66 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +** restrict.c +*/ +#include +#include +#include +#include "restrict.h" + +/* +** Routine that checks if password exist in dictionary +** RETURN -1 - error +** 1 - password exist in dictionary +** 0 - password does not exist in dictionary +*/ +int +check_pass(char *pass, char *dict) +{ + FILE *dct; + char *string; + string = (char *) calloc(1,MAX_DICT_STRING_SIZE); + + /* + ** Open dict file an report of error + */ + if ( (dct = fopen(dict,"r")) == NULL) + return(-1); + + while ((fgets(string, MAX_DICT_STRING_SIZE, dct) != NULL)) + { + string = strtok (string," \t\n\0"); + if(strlen(string) != strlen(pass)) continue; + else if (strncmp(string, pass, strlen(pass)) == 0) return (1); + } + free ( (void *)string); + fclose (dct); + return (0); +} diff --git a/restrict.h b/restrict.h new file mode 100644 index 0000000..621821e --- /dev/null +++ b/restrict.h @@ -0,0 +1,41 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* +** restrict.h +*/ +#ifndef RESTRICT_H +#define RESTRICT_H 1 + +#define MAX_DICT_STRING_SIZE 255 +extern int check_pass(char * pass, char *dict); +extern int make_db_dict(char *dict, char *bddict); +extern int construct_db_name(char *plain_filename, char * dbname); + +#endif /* RESTRICT_H */ diff --git a/rnd.c b/rnd.c new file mode 100644 index 0000000..e86fd58 --- /dev/null +++ b/rnd.c @@ -0,0 +1,117 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include +#include +#include +#include "rnd.h" +#include "./cast/cast.h" + +UINT32 __rnd_seed[2]; /* Random Seed 2*32=64 */ + +/* +** randint(int n) - Produces a Random number from 0 to n-1 . +*/ +UINT +randint(int n) +{ + return ( (UINT)( x917cast_rnd() % (UINT32)n ) ); +} + +/* +** ANSI X9.17 pseudorandom generator that uses CAST algorithm instead of DES +** m = 1 +*/ +UINT32 +x917cast_rnd (void) +{ + struct timeval local_time; + UINT32 I[2] = {0L,0L}; + UINT32 I_plus_s[2] = {0L,0L}; + UINT32 Xi[2] = {0L,0L}; + UINT32 Xi_plus_I[2] = {0L,0L}; + cast_key ky; + +/********************************************************************** +* ENCRYPTION KEY HEX : 0x000102030405060708090A0B0C0D0E0F (128-bit) * +* YOU CAN CHANGE IT IF YOU WANT * +**********************************************************************/ +u8 ro_key[16] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, +0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}; +/********************************************************************** +* ENCRYPTION KEY HEX : 0x000102030405060708090A0B0C0D0E0F (128-bit) * +* YOU CAN CHANGE IT IF YOU WANT * +**********************************************************************/ + (void) gettimeofday (&local_time, 0); + cast_setkey(&ky, (u8*)&ro_key[0], 16); + cast_encrypt (&ky, (u8 *)&local_time, (u8*)&I[0]); /* I=Ek(D), D-time */ + I_plus_s[0] = I[0] ^ __rnd_seed[0]; /* I0 (+) s0 */ + I_plus_s[1] = I[1] ^ __rnd_seed[1]; /* I1 (+) s1 */ + cast_encrypt (&ky, (u8 *)&I_plus_s[0], (u8*)&Xi[0]); /* Xi=Ek( I (+) s ) */ + Xi_plus_I[0] = Xi[0] ^ I[0]; /* Xi0 (+) I0 */ + Xi_plus_I[1] = Xi[1] ^ I[1]; /* Xi1 (+) I1 */ + cast_encrypt (&ky, (u8 *)&Xi_plus_I[0], (u8*)&__rnd_seed[0]); /* s=Ek( Xi (+) I ) */ + return (Xi[0]); +} + +/* +** x917cast_setseed (UINT32 seed) - Initializes seed +** UINT32 seed - seed value +*/ +void +x917cast_setseed (UINT32 seed) +{ + FILE * dr; + UINT32 drs[2]; + + if ( (dr = fopen(APG_DEVRANDOM, "r")) != NULL) + { + (void) fread( (void *)&drs[0], 8, 1, dr); + __rnd_seed[0] = seed ^ drs[0]; + __rnd_seed[1] = seed ^ drs[1]; + (void) fclose(dr); + } + else if ( (dr = fopen(APG_DEVURANDOM, "r")) != NULL) + { + (void) fread( (void *)&drs[0], 8, 1, dr); + __rnd_seed[0] = seed ^ drs[0]; + __rnd_seed[1] = seed ^ drs[1]; + (void) fclose(dr); + } + else + { +#ifndef CLISERV + fprintf(stderr,"CAN NOT USE /dev/random TO GENERATE RANDOM SEED\n"); + fprintf(stderr,"USEING LOCAL TIME FOR SEED GENERATION !!!\n"); + fflush(stderr); +#endif /* CLISERV */ + __rnd_seed[0] = seed; + __rnd_seed[1] = seed; + } +} diff --git a/rnd.h b/rnd.h new file mode 100644 index 0000000..43399cc --- /dev/null +++ b/rnd.h @@ -0,0 +1,47 @@ +/* +** Copyright (c) 1999, 2000, 2001 +** Adel I. Mirzazhanov. All rights reserved +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1.Redistributions of source code must retain the above copyright notice, +** this list of conditions and the following disclaimer. +** 2.Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3.The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +** OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +** DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +** GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef RND_H +#define RND_H 1 + +#ifndef OWN_TYPES_H +#include "owntypes.h" +#endif /* OWN_TYPES_H */ + +extern UINT32 __rnd_seed[2]; + +#define RND_MX 0x7FFFFFFF +#define APG_DEVRANDOM "/dev/random" +#define APG_DEVURANDOM "/dev/urandom" + +extern void x917cast_setseed (UINT32 seed); +extern UINT randint (int n); +UINT32 x917cast_rnd (void); + +#endif /* RND_H */