Hash Functions

Contents

Hash Functions#

Note

The MD5 algorithm is considered weak due to known attacks on it. The functionality remains in the library, but the implementation will no longer be optimized and no security patches will be applied. A more secure alternative is available: SHA-2. For more information, see Fast Collision Attack on MD5 (https://eprint.iacr.org/2013/170.pdf) and How to Break MD5 and Other Hash Functions (http://merlot.usc.edu/csac-f06/papers/Wang05a.pdf).

Functions described in this section apply hash algorithms to digesting streaming messages.

Usage model of the generalized hash functions is similar to the model explained below.

A primitive implementing a hash algorithm uses the state context IppsHashState as an operational vehicle to carry all necessary variables to manage the computation of the chaining digest value.

The following example illustrates how the application code can apply the implemented SHA-1 hash standard to digest the input message stream.

  1. Call the function HashGetSize to get the size required to configure the IppsHashState context.

  2. Ensure that the required memory space is properly allocated. With the allocated memory, call the HashInit function with the value of hashAlg equal to ippHashAlg_SHA1 to set up the initial context state with the SHA-1 specified initialization vectors.

  3. Keep calling the function HashUpdate to digest incoming message stream in the queue till its completion. To determine the current value of the digest, call HashGetTag between the two calls to HashUpdate.

  4. Call the function HashFinal to pad the partial block into a final SHA-1 message block and transform it into a 160-bit message digest value.

  5. Clean up secret data stored in the context.

  6. Call the operating system memory free service function to release the IppsSHA1StateIppsHashState context.

The IppsHashState context is position-dependent. The HashPack, HashUnpack functions transform this context to a position-independent form and vice versa.

Note

For memory-critical applications, consider using Reduced Memory Footprint Functions.

Note

Important

The crypto community does not consider SHA-1 or MD5 algorithms secure anymore.

Recommendation: use a more secure hash algorithm (for example, any algorithm from the SHA-2 family) instead of SHA-1 or MD5.

Examples#

  1. Usage of the hash API to digest a message with extendable output length (XOF) SHAKE128.

/*************************************************************************
* Copyright (C) 2025 Intel Corporation
*
* Licensed under the Apache License,  Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 	http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law  or agreed  to  in  writing,  software
* distributed under  the License  is  distributed  on  an  "AS IS"  BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the  specific  language  governing  permissions  and
* limitations under the License.
*************************************************************************/

/*!
  *
  *  \file
  *
  *  \brief XOF Hash example
  *
  *  This example demonstrates usage of Hash algorithms to digest a message with extendable output length.
  *  Reduced Memory Footprint (_rmf) API is used in this example.
  *
  */

#include <string.h>
#include <vector>

#include "ippcp.h"
#include "examples_common.h"

/* Message text */
const Ipp8u msg[] = "abc";

/* Known digest to check the results (189 bytes)*/
const Ipp8u shake128[] = "\x58\x81\x09\x2d\xd8\x18\xbf\x5c\xf8\xa3\xdd\xb7\x93\xfb\xcb\xa7\x40\x97"
                         "\xd5\xc5\x26\xa6\xd3\x5f\x97"
                         "\xb8\x33\x51\x94\x0f\x2c\xc8\x44\xc5\x0a\xf3\x2a\xcd\x3f\x2c\xdd\x06\x65"
                         "\x68\x70\x6f\x50\x9b\xc1\xbd"
                         "\xde\x58\x29\x5d\xae\x3f\x89\x1a\x9a\x0f\xca\x57\x83\x78\x9a\x41\xf8\x61"
                         "\x12\x14\xce\x61\x23\x94\xdf"
                         "\x28\x6a\x62\xd1\xa2\x25\x2a\xa9\x4d\xb9\xc5\x38\x95\x6c\x71\x7d\xc2\xbe"
                         "\xd4\xf2\x32\xa0\x29\x4c\x85"
                         "\x7c\x73\x0a\xa1\x60\x67\xac\x10\x62\xf1\x20\x1f\xb0\xd3\x77\xcf\xb9\xcd"
                         "\xe4\xc6\x35\x99\xb2\x7f\x34"
                         "\x62\xbb\xa4\xa0\xed\x29\x6c\x80\x1f\x9f\xf7\xf5\x73\x02\xbb\x30\x76\xee"
                         "\x14\x5f\x97\xa3\x2a\xe6\x8e"
                         "\x76\xab\x66\xc4\x8d\x51\x67\x5b\xd4\x9a\xcc\x29\x08\x2f\x56\x47\x58\x4e"
                         "\x6a\xa0\x1b\x3f\x5a\xf0\x57"
                         "\x80\x5f\x97\x3f\xf8\xec\xb8\xb2\x26\xac\x32\xad\xa6\xf0";

/* Message size in bytes */
const int msg_byte_len    = sizeof(msg) - 1;
const int digest_byte_len = sizeof(shake128) - 1;

int main(void)
{
    /* Internal function status */
    IppStatus status = ippStsNoErr;

    /* 1. Get the hash methods which is used
       Initially it is possible to pass a digest size smaller
       than it will be obtained with ippsHashSqueeze_rmf() */
    const int digest_size             = 10 * 8;
    const IppsHashMethod* hash_method = ippsHashMethod_SHAKE128(digest_size);

    /* The size of the SHAKE128 hash context structure. It will be set up in ippsHashGetSize_rmf(). */
    int context_size = 0;

    /* 2. Get the size needed for the SHAKE128 hash context structure */
    status = ippsHashGetSizeOptimal_rmf(&context_size, hash_method);
    if (!checkStatus("ippsHashGetSizeOptimal_rmf", ippStsNoErr, status)) {
        return status;
    }

    /* 3. Allocate memory for the SHAKE128 hash context structure */
    std::vector<Ipp8u> context_buffer(context_size);

    /* 4. Buffers for the digest and the tag */
    Ipp8u output_hash_buffer[digest_byte_len];
    IppsHashState_rmf* hash_state = (IppsHashState_rmf*)(context_buffer.data());

    /* 5. Initialize SHAKE128 hash context */
    status = ippsHashInit_rmf(hash_state, hash_method);
    if (!checkStatus("ippsHashInit_rmf", ippStsNoErr, status)) {
        return status;
    }

    /* 6. Call HashUpdate function to digest the message of the given length
       This function can be called multiple times for a stream of messages */
    status = ippsHashUpdate_rmf(msg, msg_byte_len, hash_state);
    if (!checkStatus("ippsHashUpdate_rmf", ippStsNoErr, status)) {
        return status;
    }

    const int digestLen = 3;

    for (int i = 0; i < digest_byte_len; i += digestLen) {
        /* 7. Squeeze the digestLen bytes of the digest value */
        status = ippsHashSqueeze_rmf(output_hash_buffer + i, digestLen, hash_state);
        if (!checkStatus("ippsHashSqueeze_rmf", ippStsNoErr, status)) {
            return status;
        }
        /* 8. Verify the resulted digest part with the known one */
        int check = memcmp(output_hash_buffer + i, shake128 + i, digestLen);
        if (check != 0) {
            printf("ERROR: Hash and the reference do not match\n");
            status = -1;
        }
    }

    /* 9. Verify the entire resulted digest with the known one */
    int check = memcmp(output_hash_buffer, shake128, digest_byte_len);
    if (check != 0) {
        printf("ERROR: Hash and the reference do not match\n");
        status = -1;
    }

    PRINT_EXAMPLE_STATUS("ippsHashUpdate_rmf", "XOF SHAKE128 Hash", !status)

    return status;
}
  1. Usage of the hash API to digest a message using SM3 standard.

/*************************************************************************
* Copyright (C) 2024 Intel Corporation
*
* Licensed under the Apache License,  Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 	http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law  or agreed  to  in  writing,  software
* distributed under  the License  is  distributed  on  an  "AS IS"  BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the  specific  language  governing  permissions  and
* limitations under the License.
*************************************************************************/

/*!
  *
  *  \file
  *
  *  \brief SM3 Hash example
  *
  *  This example demonstrates usage of Hash algorithms to digest a message by
  *  using SM3 standard.
  *  Reduce Memory Footprint (_rmf) APIs are used in this example.
  *
  */

#include <string.h>
#include <vector>

#include "ippcp.h"
#include "examples_common.h"

/*! Message text */
const Ipp8u msg[] = "abc";

/*! Known digest to check the results */
const Ipp8u sm3[] = "\x66\xc7\xf0\xf4\x62\xee\xed\xd9\xd1\xf2\xd4\x6b\xdc\x10\xe4\xe2"
                    "\x41\x67\xc4\x87\x5c\xf2\xf7\xa2\x29\x7d\xa0\x2b\x8f\x4b\xa8\xe0";

/*! Message size in bytes */
const int msg_byte_len = sizeof(msg) - 1;

int main(void)
{
    /*! Internal function status */
    IppStatus status = ippStsNoErr;

    /*! 1. Get the hash methods which is used */
    /* _TT (tick-tock) version of ippsHashMethod_SM3() function automatically switch on SM3 instructions, if possible*/
    const IppsHashMethod* hash_method = ippsHashMethod_SM3_TT();

    /*! The digest size of the SM3 standard */
    Ipp32u hash_size = IPP_SM3_DIGEST_BYTESIZE;

    /*! The size of the SM3 hash context structure. It will be set up in ippsHashGetSize_rmf(). */
    int context_size = 0;

    /*! 2. Get the size needed for the SM3 hash context structure */
    status = ippsHashGetSize_rmf(&context_size);
    if (!checkStatus("ippsHashGetSize_rmf", ippStsNoErr, status)) {
        return status;
    }

    /*! 3. Allocate memory for the SM3 hash context structure */
    std::vector<Ipp8u> context_buffer(context_size);

    /*! 4. Buffers for the digest and the tag */
    Ipp8u output_hash_buffer[IPP_SM3_DIGEST_BYTESIZE];

    IppsHashState_rmf* hash_state = (IppsHashState_rmf*)(context_buffer.data());

    /*! 5. Initialize the initial SM3 hash context */
    status = ippsHashInit_rmf(hash_state, hash_method);
    if (!checkStatus("ippsHashInit_rmf", ippStsNoErr, status)) {
        return status;
    }

    /*! 6. Call HashUpdate function to digest the message of the given length */
    /*! This function can be called multiple times for a stream of messages */
    status = ippsHashUpdate_rmf(msg, msg_byte_len, hash_state);
    if (!checkStatus("ippsHashUpdate_rmf", ippStsNoErr, status)) {
        return status;
    }

    /*! 7. Complete the computation of the digest value */
    status = ippsHashFinal_rmf(output_hash_buffer, hash_state);
    if (!checkStatus("ippsHashFinal_rmf", ippStsNoErr, status)) {
        return status;
    }

    /*! 8. Verify the resulted digest with the known one */
    int check = memcmp(output_hash_buffer, sm3, hash_size);
    if (check != 0) {
        printf("ERROR: Hash and the reference do not match\n");
        status = -1;
    }

    PRINT_EXAMPLE_STATUS("ippsHashUpdate_rmf", "SM3 Hash", !status)

    return status;
}

Related Information

Data Security Considerations