RSA组件之掩码生成函数(MGF)的实现(C源码)

文章目录

  • RSA组件之掩码生成函数(MGF)的实现(C源码)
    • 1. RSA 算法中使用 MGF 函数
      • 1.1 OAEP 中对 MGF 的调用
      • 1.2 PSS 中对 MGF 的调用
    • 2. RFC 8017 中关于 MGF 函数的描述
    • 3. MGF 函数代码
      • 3.1 实现代码
      • 3.2 测试代码
      • 3.3 编译代码和并测试
    • 4. 其它

1. RSA 算法中使用 MGF 函数

在非对称加密算法 RSA 中,如果加密模式为 RSA-OAEP 或签名方案为概率签名 RSA-PSS 时会用到一个 MGF 函数。

  • OAEP: 最优非对称加密填充 Optimal Asymmetric Encryption Padding
  • PSS: 概率签名方案, Probabilistic Signature Scheme
  • MGF: 掩码生成函数, Mask Generation Function

1.1 OAEP 中对 MGF 的调用

RSA 最优非对称加密填充中两次调用 MGF 分别用于生成 maskedDB 和 maskedSeed 数据:

1.2 PSS 中对 MGF 的调用

RSA 概率签名方案中调用 MGF 来生成 maskedDB 数据:

2. RFC 8017 中关于 MGF 函数的描述

MGF 函数基于哈希函数来构建,RSA 规范中使用的 MGF 函数是 MGF1,其在 RFC 8017 附录 B2 中的描述如下:

B.2.  Mask Generation FunctionsA mask generation function takes an octet string of variable lengthand a desired output length as input and outputs an octet string ofthe desired length.  There may be restrictions on the length of theinput and output octet strings, but such bounds are generally verylarge.  Mask generation functions are deterministic; the octet stringoutput is completely determined by the input octet string.  Theoutput of a mask generation function should be pseudorandom: Givenone part of the output but not the input, it should be infeasible topredict another part of the output.  The provable security ofRSAES-OAEP and RSASSA-PSS relies on the random nature of the outputof the mask generation function, which in turn relies on the randomnature of the underlying hash.One mask generation function is given here: MGF1, which is based on ahash function.  MGF1 coincides with the mask generation functionsdefined in IEEE 1363 [IEEE1363] and ANSI X9.44 [ANSIX944].  Futureversions of this document may define other mask generation functions.B.2.1.  MGF1MGF1 is a mask generation function based on a hash function.MGF1 (mgfSeed, maskLen)Options:Hash     hash function (hLen denotes the length in octets ofthe hash function output)Input:mgfSeed  seed from which mask is generated, an octet stringmaskLen  intended length in octets of the mask, at most 2^32 hLenOutput:mask     mask, an octet string of length maskLenError: "mask too long"Steps:1.  If maskLen > 2^32 hLen, output "mask too long" and stop.2.  Let T be the empty octet string.3.  For counter from 0 to \ceil (maskLen / hLen) - 1, do thefollowing:A.  Convert counter to an octet string C of length 4 octets (seeSection 4.1):C = I2OSP (counter, 4) .B.  Concatenate the hash of the seed mgfSeed and C to the octetstring T:T = T || Hash(mgfSeed || C) .4.  Output the leading maskLen octets of T as the octet string mask.

说重点, MGF1 是一个伪随机函数,其输入参数是一个任意长度的位串 mgfSeed 和需要输出的掩码位长 maskLen,基于哈希函数构造。

  1. MGF1 有两个参数 mgfSeed 和 maskLen

    • mgfSeed 是输入的随机变量
    • maskLen 是输出的掩码长度
  2. MGF1 内部根据需要调用一个哈希函数,默认为 SHA1,其输出哈希长度为 hLen

  3. MGF1 函数内部有一个计数器 counter,其大小为 0 ~ maskLen / hLen

  4. 将 counter 转换成 4 字节的字符串 C,附加到 mgfSeed 的末尾并计算哈希

Hash(mgfSeed || C)
  1. 递增计数器,计算哈希输出,并链接前一个哈希输出的末尾,直到输出位长的长度达到要求(不少于 maskLen),然后截取前面的 maskLen 字节并返回

所以整个格式类似:

Hash(mgfSeed||0x00000000) || Hash(mgfSeed||0x00000001) || Hash(mgfSeed||0x00000002)... Hash(mgfSeed||n)

