mbedtls | 03 - 单向散列算法的配置与使用(MD5、SHA1、SHA256、SHA512)

mbedtls系列文章



一、单向散列算法

1. 单向散列函数

单向散列函数是一类满足密码学算法安全属性的特殊散列函数,可以根据消息的内容计算出散列值,又称为安全散列函数或者哈希函数,通常用于检验消息完整性

输入数据称为消息,计算出的散列值称为消息摘要(摘要)

单向散列函数具有如下特点:

  • 输入长度任意;
  • 输出长度固定
  • 单向性:无法根据散列值还原出消息;

单向散列函数主要用在:

  • 消息完整性检测;
  • 构造伪随机数生成算法;
  • 消息认证码;
  • 数字签名;
  • 一次性口令;

2. 单向散列算法

单向散列算法是单向散列函数的实现,主要包括两大算法实现:MD4/5系列实现、SHA系列实现。

2.1. MD系列实现

MD系列算法最早是MD4,后来诞生了MD5,两者都可以产生128 bit 的散列值。

2.2. SHA系列算法

SHA系列算法由美国国家标准与技术研究所NIST确定,主要包含以下几个:

  • SHA0:1993年发布,可以产生160 bit 的消息摘要,但是存在重大缺陷被撤销;
  • SHA1:1995年发布,可以产生160 bit 的消息摘要,也存在缺陷(不推荐使用);
  • SHA2:包括SHA256算法、SHA384算法、SHA512算法;
  • SHA3:支持与SHA2相同的消息摘要长度,但是算法内部结构不同;

3. mbedtls中提供的单向散列算法

  • MD2
  • MD4
  • MD5
  • SHA1
  • SHA224
  • SHA256
  • SHA384
  • SHA512

二、功能模块的使用方法

1. 配置宏

mbedtls中提供的这些单向散列算法,每个都是一个独立的模块,由对应的宏控制是否开启

#define MBEDTLS_MD2_C
#define MBEDTLS_MD4_C
#define MBEDTLS_MD5_C
#define MBEDTLS_SHA1_C
#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C

在使用的时候,除了可以使用每个功能模块提供的API,还可以使用md通用接口,通过下面的宏开启:

/**
 * \def MBEDTLS_MD_C
 *
 * Enable the generic message digest layer.
 *
 * Module:  library/md.c
 * Caller:
 *
 * Uncomment to enable generic message digest wrappers.
 */
#define MBEDTLS_MD_C

在本实验中,我们准备测试SHA1、SHA256、SHA512三个算法,所以编写一个新的配置头文件mbedtls_config_sha_x.h,内容如下:

/**
 * @brief   Minimal configuration for SHAX Function
 * @author  mculover666
 * @date    2020/09/22
*/

#ifndef _MBEDTLS_CONFIG_SHA_X_H_
#define _MBEDTLS_CONFIG_SHA_X_H_

/* System support */
#define MBEDTLS_HAVE_ASM
//#define MBEDTLS_HAVE_TIME

/* mbed feature support */
#define MBEDTLS_NO_PLATFORM_ENTROPY

/* mbed modules */
//#define MBEDTLS_MD2_C
//#define MBEDTLS_MD4_C
//#define MBEDTLS_MD5_C
#define MBEDTLS_SHA1_C
//#define MBEDTLS_SHA224_C
#define MBEDTLS_SHA256_C
//#define MBEDTLS_SHA384_C
#define MBEDTLS_SHA512_C

/* enable generic message digest wrappers */
#define MBEDTLS_MD_C

#include "mbedtls/check_config.h"

#endif /* _MBEDTLS_CONFIG_SHA_X_H_ */

将工程中所使用的配置文件修改为此文件:

2. md通用接口API说明

头文件:

#include "mbedtls/md.h"

① 初始化MD结构体:

/**
 * \brief           This function initializes a message-digest context without
 *                  binding it to a particular message-digest algorithm.
 *
 *                  This function should always be called first. It prepares the
 *                  context for mbedtls_md_setup() for binding it to a
 *                  message-digest algorithm.
 */
void mbedtls_md_init( mbedtls_md_context_t *ctx );

② 根据算法类型得到md信息结构体指针:

/**
 * \brief           This function returns the message-digest information
 *                  associated with the given digest type.
 *
 * \param md_type   The type of digest to search for.
 *
 * \return          The message-digest information associated with \p md_type.
 * \return          NULL if the associated message-digest information is not found.
 */
