openssl hmac源码分析

2023-11-12

hmac 原理

HMAC 用于保护消息的完整性,它采用摘要算法对消息、填充以及秘密密钥进行混合
运算。在消息传输时,用户不仅传送消息本身,还传送 HMAC 值。接收方接收数据后也进
行 HMAC 运算,再比对 MAC 值是否一致。由于秘密密钥只有发送方和接收方才有,其他
人不可能伪造假的 HMAC 值,从而能够知道消息是否被篡改。
ssl 协议中用 HMAC 来保护发送消息,并且 ssl 客户端和服务端的 HMAC 密钥是不同的,
即对于双方都有一个读 MAC 保护密钥和写 MAC 保护密钥。

图片来自网络

实现过程

实现在hmac.c中

unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
                    const unsigned char *d, size_t n, unsigned char *md,
                    unsigned int *md_len)
{
    HMAC_CTX *c = NULL;
    static unsigned char m[EVP_MAX_MD_SIZE];
    static const unsigned char dummy_key[1] = {'\0'};

    if (md == NULL)
        md = m;
    if ((c = HMAC_CTX_new()) == NULL)
        goto err;

    /* For HMAC_Init_ex, NULL key signals reuse. */
    if (key == NULL && key_len == 0) {
        key = dummy_key;
    }

    if (!HMAC_Init_ex(c, key, key_len, evp_md, NULL))
        goto err;
    if (!HMAC_Update(c, d, n))
        goto err;
    if (!HMAC_Final(c, md, md_len))
        goto err;
    HMAC_CTX_free(c);
    return md;
 err:
    HMAC_CTX_free(c);
    return NULL;
}

数据结构

struct hmac_ctx_st {
    const EVP_MD *md;
    EVP_MD_CTX *md_ctx; 
    EVP_MD_CTX *i_ctx;  //输入
    EVP_MD_CTX *o_ctx;  //输出
};


初始化

int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
                 const EVP_MD *md, ENGINE *impl)
{
    int rv = 0, reset = 0;
    int i, j;
    unsigned char pad[HMAC_MAX_MD_CBLOCK_SIZE];
    unsigned int keytmp_length;
    unsigned char keytmp[HMAC_MAX_MD_CBLOCK_SIZE];//定义的是144

    /* If we are changing MD then we must have a key */
    if (md != NULL && md != ctx->md && (key == NULL || len < 0))
        return 0;

    if (md != NULL) {
        ctx->md = md;
    } else if (ctx->md) {
        md = ctx->md;
    } else {
        return 0;
    }

    /*
     * The HMAC construction is not allowed  to be used with the
     * extendable-output functions (XOF) shake128 and shake256.
     */
    if ((EVP_MD_meth_get_flags(md) & EVP_MD_FLAG_XOF) != 0)
        return 0;

    if (key != NULL) {
        reset = 1;

        j = EVP_MD_block_size(md);
        if (!ossl_assert(j <= (int)sizeof(keytmp)))//块大小需要小于最大块大小,144 sha3_224的块大小
            return 0;
        if (j < len) {//如果key长度大于最大块大小,需要通过摘要生成一个零时key.
            if (!EVP_DigestInit_ex(ctx->md_ctx, md, impl)
                    || !EVP_DigestUpdate(ctx->md_ctx, key, len)
                    || !EVP_DigestFinal_ex(ctx->md_ctx, keytmp,
                                           &keytmp_length))
                return 0;
        } else {
        //如果key长度小于0或者大于最大块大小,直接返回
            if (len < 0 || len > (int)sizeof(keytmp))
                return 0;
                //如果key小于最大块大小,拷贝key的全部进入临时key空间
            memcpy(keytmp, key, len);
            keytmp_length = len;
        }
        //如果key长度还不够块大小,剩余空间补0
        if (keytmp_length != HMAC_MAX_MD_CBLOCK_SIZE)
            memset(&keytmp[keytmp_length], 0,
                   HMAC_MAX_MD_CBLOCK_SIZE - keytmp_length);
		//对pad进行异或0x36
        for (i = 0; i < HMAC_MAX_MD_CBLOCK_SIZE; i++)
            pad[i] = 0x36 ^ keytmp[i];
            //对pad进行摘要,注意这里是ctx->i_ctx
        if (!EVP_DigestInit_ex(ctx->i_ctx, md, impl)
                || !EVP_DigestUpdate(ctx->i_ctx, pad, EVP_MD_block_size(md)))
            goto err;
		//同上,这次是对ctx->o_ctx进行摘要
        for (i = 0; i < HMAC_MAX_MD_CBLOCK_SIZE; i++)
            pad[i] = 0x5c ^ keytmp[i];
        if (!EVP_DigestInit_ex(ctx->o_ctx, md, impl)
                || !EVP_DigestUpdate(ctx->o_ctx, pad, EVP_MD_block_size(md)))
            goto err;
    }
    //拷贝输入ctx到md_ctx
    if (!EVP_MD_CTX_copy_ex(ctx->md_ctx, ctx->i_ctx))
        goto err;
    rv = 1;
 err:
    if (reset) {
        OPENSSL_cleanse(keytmp, sizeof(keytmp));
        OPENSSL_cleanse(pad, sizeof(pad));
    }
    return rv;
}

