int mbedtls_md_hmac(
    const mbedtls_md_info_t* md_info,
    const unsigned char* key,
    size_t               keyLength,
    const unsigned char* input,
    size_t               inputLength,
    unsigned char* output
)
1.0、参考
1.1、此函数的作用

HMAC算法

1.2、参数说明

mbedtls_md_info_t的定义:

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;

typedef struct {
    const char*       name; /** Name of the message digest */
    mbedtls_md_type_t type; /** Digest identifier */
    unsigned char size;      /** Output length of the digest function in bytes */
    unsigned char block_size; /** Block length of the digest function in bytes */
} mbedtls_md_info_t;

#if defined(MBEDTLS_MD2_C)
extern const mbedtls_md_info_t mbedtls_md2_info = {"MD2", MBEDTLS_MD_MD2, 16, 16};
#endif

#if defined(MBEDTLS_MD4_C)
extern const mbedtls_md_info_t mbedtls_md4_info = {"MD4", MBEDTLS_MD_MD4, 16, 64};
#endif

#if defined(MBEDTLS_MD5_C)
extern const mbedtls_md_info_t mbedtls_md5_info = {"MD5", MBEDTLS_MD_MD5, 16, 64};
#endif

#if defined(MBEDTLS_RIPEMD160_C)
extern const mbedtls_md_info_t mbedtls_ripemd160_info = {"RIPEMD160", MBEDTLS_MD_RIPEMD160, 20, 64};
#endif

#if defined(MBEDTLS_SHA1_C)
extern const mbedtls_md_info_t mbedtls_sha1_info = {"SHA1", MBEDTLS_MD_SHA1, 20, 64};
#endif

#if defined(MBEDTLS_SHA256_C)
extern const mbedtls_md_info_t mbedtls_sha224_info = {"SHA224", MBEDTLS_MD_SHA224, 28, 64};
extern const mbedtls_md_info_t mbedtls_sha256_info = {"SHA256", MBEDTLS_MD_SHA256, 32, 64};
#endif

#if defined(MBEDTLS_SHA512_C)
#if !defined(MBEDTLS_SHA512_NO_SHA384)
extern const mbedtls_md_info_t mbedtls_sha384_info = {"SHA384", MBEDTLS_MD_SHA384, 48, 128};
#endif

extern const mbedtls_md_info_t mbedtls_sha512_info = {"SHA512", MBEDTLS_MD_SHA512, 64, 128};
#endif

const unsigned char *key密钥字节数据C语言中没有其他语言中的byte类型,C语言中表达byte类型就是用unsigned charunsigned char的意思就是告诉编译器, 不要把我的最高位当成符号位,这样这8bit就都表示真实的数据了。

size_t的定义:

typedef long unsigned int __darwin_size_t;
typedef __darwin_size_t size_t;

size_t keyLengthconst unsigned char* key的大小,单位是字节

const unsigned char* input输入字节数据

size_t inputLengthconst unsigned char* input的大小,单位是字节

unsigned char* output输出字节数据。其长度由决定。

1.3、返回值说明

0表示成功。

非0表示失败。错误码定义如下:

#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. */
1.4、使用示例

step1、创建一个项目目录和存放源码的目录HMAC/mbedtls,并进入该目录

mkdir -p HMAC/mbedtls && cd HMAC/mbedtls

step2、使用curl命令下载代码

BRANCH=development
BASE_URL_H=https://raw.githubusercontent.com/ARMmbed/mbedtls/$BRANCH/include/mbedtls
BASE_URL_C=https://raw.githubusercontent.com/ARMmbed/mbedtls/$BRANCH/library

for item in sha256.h md.h md_internal.h platform_util.h platform.h threading.h error.h
do
    curl -LO "$BASE_URL_H/$item"
done

for item in sha256.c md.c platform_util.c platform.c threading.c error.c
do
    curl -LO "$BASE_URL_C/$item"
done

step3、编写一个config.h文件,其内容如下

#define MBEDTLS_MD_C
#define MBEDTLS_SHA256_C
此例中,我们只与SHA-256联合使用。要与其他哈希函数联合使用的话,定义对应的,并下载对应的代码。
#define MBEDTLS_MD5_C
md5.h
#define MBEDTLS_RIPEMD160_C
ripemd160.h
#define MBEDTLS_SHA1_C
sha1.h
#define MBEDTLS_SHA256_C
sha256.h
#define MBEDTLS_SHA512_C
sha512.h

step4、将代码中的mbedtls/字符串去掉

sed -i    's@mbedtls/@@g' * 2> /dev/null ||
sed -i "" 's@mbedtls/@@g' *

step5、进入目录HMAC

cd ..

step6、编写一个C语言源程序hamcTest.c,其内容如下

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

void showHelp() {
    printf("usage: hmac <option> <KEY> <CONTENT>\n");
    printf("option: -x lower case, default true\n");
    printf("        -X upper case\n");
    printf("example:hmac -X 123456 abcdefg\n");
    exit(1);
}

void base16(unsigned char input[32], char* output, bool isToUpper) {
    const char* format = isToUpper ? "%02X" : "%02x";
    char tmp[3] = {0};
    for(int i = 0; i < 32; i++) {
        sprintf(tmp, format, input[i]);
        strcat(output, tmp);
    }
}

void performHMAC_SHA256(char* key, char* input, bool isToUpper) {
    //SHA-256算法能够根据任意长度的数据计算出一个固定长度(256bit=32byte)的唯一数据
    unsigned char output[32] = {0};
    extern const mbedtls_md_info_t mbedtls_sha256_info;
    int resultCode = mbedtls_md_hmac(&mbedtls_sha256_info, (unsigned char*)key, strlen(key), (unsigned char*)input, strlen(input), output);
    if (0 == resultCode) {
        //为了便于比较,通常会把SHA-256运算后得到的256bit数据再用base16编码。因为每4bit可以表示一个十六进制字符,用十六进制表示就是64个字符。
        char hex[65] = {0};
        base16(output, hex, isToUpper);
        printf("hmac_sha256(content=%s,key=%s)=%s\n", input, key, hex);
    } else {
        printf("error occurred. code is %d\n", resultCode);
    }
}

int main(int argc, char* argv[]) {
    if (4 == argc) {
        if (strcmp("-x", argv[1]) == 0) {
            performHMAC_SHA256(argv[2], argv[3], false);
        } else if (strcmp("-X", argv[1]) == 0) {
            performHMAC_SHA256(argv[2], argv[3], true);
        } else {
            showHelp();
        }
    }

    return 0;
}

step7、使用cc命令进行编译

cc -o hamcTest hamcTest.c mbedtls/*.c

step8、运行hamcTest

./hmacTest -x 123456 abc
hmac_sha256(content=abc,key=123456)=f6ced6f4883ffc0981a6b9945819f680102b43097ad8ef7a0df9bde06fb3d2e4

./hmacTest -X 123456 abc
hmac_sha256(content=abc,key=123456)=F6CED6F4883FFC0981A6B9945819F680102B43097AD8EF7A0DF9BDE06FB3D2E4

step9、验证结果是否正确。在线工具中输入相同的字符,看看输出是否一样。

source code on GitHub