⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fips.c

📁 fips181 一个很好的密码生成器
💻 C
📖 第 1 页 / 共 5 页
字号:
 /* 
  * Execute this upon startup.  This initializes the
  * environment, including seed'ing the random number
  * generator and loading the on-line dictionary.
  */
    if (!been_here_before)
    {
     been_here_before = TRUE;


#ifndef RAN_DEBUG
     set_seed(seed);
#endif
    }

 /* 
  * Check for minlen>maxlen.  This is an error.
  * and a length of 0.
  */
    if (minlen > maxlen)
     return (-1);

 /* 
  * Check for zero length words.  This is technically not an error,
  * so we take the short cut and return a null word and a length of
0.
  */
    if (maxlen == 0)
    {
     word[0] = '\0';
     hyphenated_word[0] = '\0';
     return (0);
    }

 /* 
  * Continue finding words until the criteria are satisfied.
  * The criteria are, if restrict is set, that if the word appears
  * as either a login name or as part of the on-line dictionary,
  * throw out the word and look for another.
  */
    loop_count = 0;

    do
    {
    /* 
     * Get a random word.  Its length is a random quantity
     * from with the limits specified in the call to
     * randomword().
     */
     pwlen = get_word (word, hyphenated_word, get_random (minlen,
maxlen));





     restrict = 0;

     loop_count++;
    }
    while (restrict && (loop_count <= MAX_UNACCEPTABLE));

    if (restrict)  {
     (void) fflush(stdout);
     (void) fprintf(stderr, "could not find acceptable random password\n");
     (void) fflush(stderr);
     exit(1);
    }

    return (pwlen);
}


/*
 * This is the routine that returns a random word -- as
 * yet unchecked against the passwd file or the dictionary.
 * It collects random syllables until a predetermined
 * word length is found.  If a retry threshold is reached,
 * another word is tried.  Given that the random number
 * generator is uniformly distributed, eventually a word
 * will be found if the retry limit is adequately large enough.
 */
static int
get_word (word, hyphenated_word, pwlen)
char   *word;
char   *hyphenated_word;
unsigned short int  pwlen;
{
    register unsigned short int word_length;
    register unsigned short int syllable_length;
    register char  *new_syllable;
    register unsigned short int *syllable_units;
    register unsigned short int word_size;
    register unsigned short int word_place;
    int unsigned short *word_units;
    int unsigned short  syllable_size;
    int unsigned    tries;

    /*
     * Keep count of retries.
     */
    tries = 0;

    /*
     * The length of the word in characters.
     */
    word_length = 0;

    /*
     * The length of the word in character units (each of which is
one or
     * two characters long.
     */
    word_size = 0;

    /*
     * Initialize the array storing the word units.  Since we know
the
     * length of the word, we only need one of that length.  This
method is
     * preferable to a static array, since it allows us flexibility
in
     * choosing arbitrarily long word lengths.  Since a word can
contain one
     * syllable, we should make syllable_units, the array holding
the
     * analogous units for an individual syllable, the same length. 
No
     * explicit rule limits the length of syllables, but digram
rules and
     * heuristics do so indirectly.
     */
    word_units =
     (unsigned short int *)
     calloc (sizeof (unsigned short int), pwlen);
    syllable_units =
     (unsigned short int *)
     calloc (sizeof (unsigned short int), pwlen);
    new_syllable =
     calloc (sizeof (unsigned short int), pwlen);

    /*
     * Find syllables until the entire word is constructed.
     */
    while (word_length < pwlen)
    {
     /*
      * Get the syllable and find its length.
      */
     (void) get_syllable (new_syllable, pwlen - word_length,
syllable_units, &syllable_size);
     syllable_length = strlen (new_syllable);

     /*
      * Append the syllable units to the word units.
      */
     for (word_place = 0; word_place <= syllable_size;
word_place++)
         word_units[word_size + word_place] =
syllable_units[word_place];
     word_size += syllable_size + 1;

     /* 
      * If the word has been improperly formed, throw out
      * the syllable.  The checks performed here are those
      * that must be formed on a word basis.  The other
      * tests are performed entirely within the syllable.
      * Otherwise, append the syllable to the word and
      * append the syllable to the hyphenated version of
      * the word.
      */
     if (improper_word (word_units, word_size) ||
          ((word_length == 0) &&
              have_initial_y (syllable_units, syllable_size)) ||
          ((word_length + syllable_length == pwlen) &&
              have_final_split (syllable_units, syllable_size)))
         word_size -= syllable_size + 1;
     else
     {
         if (word_length == 0)
         {
          (void) strcpy (word, new_syllable);
          (void) strcpy (hyphenated_word, new_syllable);
         }
         else
         {
          (void) strcat (word, new_syllable);
          (void) strcat (hyphenated_word, "-");
          (void) strcat (hyphenated_word, new_syllable);
         }
         word_length += syllable_length;
     }

       /* 
        * Keep track of the times we have tried to get
        * syllables.  If we have exceeded the threshold,
        * reinitialize the pwlen and word_size variables, clear
        * out the word arrays, and start from scratch.
        */
     tries++;
     if (tries > MAX_RETRIES)
     {
         word_length = 0;
         word_size = 0;
         tries = 0;
         (void) strcpy (word, "");
         (void) strcpy (hyphenated_word, "");
     }
    }

    /* 
     * The units arrays and syllable storage are internal to this
     * routine.  Since the caller has no need for them, we
     * release the space.
     */
    free ((char *) new_syllable);
    free ((char *) syllable_units);
    free ((char *) word_units);

    return ((int) word_length);
}



