国密算法--Openssl 实现国密算法(加密和解密)
上一次讲了产生密钥,这次我们讲一下加密解密的实现。
先说一下加密解密的流程,一下这些内容都是从国密局发布的国密标准文档里面摘录出来的。大家可以去国密局的网站上自己下载。
下列符号适用于本部分。
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上面.
国密算法--Openssl 实现国密算法(加密和解密)的更多相关文章
- 国密算法--Openssl 实现国密算法(基础介绍和产生秘钥对)
国密非对称加密算法 又称sm2,它是采取了ECC(曲线加密算法)中的一条固定的曲线,实际上就是ECC算法. 因为openssl里面不包含sm2算法,所以就要重新进行封装-. - 对于ECC算法我就不介 ...
- C# 中使用 OpenSSL 的公钥/私钥进行加密和解密
在C#中进行RSA解密,需要用RSACryptoServiceProvider,但是不支持OpenSSL格式的公钥或者私钥. X509 公钥 -----BEGIN PUBLIC KEY----- MI ...
- 常见的加密和解密算法—DES
一.DES加密概述 DES全称为Data Encryption Standard,即数据加密标准,是一种使用密钥加密的块算法,1977年被美国联邦政府的国家标准局确定为联邦资料处理标准(FIPS),并 ...
- 常见的加密和解密算法—AES
一.AES加密概述 高级加密标准(英语:Advanced Encryption Standard,缩写:AES),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准.这个标准用 ...
- 常见的加密和解密算法—BASE64
一.BASE64加密和解密概述 Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,Base64编码可用于在HTTP环境下传递较长的标识信息.例如,在Java Persistence系 ...
- 常见的加密和解密算法—MD5
一.MD5加密概述 Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护.该算法的文件号为RFC 13 ...
- java sm4国密算法加密、解密
java sm4国密算法加密.解密 CreationTime--2018年7月5日09点20分 Author:Marydon 1.准备工作 所需jar包: bcprov-jdk15on-1.59. ...
- openssl解析国密X509证书
openssl解析国密X509证书,把公钥拿出来重写一下就行了 x = strToX509(pbCert, pulCertLen);dwRet = getCertPubKey(x, &a ...
- 源代码方式向openssl中加入新算法完整具体步骤(演示样例:摘要算法SM3)【非engine方式】
openssl简单介绍 openssl是一个功能丰富且自包括的开源安全工具箱.它提供的主要功能有:SSL协议实现(包括SSLv2.SSLv3和TLSv1).大量软算法(对称/非对称/摘要).大数运算. ...
随机推荐
- 在centos7上搭建博客之小白教程~
原理 http使用方法一编译安装,php模块打入方式实现. 软件版本 在本次实验中,我们需要用到的软件版本如下: apr-1.6.2 apr-util-1.6.0 httpd-2.4.28 maria ...
- 多线程之CountDownLatch、CyclicBarrier和Semaphore
Java并发编程:CountDownLatch.CyclicBarrier和Semaphore 在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch ...
- 输入一批考生的的准考证号码,如果是 15 位,表示输入正确,否则重新输入。然后判断这个人的考试类别(号码中如果是以奇数结尾则考试类别为“A 类”,否则为“B 类”),最后输出此准考证的前 5 位和后 4 位,其他位用“*”来代替。说明:使用 StringBuffer 类的相关方法完成实验内容。
因为是一批考生,所以先创建一个字符数组存放一组准考证号. 此外这个程序涉及到包装类与基本数据类型的互相转换. string的substring方法,返回一个字符串是该字符串的子串.从第一个参数开始,第 ...
- css布局中关于 块状元素和行内元素的区分
这两天在准备实习的面试和笔试,准备复习一下这些基础的概念,避免自己处于一种仅脑袋理解嘴巴不能表述出来的状态. 块状元素和行内元素的概念是在css页面布局这个地方出现.主要是将html标签按照一定的特性 ...
- [iOS]拾遗补阙
一.AFNetworking POST纯字符串 修改位置AFURLRequestSerialization 修改前 NSString * AFQueryStringFromParameters(NSD ...
- 使用java发送QQ邮件的总结
最近帮朋友做个网站,实现用邮箱订阅功能,所以现在把这个发送邮件的功能放在这里,算是这两天工作的总结吧! 首先,想要实现订阅功能,要把邮箱保存,但是这个做的是个小网站,前后台交互的太少了,所以我就直接保 ...
- react使用阿里字体图标
1. 在react项目的public文件夹下面创建iconfont文件夹,将下载的文件放到iconfont文件夹下 2.在public文件夹下的index.html引入iconfont.css,如 & ...
- python 第一课作用
1.使用while循环输入 1 2 3 4 5 6 8 9 10 x=0while x<10: x=x+1 if x==7: print(' ') continue print(x)#学 ...
- c# 访问postgressql,使用pghelper访问pgsql
由于工作需要,数据库是postgressql的,本来以为很简单的,结果弄了一晚上,为了总结经验,现将C#连接PGSQL(postgres sql)的资料整理如下. 一.总体思路 1.通过第三方Npgs ...
- python基础学习2-easygui框架编程
#!/usr/bin/env python # -*- coding:utf-8 -*- import easygui as g #导入方式一 #导入方式2 #from easygui import ...