3. MGF 函数代码

3.1 实现代码

整个过程的 C 语言代码如下:

  • mgf.h
#ifndef __ROCKY_MGF__H
#define __ROCKY_MGF__Hint MGF1(const char *mgfSeed, unsigned int mgfSeedLen, HASH_ALG alg, unsigned int maskLen, char *mask);#endif
  • mgf.c
#define MGF1_BUF_SIZE 256
int MGF1(const unsigned char *mgfSeed, unsigned int mgfSeedLen, HASH_ALG alg, unsigned int maskLen, unsigned char *mask)
{unsigned char buf[MGF1_BUF_SIZE], *p;unsigned char digest[64]; /* 最长支持 SHA-512 */unsigned long digestLen;unsigned long counter, restLen;if (mgfSeedLen > MGF1_BUF_SIZE - 4){printf("MGF1 buffer is not long enough!\n");return -1;}// copy mgfSeed to buffermemcpy(buf, mgfSeed, mgfSeedLen);// clear rest buffer to 0p = buf + mgfSeedLen;memset(p, 0, MGF1_BUF_SIZE-mgfSeedLen);digestLen = HASH_GetDigestSize(alg, 0);counter = 0;restLen = maskLen;while (restLen > 0){p[0] = (counter >> 24) & 0xff;p[1] = (counter >> 16) & 0xff;p[2] = (counter >>  8) & 0xff;p[3] = counter & 0xff;if (restLen >= digestLen){HASH(alg, buf, mgfSeedLen+4, (unsigned char *)mask);restLen -= digestLen;mask += digestLen;counter ++;}else // 剩余的不足单次哈希长度的部分{HASH(alg, buf, mgfSeedLen+4, (unsigned char *)digest);memcpy(mask, digest, restLen);restLen = 0;}}return 0;
}

其中使用到一个计算哈希函数的库 libhash.a,其头文件如下:

  • hash.h
/** @        file: hash.h* @ description: header file for hash.c* @      author: Gu Yongqiang* @        blog: https://blog.csdn.net/guyongqiangx*/
#ifndef __ROCKY_HASH__H
#define __ROCKY_HASH__H
#include "type.h"/* Hash Algorithm List */
typedef enum {HASH_ALG_MD2,HASH_ALG_MD4,HASH_ALG_MD5,HASH_ALG_SHA1,HASH_ALG_SHA224,HASH_ALG_SHA256,HASH_ALG_SHA384,HASH_ALG_SHA512,HASH_ALG_SHA512_224,HASH_ALG_SHA512_256,HASH_ALG_SHA512_T,HASH_ALG_SHA3_224,HASH_ALG_SHA3_256,HASH_ALG_SHA3_384,HASH_ALG_SHA3_512,HASH_ALG_SHAKE128,HASH_ALG_SHAKE256,HASH_ALG_SM3,HASH_ALG_MAX,HASH_ALG_INVALID
} HASH_ALG;typedef struct hash_context {/** currently we don't use below 3 stuffs,* just for future use, like hmac, hash_drbg, hmac_drbg and so on.*/HASH_ALG alg;uint32_t block_size;uint32_t digest_size;void     *impl;
}HASH_CTX;int HASH_Init(HASH_CTX *ctx, HASH_ALG alg);
int HASH_Update(HASH_CTX *ctx, const void *data, size_t len);
int HASH_Final(unsigned char *md, HASH_CTX *ctx);
unsigned char *HASH(HASH_ALG alg, const unsigned char *data, size_t n, unsigned char *md);/** For SHA-512t, SHAKE128, SHAKE256*/
int HASH_Init_Ex(HASH_CTX *ctx, HASH_ALG alg, uint32_t ext);
unsigned char *HASH_Ex(HASH_ALG alg, const unsigned char *data, size_t n, unsigned char *md, uint32_t ext);uint32_t HASH_GetBlockSize(HASH_ALG alg);
uint32_t HASH_GetDigestSize(HASH_ALG alg, uint32_t ext);#endif

3.2 测试代码

  • mgftest.c

这里的测试内容参考维基百科 MGF 词条中使用 python 测试的内容,具体参考代码中的注释段。

#include <stdio.h>
#include "hash.h"
#include "mgf.h"/** From: https://en.wikipedia.org/wiki/Mask_generation_function** Example outputs of MGF1:** Python 2.7.6 (default, Sep  9 2014, 15:04:36) * [GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.39)] on darwin* Type "help", "copyright", "credits" or "license" for more information.* >>> from mgf1 import mgf1* >>> from binascii import hexlify* >>> from hashlib import sha256* >>> hexlify(mgf1('foo', 3))* '1ac907'* >>> hexlify(mgf1('foo', 5))* '1ac9075cd4'* >>> hexlify(mgf1('bar', 5))* 'bc0c655e01'* >>> hexlify(mgf1('bar', 50))* 'bc0c655e016bc2931d85a2e675181adcef7f581f76df2739da74faac41627be2f7f415c89e983fd0ce80ced9878641cb4876'* >>> hexlify(mgf1('bar', 50, sha256))* '382576a7841021cc28fc4c0948753fb8312090cea942ea4c4e735d10dc724b155f9f6069f289d61daca0cb814502ef04eae1'*/
int main(int argc, char *argv)
{int i;char buf[1024];MGF1("foo", 3, HASH_ALG_SHA1, 3, buf);for (i=0; i<3; i++){printf("%02x", ((unsigned char *)buf)[i]);}printf("\n");MGF1("foo", 3, HASH_ALG_SHA1, 5, buf);for (i=0; i<5; i++){printf("%02x", ((unsigned char *)buf)[i]);}printf("\n");MGF1("bar", 3, HASH_ALG_SHA1, 5, buf);for (i=0; i<5; i++){printf("%02x", ((unsigned char *)buf)[i]);}printf("\n");MGF1("bar", 3, HASH_ALG_SHA1, 50, buf);for (i=0; i<50; i++){printf("%02x", ((unsigned char *)buf)[i]);}printf("\n");MGF1("bar", 3, HASH_ALG_SHA256, 50, buf);for (i=0; i<50; i++){printf("%02x", ((unsigned char *)buf)[i]);}printf("\n");return 0;
}

3.3 编译代码和并测试

使用如下命令编译:

cc mgftest.c mgf.c -o mgftest -I/public/ygu/cryptography/crypto-work.git/out/include -L/public/ygu/cryptography/crypto-work.git/out/lib -lhash

这里使用了 -I-L 选项来指定哈希函数库的头文件和库文件位置。

执行结果如下:

/public/ygu/cryptography/crypto-work.git/mgf$ ./mgftest
1ac907
1ac9075cd4
bc0c655e01
bc0c655e016bc2931d85a2e675181adcef7f581f76df2739da74faac41627be2f7f415c89e983fd0ce80ced9878641cb4876
382576a7841021cc28fc4c0948753fb8312090cea942ea4c4e735d10dc724b155f9f6069f289d61daca0cb814502ef04eae1

4. 其它

洛奇工作中常常会遇到自己不熟悉的问题,这些问题可能并不难,但因为不了解,找不到人帮忙而瞎折腾,往往导致浪费几天甚至更久的时间。

所以我组建了几个微信讨论群(记得微信我说加哪个群,如何加微信见后面),欢迎一起讨论:

  • 一个密码编码学讨论组,主要讨论各种加解密,签名校验等算法,请说明加密码学讨论群。
  • 一个Android OTA的讨论组,请说明加Android OTA群。
  • 一个git和repo的讨论组,请说明加git和repo群。

在工作之余,洛奇尽量写一些对大家有用的东西,如果洛奇的这篇文章让您有所收获,解决了您一直以来未能解决的问题,不妨赞赏一下洛奇,这也是对洛奇付出的最大鼓励。扫下面的二维码赞赏洛奇,金额随意:

洛奇自己维护了一个公众号“洛奇看世界”,一个很佛系的公众号,不定期瞎逼逼。公号也提供个人联系方式,一些资源,说不定会有意外的收获,详细内容见公号提示。扫下方二维码关注公众号:

RSA组件之掩码生成函数(MGF)的实现(C源码)相关推荐

  1. C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统

    基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于C#+asp.net+C++的RSA文件加密系统设计与实现,文章末尾附有本毕业设计的论文 ...

  2. C#毕业设计——基于MD5+RSA的数字签名设计与实现(毕业论文+程序源码)——数字签名系统

    基于MD5+RSA的数字签名设计与实现(毕业论文+程序源码) 大家好,今天给大家介绍基于MD5+RSA的数字签名设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦.需要下载开题报告PPT模板及论 ...

  3. 日志组件Log2Net的介绍和使用(附源码开源地址)

    Log2Net是一个用于收集日志到数据库或文件的组件,支持.NET和.NetCore平台. 此组件自动收集系统的运行日志(服务器运行情况.在线人数等).异常日志.程序员还可以添加自定义日志. 该组件支 ...

  4. 【C#+SQL Server+打印组件】实现电商快递单打印系统 五:自定义组件和快递单模板设计(附源码和资源)

    需要源码和资源请点赞关注收藏后评论区留言私信~~~ 一.自定义组件(扩展TextBox) 由于快递单种类较多,所以在设计系统时考虑开发一个通用模板,由用户根据自己使用的快递单样式自行定义快递单的文本输 ...

  5. Java Review - 并发组件ConcurrentHashMap使用时的注意事项及源码分析

    文章目录 概述 案例 原因分析 修复 小结 概述 ConcurrentHashMap虽然为并发安全的组件,但是使用不当仍然会导致程序错误.我们这里通过一个简单的案例来复现这些问题,并给出开发时如何避免 ...

  6. 微信小程序组件库(简洁极客)---附源码

    效果图如下所示,正在逐渐完善. 目前只完成了弹出层和加载,后续会继续更新,时间是不定时的有时间就会写一点,你需要什么样的功能可以在下方评论反馈 我可以加上去 弹出层组件参数 加载组件参数 链接: ht ...

  7. kbengine源码_KBEngine源码:组件方案

    相对于skynet,KBEngine提供了完整的组件方案. Loginapp 登录验证.注册.Client的接入口. Baseapp 通过Loginapp分配过来的Client会与Baseapp保持连 ...

  8. PyCrypto密码学库源码解析(二)RSA参数生成

    Python Crypto库源码解析(二) RSA参数生成 * 版权声明 * 引用请注明出处,转载请联系: h0.1c@foxmail.com 本文主要讲解pycrypto库中RSA参数生成的实现方法 ...

  9. 开源Vue表格组件,表格插件源码

    开源Vue表格组件,表格插件源码 前言: 关于html里面原生的table,通常满足不了程序员的要求.所以开发了一款表格插件,其功 能有: 1 导入json格式数据后,自动填充表格.表格长宽自适应.排 ...

最新文章

  1. 序列拼接工具Bowtie使用说明
  2. BaseModelOutputWithPoolingAndCrossAttentions的API
  3. ​IBM人工智能芯片的新进展
  4. java练习:打印 数字1、2、3、4的组合,不能以4开头,1和3不能相邻,且数字不能重复
  5. 区块链BaaS云服务(14)华大BGI区块链“Baas接口“
  6. C语言再学习 -- 内存管理
  7. System.Text.Json中时间格式化
  8. 数据库基础知识——DQL语言(二)
  9. 孙鑫-MFC笔记四--文本编程
  10. 数据分析面试都会问到哪些问题
  11. 我用 Python 分析1585家电商车厘子销售数据,发现这些秘密
  12. layui 使用文档总结
  13. 菜鸟也能飞:SQL数据库实战专业教程(二)
  14. postman接口自动化图文案例介绍
  15. 编译与调试以及makefile
  16. C语言实现QQ聊天室小项目 [完整源码]
  17. 老马群控使用教程之手机设备怎么开启【开发者选项】
  18. 【office各个版本安装包】
  19. linux dev ram,fdisk -l 显示 16个ram磁盘/dev/ram0... /ram15
  20. Firefox浏览器的主页更改

热门文章

  1. GetLastError()函数返回值对照列表
  2. Salesforce的V2MOM工作法:明确企业在做什么
  3. C++ Primer Plus 第九章答案 内存模型和名称空间
  4. 台式电脑开机显示蓝屏 检查计算机上的病毒,电脑出现蓝屏是怎么回事
  5. 洛谷P3373 【模板】线段树 2
  6. 芯片k66中文数据手册_IXFK66N50Q2
  7. 大数据之Hadoop生态系统概述
  8. Cyberdog——小米四足机器人测评
  9. 《吊打面试官》系列-Redis基础
  10. 一个大牛的acm历程(看着就要颤抖)