view libtomcrypt/src/misc/pkcs5/pkcs_5_1.c @ 1499:2d450c1056e3

options: Complete the transition to numeric toggles (`#if') For the sake of review, this commit alters only the code; the affiliated comments within the source files also need to be updated, but doing so now would obscure the operational changes that have been made here. * All on/off options have been switched to the numeric `#if' variant; that is the only way to make this `default_options.h.in' thing work in a reasonable manner. * There is now some very minor compile-time checking of the user's choice of options. * NO_FAST_EXPTMOD doesn't seem to be used, so it has been removed. * ENABLE_USER_ALGO_LIST was supposed to be renamed DROPBEAR_USER_ALGO_LIST, and this commit completes that work. * DROPBEAR_FUZZ seems to be a relatively new, as-yet undocumented option, which was added by the following commit: commit 6e0b539e9ca0b5628c6c5a3d118ad6a2e79e8039 Author: Matt Johnston <[email protected]> Date: Tue May 23 22:29:21 2017 +0800 split out checkpubkey_line() separately It has now been added to `sysoptions.h' and defined as `0' by default. * The configuration option `DROPBEAR_PASSWORD_ENV' is no longer listed in `default_options.h.in'; it is no longer meant to be set by the user, and is instead left to be defined in `sysoptions.h' (where it was already being defined) as merely the name of the environment variable in question: DROPBEAR_PASSWORD To enable or disable use of that environment variable, the user must now toggle `DROPBEAR_USE_DROPBEAR_PASSWORD'. * The sFTP support is now toggled by setting `DROPBEAR_SFTPSERVER', and the path of the sFTP server program is set independently through the usual SFTPSERVER_PATH.
author Michael Witten <mfwitten@gmail.com>
date Thu, 20 Jul 2017 19:38:26 +0000
parents 6dba84798cd5
children
line wrap: on
line source

/* LibTomCrypt, modular cryptographic library -- Tom St Denis
 *
 * LibTomCrypt is a library that provides various cryptographic
 * algorithms in a highly modular and flexible manner.
 *
 * The library is free for all purposes without any express
 * guarantee it works.
 */
#include "tomcrypt.h"

/**
   @file pkcs_5_1.c
   PKCS #5, Algorithm #1, Tom St Denis
*/
#ifdef LTC_PKCS_5
/**
   Execute PKCS #5 v1 in strict or OpenSSL EVP_BytesToKey()-compat mode.

   PKCS#5 v1 specifies that the output key length can be no larger than
   the hash output length.  OpenSSL unilaterally extended that by repeating
   the hash process on a block-by-block basis for as long as needed to make
   bigger keys.  If you want to be compatible with KDF for e.g. "openssl enc",
   you'll want that.

   If you want strict PKCS behavior, turn openssl_compat off.  Or (more
   likely), use one of the convenience functions below.

   @param password         The password (or key)
   @param password_len     The length of the password (octet)
   @param salt             The salt (or nonce) which is 8 octets long
   @param iteration_count  The PKCS #5 v1 iteration count
   @param hash_idx         The index of the hash desired
   @param out              [out] The destination for this algorithm
   @param outlen           [in/out] The max size and resulting size of the algorithm output
   @param openssl_compat   [in] Whether or not to grow the key to the buffer size ala OpenSSL
   @return CRYPT_OK if successful
*/
static int _pkcs_5_alg1_common(const unsigned char *password,
                       unsigned long password_len,
                       const unsigned char *salt,
                       int iteration_count,  int hash_idx,
                       unsigned char *out,   unsigned long *outlen,
                       int openssl_compat)
{
   int err;
   unsigned long x;
   hash_state    *md;
   unsigned char *buf;
   /* Storage vars in case we need to support > hashsize (OpenSSL compat) */
   unsigned long block = 0, iter;
   /* How many bytes to put in the outbut buffer (convenience calc) */
   unsigned long outidx = 0, nb = 0;

   LTC_ARGCHK(password != NULL);
   LTC_ARGCHK(salt     != NULL);
   LTC_ARGCHK(out      != NULL);
   LTC_ARGCHK(outlen   != NULL);

   /* test hash IDX */
   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
      return err;
   }

   /* allocate memory */
   md  = XMALLOC(sizeof(hash_state));
   buf = XMALLOC(MAXBLOCKSIZE);
   if (md == NULL || buf == NULL) {
      if (md != NULL) {
         XFREE(md);
      }
      if (buf != NULL) {
         XFREE(buf);
      }
      return CRYPT_MEM;
   }

   while(block * hash_descriptor[hash_idx].hashsize < *outlen) {

      /* hash initial (maybe previous hash) + password + salt */
      if ((err = hash_descriptor[hash_idx].init(md)) != CRYPT_OK) {
          goto LBL_ERR;
      }
      /* in OpenSSL mode, we first hash the previous result for blocks 2-n */
      if (openssl_compat && block) {
          if ((err = hash_descriptor[hash_idx].process(md, buf, hash_descriptor[hash_idx].hashsize)) != CRYPT_OK) {
              goto LBL_ERR;
          }
      }
      if ((err = hash_descriptor[hash_idx].process(md, password, password_len)) != CRYPT_OK) {
          goto LBL_ERR;
      }
      if ((err = hash_descriptor[hash_idx].process(md, salt, 8)) != CRYPT_OK) {
          goto LBL_ERR;
      }
      if ((err = hash_descriptor[hash_idx].done(md, buf)) != CRYPT_OK) {
          goto LBL_ERR;
      }

      iter = iteration_count;
      while (--iter) {
         /* code goes here. */
         x = MAXBLOCKSIZE;
         if ((err = hash_memory(hash_idx, buf, hash_descriptor[hash_idx].hashsize, buf, &x)) != CRYPT_OK) {
            goto LBL_ERR;
         }
      }

      /* limit the size of the copy to however many bytes we have left in
         the output buffer (and how many bytes we have to copy) */
      outidx = block*hash_descriptor[hash_idx].hashsize;
      nb = hash_descriptor[hash_idx].hashsize;
      if(outidx+nb > *outlen)
          nb = *outlen - outidx;
      if(nb > 0)
          XMEMCPY(out+outidx, buf, nb);

      block++;
      if (!openssl_compat)
          break;
   }
   /* In strict mode, we always return the hashsize, in compat we filled it
      as much as was requested, so we leave it alone. */
   if(!openssl_compat)
      *outlen = hash_descriptor[hash_idx].hashsize;

   err = CRYPT_OK;
LBL_ERR:
#ifdef LTC_CLEAN_STACK
   zeromem(buf, MAXBLOCKSIZE);
   zeromem(md, sizeof(hash_state));
#endif

   XFREE(buf);
   XFREE(md);

   return err;
}