update

对数据进行摘要,注意在这之前已经对key进行了处理并进行了摘要


int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data, size_t len)
{
    if (!ctx->md)
        return 0;
    return EVP_DigestUpdate(ctx->md_ctx, data, len);
}

final


int HMAC_Final(HMAC_CTX *ctx, unsigned char *md, unsigned int *len)
{
    unsigned int i;
    unsigned char buf[EVP_MAX_MD_SIZE];

    if (!ctx->md)
        goto err;
	//对将缓存区中的数据摘要完成
    if (!EVP_DigestFinal_ex(ctx->md_ctx, buf, &i))
        goto err;
        //将ctx->o_ctx拷贝到ctx_md_ctx
    if (!EVP_MD_CTX_copy_ex(ctx->md_ctx, ctx->o_ctx))
        goto err;
        //对刚才输入的摘要结果再次摘要,注意这个摘要之前已经有ctx->o_ctx的结果
    if (!EVP_DigestUpdate(ctx->md_ctx, buf, i))
        goto err;
        //处理最后的缓冲区
    if (!EVP_DigestFinal_ex(ctx->md_ctx, md, len))
        goto err;
    return 1;
 err:
    return 0;
}



总结

hmac本质就是对数据和key混合进行摘要。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

openssl hmac源码分析 的相关文章

