Logo Search packages:      
Sourcecode: linux-fsl-imx51 version File versions  Download package

fsl_shw_hash.c

/*
 * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

/*!
 * @file fsl_shw_hash.c
 *
 * This file implements Cryptographic Hashing functions of the FSL SHW API
 * for Sahara.  This does not include HMAC.
 */

#include "sahara.h"
#include "sf_util.h"

#ifdef LINUX_KERNEL
EXPORT_SYMBOL(fsl_shw_hash);
#endif

/* REQ-S2LRD-PINTFC-API-BASIC-HASH-005 */
/*!
 * Hash a stream of data with a cryptographic hash algorithm.
 *
 * The flags in the @a hash_ctx control the operation of this function.
 *
 * Hashing functions work on 64 octets of message at a time.  Therefore, when
 * any partial hashing of a long message is performed, the message @a length of
 * each segment must be a multiple of 64.  When ready to
 * #FSL_HASH_FLAGS_FINALIZE the hash, the @a length may be any value.
 *
 * With the #FSL_HASH_FLAGS_INIT and #FSL_HASH_FLAGS_FINALIZE flags on, a
 * one-shot complete hash, including padding, will be performed.  The @a length
 * may be any value.
 *
 * The first octets of a data stream can be hashed by setting the
 * #FSL_HASH_FLAGS_INIT and #FSL_HASH_FLAGS_SAVE flags.  The @a length must be
 * a multiple of 64.
 *
 * The flag #FSL_HASH_FLAGS_LOAD is used to load a context previously saved by
 * #FSL_HASH_FLAGS_SAVE.  The two in combination will allow a (multiple-of-64
 * octets) 'middle sequence' of the data stream to be hashed with the
 * beginning.  The @a length must again be a multiple of 64.
 *
 * Since the flag #FSL_HASH_FLAGS_LOAD is used to load a context previously
 * saved by #FSL_HASH_FLAGS_SAVE, the #FSL_HASH_FLAGS_LOAD and
 * #FSL_HASH_FLAGS_FINALIZE flags, used together, can be used to finish the
 * stream.  The @a length may be any value.
 *
 * If the user program wants to do the padding for the hash, it can leave off
 * the #FSL_HASH_FLAGS_FINALIZE flag.  The @a length must then be a multiple of
 * 64 octets.
 *
 * @param      user_ctx  A user context from #fsl_shw_register_user().
 * @param[in,out] hash_ctx Hashing algorithm and state of the cipher.
 * @param      msg       Pointer to the data to be hashed.
 * @param      length    Length, in octets, of the @a msg.
 * @param[out] result    If not null, pointer to where to store the hash
 *                       digest.
 * @param      result_len Number of octets to store in @a result.
 *
 * @return    A return code of type #fsl_shw_return_t.
 */
00071 fsl_shw_return_t fsl_shw_hash(fsl_shw_uco_t * user_ctx,
                        fsl_shw_hco_t * hash_ctx,
                        const uint8_t * msg,
                        uint32_t length,
                        uint8_t * result, uint32_t result_len)
{
      SAH_SF_DCLS;
      unsigned ctx_flags = (hash_ctx->flags & (FSL_HASH_FLAGS_INIT
                                     | FSL_HASH_FLAGS_LOAD
                                     | FSL_HASH_FLAGS_SAVE
                                     | FSL_HASH_FLAGS_FINALIZE));

      SAH_SF_USER_CHECK();

      /* Reset expectations if user gets overly zealous. */
      if (result_len > hash_ctx->digest_length) {
            result_len = hash_ctx->digest_length;
      }

      /* Validate hash ctx flags.
       * Need INIT or LOAD but not both.
       * Need SAVE or digest ptr (both is ok).
       */
      if (((ctx_flags & (FSL_HASH_FLAGS_INIT | FSL_HASH_FLAGS_LOAD))
           == (FSL_HASH_FLAGS_INIT | FSL_HASH_FLAGS_LOAD))
          || ((ctx_flags & (FSL_HASH_FLAGS_INIT | FSL_HASH_FLAGS_LOAD)) == 0)
          || (!(ctx_flags & FSL_HASH_FLAGS_SAVE) && (result == NULL))) {
            ret = FSL_RETURN_BAD_FLAG_S;
            goto out;
      }

      if (ctx_flags & FSL_HASH_FLAGS_INIT) {
            sah_Oct_Str out_ptr;
            unsigned out_len;

            /* Create desc to perform the initial hashing operation */
            /* Desc. #8 w/INIT and algorithm */
            header = SAH_HDR_MDHA_SET_MODE_HASH
                ^ sah_insert_mdha_init
                ^ sah_insert_mdha_algorithm[hash_ctx->algorithm];

            /* If user wants one-shot, set padding operation. */
            if (ctx_flags & FSL_HASH_FLAGS_FINALIZE) {
                  header ^= sah_insert_mdha_pdata;
            }

            /* Determine where Digest will go - hash_ctx or result */
            if (ctx_flags & FSL_HASH_FLAGS_SAVE) {
                  out_ptr = (sah_Oct_Str) hash_ctx->context;
                  out_len = hash_ctx->context_register_length;
            } else {
                  out_ptr = result;
                  out_len = (result_len > hash_ctx->digest_length)
                      ? hash_ctx->digest_length : result_len;
            }

            DESC_IN_OUT(header, length, (sah_Oct_Str) msg, out_len,
                      out_ptr);
      } else {          /* not doing hash INIT */
            void *out_ptr;
            unsigned out_len;

            /*
             * Build two descriptors -- one to load in context/set mode, the
             * other to compute & retrieve hash/context value.
             *
             * First up - Desc. #6 to load context.
             */
            /* Desc. #8 w/algorithm */
            header = SAH_HDR_MDHA_SET_MODE_MD_KEY
                ^ sah_insert_mdha_algorithm[hash_ctx->algorithm];

            if (ctx_flags & FSL_HASH_FLAGS_FINALIZE) {
                  header ^= sah_insert_mdha_pdata;
            }

            /* Message Digest (in) */
            DESC_IN_IN(header,
                     hash_ctx->context_register_length,
                     (sah_Oct_Str) hash_ctx->context, 0, NULL);

            if (ctx_flags & FSL_HASH_FLAGS_SAVE) {
                  out_ptr = hash_ctx->context;
                  out_len = hash_ctx->context_register_length;
            } else {
                  out_ptr = result;
                  out_len = result_len;
            }

            /* Second -- run data through and retrieve ctx regs */
            /* Desc. #10 - no mode register with this. */
            header = SAH_HDR_MDHA_HASH;
            DESC_IN_OUT(header, length, (sah_Oct_Str) msg, out_len,
                      out_ptr);
      }                 /* else not INIT */

      /* Now that execution is rejoined, we can append another descriptor
         to extract the digest/context a second time, into the result. */
      if ((ctx_flags & FSL_HASH_FLAGS_SAVE)
          && (result != NULL) && (result_len != 0)) {

            header = SAH_HDR_MDHA_STORE_DIGEST;

            /* Message Digest (out) */
            DESC_IN_OUT(header, 0, NULL,
                      (result_len > hash_ctx->digest_length)
                      ? hash_ctx->digest_length : result_len, result);
      }

      SAH_SF_EXECUTE();

      out:
      SAH_SF_DESC_CLEAN();

      return ret;
}                       /* fsl_shw_hash() */

Generated by  Doxygen 1.6.0   Back to index