/**
   Execute PKCS #5 v1 - Strict mode (no OpenSSL-compatible extension)
   @param password         The password (or key)
   @param password_len     The length of the password (octet)
   @param salt             The salt (or nonce) which is 8 octets long
   @param iteration_count  The PKCS #5 v1 iteration count
   @param hash_idx         The index of the hash desired
   @param out              [out] The destination for this algorithm
   @param outlen           [in/out] The max size and resulting size of the algorithm output
   @return CRYPT_OK if successful
*/
int pkcs_5_alg1(const unsigned char *password, unsigned long password_len,
                const unsigned char *salt,
                int iteration_count,  int hash_idx,
                unsigned char *out,   unsigned long *outlen)
{
   return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
                             hash_idx, out, outlen, 0);
}

/**
   Execute PKCS #5 v1 - OpenSSL-extension-compatible mode

   Use this one if you need to derive keys as "openssl enc" does by default.
   OpenSSL (for better or worse), uses MD5 as the hash and iteration_count=1.
   @param password         The password (or key)
   @param password_len     The length of the password (octet)
   @param salt             The salt (or nonce) which is 8 octets long
   @param iteration_count  The PKCS #5 v1 iteration count
   @param hash_idx         The index of the hash desired
   @param out              [out] The destination for this algorithm
   @param outlen           [in/out] The max size and resulting size of the algorithm output
   @return CRYPT_OK if successful
*/
int pkcs_5_alg1_openssl(const unsigned char *password,
                        unsigned long password_len,
                        const unsigned char *salt,
                        int iteration_count,  int hash_idx,
                        unsigned char *out,   unsigned long *outlen)
{
   return _pkcs_5_alg1_common(password, password_len, salt, iteration_count,
                             hash_idx, out, outlen, 1);
}

#endif

/* ref:         $Format:%D$ */
/* git commit:  $Format:%H$ */
/* commit time: $Format:%ai$ */