随机推荐

  • 事件循环(Event Loop)

    目录 一 浏览器的进程模型 1 1 进程 1 2 线程 1 3 浏览器的进程和线程 二 渲染主线程 2 1 渲染主线程中为什么使用异步 2 2 js的异步 2 3 队列的优先级 添加任务到微队列的主要 式主要是使 Promise NextT
  • 板材眼镜大小调整方法

    http v youku com v show id XNTY0NjUwOTU2 html
  • ROS 2正式版来了,到底有哪些新变化?

    锋影 email 174176320 qq com 如果你认为本系列文章对你有所帮助 请大家有钱的捧个钱场 点击此处赞助 赞助额0 1元起步 多少随意 2017 12 09 机器人开源操作系统软件ROS 2终于推出首个正式版 新版本命名为
  • openGL之API学习(一零三)glGetActiveUniform

    获取活跃一致变量的信息 变量可以在程序执行期间被访问 则该变量被认为是活动的 void glGetActiveUniform GLuint program GLuint index GLsizei bufSize GLsizei lengt
  • 微信小程序唤起键盘页面溢出的解决方案

    文章目录 背景 解决方案 效果 背景 微信小程序的 input 组件 如果使用自带的adjust position会引起除了 input 元素的其他元素一并上移 解决方案 首先获取到屏幕的高度screenHeight 确定好每个元素所占的大
  • 静态代码分析工具清单:开源篇(多语言)

    http hao jobbole com static code analysis tool list opensource utm source hao jobbole com utm medium relatedResources 静态
  • 百度地图入门

    百度地图官网百度api 进入官网选择javascript API 里面有详细的教程 跟着教程先登录注册一个个人开发账号 并创建一个应用获取ak 创建时js需要填白名单 如果是在本地运行填写localhost就好了 当你在控制台看到这个界面是
  • eclipse双击变量高亮显示开关

    eclipse双击变量高亮显示开关 在eclipse myeclipse中如果不小心把变量的高亮显示弄丢了 可真是件愁人的事 不过看到这你就不用愁了 windows gt preferences gt java gt Editor gt M
  • Springboot读取jar下的文件(在springboot打包成jar后)

    关于取web jar中的配置数据 以及存储下载的数据临时目录 按如下方法处理 均已测试验证过 1 更新了文件路径问题 所有的初始化数据Jason直接从reasource目录的mockdata里读 2 所有下载的数据 放到web jar同一级
  • C语言学习———函数

    目录 编辑 1 函数的概念 2 函数的分类 3 库函数是什么 3 1库函数的查找学习方法 3 2库函数的分类 4 自定义函数 4 1形参与实参 4 2传值与传址调用 4 3总结一句 5 函数的嵌套定义与链式访问 5 1嵌套定义 5 2链式访
  • 什么是智能合约? 智能合约到底做什么的?

    Solidity Solidity是一种用于编写智能合约的高级语言 语法类似于JavaScript 在以太坊平台上 Solidity编写的智能合约可以被编译成字节码在以太坊虚拟机上运行 使用Solidity语言编写智能合约避免了直接编写底层
  • thinkphp5学习路程 二 URL访问路径

    URL访问路径 localhost studytp1 public index php 模块 控制器 操作名 参数名 参数值 默认情况下URL是不区分大小写的 自动转换成小写 如果要区分 就要打开配置文件中的 关闭URL中控制器和操作名的自
  • 计算机网络一到六章知识点

    一 概述 1 1互联网的基本特性 连通性 互联网上用户不管距离多远 都能通信 就像这些用户终端都彼此连通 共享性 所谓共享就是指资源共享 资源共享 包含信息 软件 硬件等共享 就像资源在用户身边 1 2 因特网 互联网 概述 1 网络的网络
  • 在小程序开发中使用 npm

    微信小程序在 2 2 1 版本后增加了对 npm 包加载的支持 使得小程序支持使用 npm 安装第三方包 1 在小程序中加载 npm 包 npm install miniprogram datepicker production node
  • 数组查找操作:寻找第二大

    一 找出数组中第二大的数字 public class Main public static void main String args int max 0 int smax 0 int arr 1 2 3 4 6 8 7 if arr 0
  • 解决bash: mysql: command not found 的方法【linux mysql命令 】

    linux下 在mysql正常运行的情况下 输入mysql提示 mysql command not found 遇上 bash mysql command not found的情况别着急 这个是因为 usr local bin目录下缺失my
  • C#使用欧姆龙PLC的Fins协议读写PLC地址(基本封装)

    FINS通讯概述 FINS factory interface network service 通信协议是欧姆龙公司开发的用于工业自动化控制网络的指令 响应系统 运用 FINS指令可实现各种网络间的无缝通信 通过编程发送FINS指令 上位机
  • Unity中用到的数学知识 整理 (为自己)

    缓动数学知识 转自 http easings net en CSS CSS properties transition and animation allow you to pick the easing function Unfortun
  • Spring两大特性:IOC和AOP

    Spring拥有两大特性 IOC 控制反转 AOP 面向切面编程 Spring注解 Spring为我们提供了多个方便的注解 例如 Controller 标明为控制层组件 Service 服务层组件 Repository DAO层 Compo
  • openssl hmac源码分析

    hmac 原理 HMAC 用于保护消息的完整性 它采用摘要算法对消息 填充以及秘密密钥进行混合 运算 在消息传输时 用户不仅传送消息本身 还传送 HMAC 值 接收方接收数据后也进 行 HMAC 运算 再比对 MAC 值是否一致 由于秘密密