const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type );

其中算法类型 mbedtls_md_type_t 是枚举类型,有以下值:

/**
 * \brief     Supported message digests.
 *
 * \warning   MD2, MD4, MD5 and SHA-1 are considered weak message digests and
 *            their use constitutes a security risk. We recommend considering
 *            stronger message digests instead.
 *
 */
typedef enum {
    MBEDTLS_MD_NONE=0,    /**< None. */
    MBEDTLS_MD_MD2,       /**< The MD2 message digest. */
    MBEDTLS_MD_MD4,       /**< The MD4 message digest. */
    MBEDTLS_MD_MD5,       /**< The MD5 message digest. */
    MBEDTLS_MD_SHA1,      /**< The SHA-1 message digest. */
    MBEDTLS_MD_SHA224,    /**< The SHA-224 message digest. */
    MBEDTLS_MD_SHA256,    /**< The SHA-256 message digest. */
    MBEDTLS_MD_SHA384,    /**< The SHA-384 message digest. */
    MBEDTLS_MD_SHA512,    /**< The SHA-512 message digest. */
    MBEDTLS_MD_RIPEMD160, /**< The RIPEMD-160 message digest. */
} mbedtls_md_type_t;

③ 设置md结构体,完成md结构体内部接口初始化:

/**
 * \brief           This function selects the message digest algorithm to use,
 *                  and allocates internal structures.
 *
 *                  It should be called after mbedtls_md_init() or
 *                  mbedtls_md_free(). Makes it necessary to call
 *                  mbedtls_md_free() later.
 *
 * \param ctx       The context to set up.
 * \param md_info   The information structure of the message-digest algorithm
 *                  to use.
 * \param hmac      Defines if HMAC is used. 0: HMAC is not used (saves some memory),
 *                  or non-zero: HMAC is used with this context.
 *
 * \return          \c 0 on success.
 * \return          #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
 *                  failure.
 * \return          #MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure.
 */
int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac );

④ 获取单向散列算法名称:

/**
 * \brief           This function extracts the message-digest name from the
 *                  message-digest information structure.
 *
 * \param md_info   The information structure of the message-digest algorithm
 *                  to use.
 *
 * \return          The name of the message digest.
 */
const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info );

⑤ 获取单向散列算法输出消息摘要的长度:

/**
 * \brief           This function extracts the message-digest size from the
 *                  message-digest information structure.
 *
 * \param md_info   The information structure of the message-digest algorithm
 *                  to use.
 *
 * \return          The size of the message-digest output in Bytes.
 */
unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info );

⑥ md启动接口:

/**
 * \brief           This function starts a message-digest computation.
 *
 *                  You must call this function after setting up the context
 *                  with mbedtls_md_setup(), and before passing data with
 *                  mbedtls_md_update().
 *
 * \param ctx       The generic message-digest context.
 *
 * \return          \c 0 on success.
 * \return          #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
 *                  failure.
 */
int mbedtls_md_starts( mbedtls_md_context_t *ctx );

⑦ md更新接口,处理输入数据,计算散列值:

/**
 * \brief           This function feeds an input buffer into an ongoing
 *                  message-digest computation.
 *
 *                  You must call mbedtls_md_starts() before calling this
 *                  function. You may call this function multiple times.
 *                  Afterwards, call mbedtls_md_finish().
 *
 * \param ctx       The generic message-digest context.
 * \param input     The buffer holding the input data.
 * \param ilen      The length of the input data.
 *
 * \return          \c 0 on success.
 * \return          #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
 *                  failure.
 */
int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen );

⑧ md完成接口:

/**
 * \brief           This function finishes the digest operation,
 *                  and writes the result to the output buffer.
 *
 *                  Call this function after a call to mbedtls_md_starts(),
 *                  followed by any number of calls to mbedtls_md_update().
 *                  Afterwards, you may either clear the context with
 *                  mbedtls_md_free(), or call mbedtls_md_starts() to reuse
 *                  the context for another digest operation with the same
 *                  algorithm.
 *
 * \param ctx       The generic message-digest context.
 * \param output    The buffer for the generic message-digest checksum result.
 *
 * \return          \c 0 on success.
 * \return          #MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification
 *                  failure.
 */
int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output );

⑨ 释放md结构体:

/**
 * \brief           This function clears the internal structure of \p ctx and
 *                  frees any embedded internal structure, but does not free
 *                  \p ctx itself.
 *
 *                  If you have called mbedtls_md_setup() on \p ctx, you must
 *                  call mbedtls_md_free() when you are no longer using the
 *                  context.
 *                  Calling this function if you have previously
 *                  called mbedtls_md_init() and nothing else is optional.
 *                  You must not call this function if you have not called
 *                  mbedtls_md_init().
 */
void mbedtls_md_free( mbedtls_md_context_t *ctx );

⑩ 错误码:

#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE                -0x5080  /**< The selected feature is not available. */
#define MBEDTLS_ERR_MD_BAD_INPUT_DATA                     -0x5100  /**< Bad input parameters to function. */
#define MBEDTLS_ERR_MD_ALLOC_FAILED                       -0x5180  /**< Failed to allocate memory. */
#define MBEDTLS_ERR_MD_FILE_IO_ERROR                      -0x5200  /**< Opening or reading of file failed. */

调用过程为:

  • starts:初始化,只需调用一次;
  • update:计算值,可以多次调用;
  • finish:获取计算出的消息摘要;

3. 编写测试函数

新建文件mbedtls_sha_x_test.c,编写如下测试函数:

/**
 * @brief   SHAX Function demo
 * @author  mculover666
 * @date    2020/09/22
*/

#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

#if defined(MBEDTLS_MD_C)

#include <stdio.h>
#include "string.h"
#include "mbedtls/md.h"

int mbedtls_shax_test(mbedtls_md_type_t md_type)
{
    int len, i;
    int ret;
    const char *message = "mculover666";
    unsigned char digest[32];
    
    mbedtls_md_context_t ctx;
    const mbedtls_md_info_t *info;

    printf("message is:%s\r\n", message);

    /* 1. init mbedtls_md_context_t structure */
    mbedtls_md_init(&ctx);
    
    /* 2. get md info structure pointer */
    info = mbedtls_md_info_from_type(md_type);
    
    /* 3. setup md info structure */
    ret = mbedtls_md_setup(&ctx, info, 0);
    if (ret != 0) {
        goto exit;
    }
    
    /* 4. start */
    ret = mbedtls_md_starts(&ctx);
     if (ret != 0) {
        goto exit;
    }
     
    /* 5. update */
    ret = mbedtls_md_update(&ctx, (unsigned char *)message, strlen(message));
    if (ret != 0) {
        goto exit;
    }
     
    /* 6. finish */
    ret = mbedtls_md_finish(&ctx, digest);
    if (ret != 0) {
        goto exit;
    }
    
    /* show */
    printf("%s digest context is:[", mbedtls_md_get_name(info));
    len= mbedtls_md_get_size(info);
    for (i = 0; i < len; i++) {
      printf("%02x", digest[i]);
    }
    printf("]\r\n");

    exit:
    /* 7. free */
    mbedtls_md_free(&ctx);
    
    return ret;
}

#endif /* MBEDTLS_MD_C */

4. 调用测试函数

在main.c中先声明测试函数:

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
//extern int mbedtls_ctr_drbg_test(void);

#include "mbedtls/md.h"
extern int mbedtls_shax_test(mbedtls_md_type_t md_type);
/* USER CODE END 0 */

然后在main函数中调用:

/* USER CODE BEGIN 2 */
printf("mbedtls port on BearPi-STM32L431RC board by mculover666\r\n");

/* 0. sha1 sha256 sha512 test */
mbedtls_shax_test(MBEDTLS_MD_SHA1);
mbedtls_shax_test(MBEDTLS_MD_SHA256);
mbedtls_shax_test(MBEDTLS_MD_SHA512);

/* USER CODE END 2 */

5. 测试结果

使用在线工具计算,对比结果是否正确:

接收精彩文章及资源推送,请订阅我的微信公众号:『mculover666』

Mculover666 CSDN认证博客专家 嵌入式软件开发 IoT全栈开发
CSDN博客专家,微信公众号mculover666,凭借与生俱来的热爱专注于嵌入式领域,在自己折腾的同时,以文字的方式分享所玩、所思、所想、所悟,作为一个技术人,我们一起前进~
©️2020 CSDN 皮肤主题: 成长之路 设计师:Amelia_0503 返回首页