博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
国密算法--Openssl 实现国密算法(加密和解密)
阅读量:6901 次
发布时间:2019-06-27

本文共 5241 字,大约阅读时间需要 17 分钟。

上一次讲了产生密钥,这次我们讲一下加密解密的实现。

先说一下加密解密的流程,一下这些内容都是从国密局发布的国密标准文档里面摘录出来的。大家可以去国密局的网站上自己下载。

下列符号适用于本部分。

A,B:使用公钥密码系统的两个用户。
a,b: Fq中的元素,它们定义Fq上的一条椭圆曲线E。
dB:用户B的私钥。
E(Fq): Fq上椭圆曲线E 的所有有理点(包括无穷远点O)组成的集合。
Fq
:包含q个元素的有限域。
G:椭圆曲线的一个基点,其阶为素数。
2Hash( ):密码杂凑函数。
Hv
( ):消息摘要长度为v比特的密码杂凑函数。
KDF( ):密钥派生函数。
M :待加密的消息。
M ′:解密得到的消息。
n:基点G的阶(n是# E(Fq)的素因子)。
O:椭圆曲线上的一个特殊点,称为无穷远点或零点,是椭圆曲线加法群的单位元。
PB:用户B的公钥。
q:有限域Fq中元素的数目。
x∥y: x与y的拼接,其中x、 y可以是比特串或字节串。
[k]P:椭圆曲线上点P的k倍点,即, [k]P= P + P + · · · + P(k个, k是正整数)。
[x,y]:大于或等于x且小于或等于y的整数的集合。
⌈x⌉:顶函数,大于或等于x的最小整数。例如⌈7⌉=7, ⌈8.3⌉=9。
⌊x⌋:底函数,小于或等于x的最大整数。例如⌊7⌋=7, ⌊8.3⌋=8。
#E(Fq): E(Fq)上点的数目,称为椭圆曲线E(Fq)的阶

下面给出加密过程:

设需要发送的消息为比特串M, klen为M的比特长度。

为了对明文M进行加密,作为加密者的用户A应实现以下运算步骤:
A1:用随机数发生器产生随机数k∈[1,n-1];
A2:计算椭圆曲线点C1=[k]G=(x1,y1),按本文本第1部分4.2.8和4.2.4给出的细节,将C1的数据类
型转换为比特串;
A3:计算椭圆曲线点S=[h]PB,若S是无穷远点,则报错并退出;
A4:计算椭圆曲线点[k]PB=(x2,y2),按本文本第1部分4.2.5和4.2.4给出的细节,将坐标x2、 y2 的
数据类型转换为比特串;
A5:计算t=KDF(x2 ∥ y2, klen),若t为全0比特串,则返回A1;
A6:计算C2 = M ⊕ t;
A7:计算C3 = Hash(x2 ∥ M ∥ y2);
A8:输出密文C = C1 ∥ C2 ∥ C3。

以及加密流程图:

加密流程图

下面是加密的核心代码:

unsigned char* t, *hm;    BIGNUM* rand;    EC_POINT* rG, *rK;    BIGNUM *rKx, *rKy, *rGx, *rGy;    unsigned char bK[65] = {0};    unsigned char C3[33] = {0};    rG = EC_POINT_new(this->mGroup);    rK = EC_POINT_new(this->mGroup);    rand = BN_new();    //随机数k∈[1,n-1]    BN_rand_range(rand, this->z);    //C1=[k]G=(x1,y1)    EC_POINT_mul(this->mGroup, rG, NULL,        this->mGP, rand, this->ctx);    rGx = BN_new();    rGy = BN_new();    if(!EC_POINT_get_affine_coordinates_GFp(this->mGroup,         rG, rGx, rGy, this->ctx))    {        return -3;    }    BN_bn2bin(rGx, pd);    BN_bn2bin(rGy, &pd[32]);    //[k]PB=(x2,y2)    EC_POINT_mul(this->mGroup, rK, NULL,         EC_KEY_get0_public_key(this->mKey),         rand, this->ctx);    rKx = BN_new();    rKy = BN_new();    if(!EC_POINT_get_affine_coordinates_GFp(this->mGroup,         rK, rKx, rKy, this->ctx))    {        return -3;    }    //t=KDF(x2||y2, klen)       BN_bn2bin(rKx, bK);    BN_bn2bin(rKy, &bK[32]);    t = new BYTE[elen + 1];    memset(t, 0, elen + 1);    this->mKDF(bK, 64, elen, t);    for (int i = elen; i--;)    {        t[i] = t[i]^pe[i];    }    //C3 = Hash(x2||M||y2)    hm = new unsigned char[elen + 65];    memset(hm, 0, elen + 65);    memcpy(hm, bK, 32);    memcpy(&hm[32], pe, elen);    memcpy(&hm[elen + 32], &bK[32], 32);    hash(hm, elen + 64, C3, "sha256");    //C = C1||C2||C3    memcpy(&pd[64], t,  elen);    memcpy(&pd[64 + elen], C3, 32);    delete[] t;    delete[] hm;    t = NULL;    hm = NULL;    EC_POINT_free(rG);    EC_POINT_free(rK);    return 0;

如果细心的朋友会发现我少了两步:

1.A3(校验rK这个点的)

2.校验 是否t为0
怎么说呢….因为我比较懒,而且也没有这个必要,因为我们用的是openssl,以上两种情况不会出现,所以就省略了,当然加上也无可厚非。

加密之后我们就要解密了,能拆就能立能砸就能砌。

解密流程

解密算法

设klen为密文中C2的比特长度。
为了对密文C=C1 ∥ C2 ∥ C3 进行解密,作为解密者的用户B应实现以下运算步骤:
B1:从C中取出比特串C1,按本文本第1部分4.2.3和4.2.9给出的细节,将C1的数据类型转换为椭
圆曲线上的点,验证C1是否满足椭圆曲线方程,若不满足则报错并退出;
B2:计算椭圆曲线点S=[h]C1,若S是无穷远点,则报错并退出;
B3:计算[dB]C1=(x2,y2),按本文本第1部分4.2.5和4.2.4给出的细节,将坐标x2、 y2的数据类型转
换为比特串;
B4:计算t=KDF(x2 ∥ y2, klen),若t为全0比特串,则报错并退出;
B5:从C中取出比特串C2,计算M ′ = C2 ⊕ t;
B6:计算u = Hash(x2 ∥ M ′ ∥ y2),从C中取出比特串C3,若u ̸= C3,则报错并退出;
B7:输出明文M ′。

以及解密流程图

解密流程图

下面是解密的核心代码:

unsigned char* t, *c2, *hm;    unsigned char bC1x[65] = {0};    unsigned char bC1y[65] = {0};    unsigned char bK[65] = {0};    unsigned char u[33] = {0};     unsigned int mlen, hm_len;      EC_POINT *rG, *rK;    BIGNUM *C1x, *C1y, *rKx, *rKy;    //取出rG    C1x = BN_new();    C1y = BN_new();    memcpy(&bC1x[32], pe, 32);    memcpy(&bC1y[32], &pe[32], 32);    BN_bin2bn(bC1x, 64, C1x);    BN_bin2bn(bC1y, 64, C1y);    rG = EC_POINT_new(this->mGroup);    if(!EC_POINT_set_affine_coordinates_GFp(this->mGroup,         rG, C1x, C1y, this->ctx))    {        EC_POINT_free(rG);        return -1;    }    //求得rK    rK = EC_POINT_new(this->mGroup);    EC_POINT_mul(this->mGroup, rK, NULL, rG,         EC_KEY_get0_private_key(this->mKey),         this->ctx);    rKx = BN_new();    rKy = BN_new();    if(!EC_POINT_get_affine_coordinates_GFp(this->mGroup,         rK, rKx, rKy, this->ctx))    {        EC_POINT_free(rG);        EC_POINT_free(rK);        return -2;    }    //求取hv 解密     BN_bn2bin(rKx, bK);    BN_bn2bin(rKy, &bK[32]);    mlen = elen - 96;    c2 = new unsigned char[mlen + 1];    memset(c2, 0, mlen + 1);    memcpy(c2, &pe[64], mlen);    t = new unsigned char[mlen + 1];    memset(t, 0, mlen + 1);    this->mKDF(bK, 64, elen - 96, t);    for (int i = elen - 96; i--;)    {        t[i] = t[i]^c2[i];    }    hm_len = mlen + 64;    hm = new unsigned char[hm_len + 1];    memset(hm, 0,hm_len + 1);    BN_bn2bin(rKx, hm);    memcpy(&hm[32], t, mlen);    BN_bn2bin(rKy, &hm[32 + mlen]);    //校验hash值    hash(hm, hm_len, u, "sha256");    for (int i = 0; i < 32;i++)    {        if (u[i] != pe[elen - 32 + i])        {            EC_POINT_free(rG);            EC_POINT_free(rK);            delete[] t;            delete[] c2;            delete[] hm;            t = NULL;            c2 = NULL;            hm = NULL;            return -3;        }       }    memcpy(pd, t, mlen);    EC_POINT_free(rG);    EC_POINT_free(rK);    delete[] t;    delete[] c2;    delete[] hm;    t = NULL;    c2 = NULL;    hm = NULL;    return 0;

以上就是加解密的过程,完整代码我会上传到github上面.

转载于:https://www.cnblogs.com/cnblogs-wangzhipeng/p/9933694.html

你可能感兴趣的文章
PHP代码自动检测(git/svn集成PHP_CodeSniffer)
查看>>
js--string/正则表达式replace方法详解
查看>>
那家CTO带头喊麦的直播公司,快要倒闭了
查看>>
想像亚马逊或 Netflix 一样酷?抱走敏捷转型五大秘籍
查看>>
指针和字符串和字符串常量、用gdb来获取非法内存中的内容
查看>>
青阳网络文件传输系统 kiftd 1.0.17 正式发布
查看>>
搞懂Mysql InnoDB B+树索引
查看>>
SpaceX完成载人猎鹰9火箭静态点火试验,将于2月实现载人升空 ...
查看>>
子查询中有个不存在的列居然不报错是bug吗?
查看>>
Swarm实战Docker容器集群,基于Linux环境部署Web集群例子
查看>>
再不了解PostgreSQL,你就晚了之PostgreSQL主从流复制部署
查看>>
snakemake--我最喜欢的流程管理工具
查看>>
如何用 Python 和 gensim 调用中文词嵌入预训练模型?
查看>>
SSM-Spring-09:Spring中jdk动态代理
查看>>
设计模式—装饰模式的C++实现
查看>>
云数据库产品月刊·5月刊
查看>>
直播转点播实践
查看>>
图像识别落地B端应用,商业化的“绣球”先抛给了哪些行业?
查看>>
python web开发之——Flask入门教程
查看>>
区块链每日一问 | 什么是区块链的“分叉”?
查看>>