/*
 * Check that the word does not contain illegal combinations
 * that may span syllables.  Specifically, these are:
 *   1. An illegal pair of units between syllables.
 *   2. Three consecutive vowel units.
 *   3. Three consecutive consonant units.
 * The checks are made against units (1 or 2 letters), not against
 * the individual letters, so three consecutive units can have
 * the length of 6 at most.
 */
static boolean
improper_word (units, word_size)
register unsigned short int *units;
register unsigned short int word_size;
{
    register unsigned short int unit_count;
    register    boolean failure;

    failure = FALSE;

    for (unit_count = 0; !failure && (unit_count < word_size);
         unit_count++)
    {
     /* 
      * Check for ILLEGAL_PAIR.  This should have been caught
      * for units within a syllable, but in some cases it
      * would have gone unnoticed for units between syllables
      * (e.g., when saved_unit's in get_syllable() were not
      * used).
      */
     if ((unit_count != 0) &&
          (digram[units[unit_count - 1]][units[unit_count]] &
              ILLEGAL_PAIR))
         failure = TRUE;

     /* 
      * Check for consecutive vowels or consonants.  Because
      * the initial y of a syllable is treated as a consonant
      * rather than as a vowel, we exclude y from the first
      * vowel in the vowel test.  The only problem comes when
      * y ends a syllable and two other vowels start the next,
      * like fly-oint.  Since such words are still
      * pronounceable, we accept this.
      */
     if (!failure && (unit_count >= 2))
     {
         /*
          * Vowel check.
          */
         if ((((rules[units[unit_count - 2]].flags & VOWEL) &&
                   !(rules[units[unit_count - 2]].flags &
                    ALTERNATE_VOWEL)) &&
               (rules[units[unit_count - 1]].flags & VOWEL) &&
               (rules[units[unit_count]].flags & VOWEL)) ||
         /*
          * Consonant check.
          */
              (!(rules[units[unit_count - 2]].flags & VOWEL) &&
               !(rules[units[unit_count - 1]].flags & VOWEL) &&
               !(rules[units[unit_count]].flags & VOWEL)))
          failure = TRUE;
     }
    }

    return (failure);
}


/*
 * Treating y as a vowel is sometimes a problem.  Some words
 * get formed that look irregular.  One special group is when
 * y starts a word and is the only vowel in the first syllable.
 * The word ycl is one example.  We discard words like these.
 */
static boolean
have_initial_y (units, unit_size)
register unsigned short int *units;
register unsigned short int unit_size;
{
    register unsigned short int unit_count;
    register unsigned short int vowel_count;
    register unsigned short int normal_vowel_count;

    vowel_count = 0;
    normal_vowel_count = 0;

    for (unit_count = 0; unit_count <= unit_size; unit_count++)
     /*
      * Count vowels.
      */
     if (rules[units[unit_count]].flags & VOWEL)
     {
         vowel_count++;

         /*
          * Count the vowels that are not: 1. y, 2. at the start of
          * the word.
          */
         if (!(rules[units[unit_count]].flags & ALTERNATE_VOWEL)
||
              (unit_count != 0))
          normal_vowel_count++;
     }

    return ((vowel_count <= 1) && (normal_vowel_count == 0));
}


/*
 * Besides the problem with the letter y, there is one with
 * a silent e at the end of words, like face or nice.  We
 * allow this silent e, but we do not allow it as the only
 * vowel at the end of the word or syllables like ble will
 * be generated.
 */
static boolean
have_final_split (units, unit_size)
register unsigned short int *units;
register unsigned short int unit_size;
{
    register unsigned short int unit_count;
    register unsigned short int vowel_count;

    vowel_count = 0;

    /*
     *    Count all the vowels in the word.
     */
    for (unit_count = 0; unit_count <= unit_size; unit_count++)
     if (rules[units[unit_count]].flags & VOWEL)
         vowel_count++;

    /*
     * Return TRUE iff the only vowel was e, found at the end if
the
     * word.
     */
    return ((vowel_count == 1) &&
         (rules[units[unit_size]].flags & NO_FINAL_SPLIT));
}


/*
 * Generate next unit to password, making sure that it follows
 * these rules:
 *   1. Each syllable must contain exactly 1 or 2 consecutive
 *      vowels, where y is considered a vowel.
 *   2. Syllable end is determined as follows:
 *        a. Vowel is generated and previous unit is a
 *           consonant and syllable already has a vowel.  In
 *           this case, new syllable is started and already
 *           contains a vowel.
 *        b. A pair determined to be a "break" pair is encountered.
 *           In this case new syllable is started with second unit
 *           of this pair.
 *        c. End of password is encountered.
 *        d. "begin" pair is encountered legally.  New syllable is
 *           started with this pair.
 *        e. "end" pair is legally encountered.  New syllable has
 *           nothing yet.
 *   3. Try generating another unit if:
 *        a. third consecutive vowel and not y.
 *        b. "break" pair generated but no vowel yet in current
 *           or previous 2 units are "not_end".
 *        c. "begin" pair generated but no vowel in syllable
 *           preceding begin pair, or both previous 2 pairs are
 *          designated "not_end".
 *        d. "end" pair generated but no vowel 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -