找回密码
 立即注册

扫一扫,登录网站

首页 自媒体 查看内容
  • 5013
  • 0
  • 分享到

区块链的3种加密算法及安全要求详解(附代码)

2018-4-5 14:37

来源: HiBlock-Net





欢迎收听「虾说区块链」。现在区块链这个概念在互联网上相当火热,这里简单做一个普及,不涉及项目推广投资,单纯地对区块链相关基础知识概念作一个说明讲解。本人区块链技术爱好者,结合相关区块链资料总结整理了「虾说区块链」,也是自己一个学习笔记,涉及相关内容如理解有误,也请及时指正。


1

SHA-256


SHA(Secure hash algorithm)安全散列算法,由美国国家安全局(NSA)设计,美国国家标准与技术研究院(NIST)发布的一系列密码散列函数集,包括了SHA-1、SHA-224、SHA-256、SHA-384、SHA-512等。


一种哈希函数要达到密码安全的要求,大致要满足三个条件:

碰撞阻力(collision-resistance)、隐秘性(hiding)、谜题友好(puzzle-friendliness)。


碰撞阻力


哈希函数作为密码函数来使用,必须具有良好的碰撞阻力,所谓碰撞阻力即:输入x、y,x≠y,则H(x)=H(y)不成立。


事实上哈希函数的碰撞理论上一直存在,根据计数论证和鸽巢原理,简单想象一下,大量的输入映射到任意指定的输出,以无限对待有限,显而易见,肯定会出现x、y,x≠y,则H(x)=H(y)。


从工程应用的角度来看,那么一个256位的输出,选择2的256次方+1次的输入,必然出现了碰撞,甚至不需要那么多次的输出,根据生日悖论理论,输入2的130次方+1次,得到相同哈希输出的概率即99.8%。


根据输出次数,暂时不论现在热门的量子计算机,传统计算机来计算2的128次方的哈希计算,大致需要10的27次方年(假设传统计算机每秒计算10000次哈希值)。那么这种情况下出现碰撞的概念就认为具有碰撞阻力。


隐秘性


同样也是一个概率问题,H(x)=y,那么根据y无法简单逆推出x值。


引入一个信息论中熵(信息熵概念:所有可能性的关系,即每个可能事件发生都有一个概率的问题,熵理解为平均而言发生一个事情信息量的大小,也就是信息量的一个期望)的概念,高阶最小熵来描述随机变量的分散程度。


还是以256位字符串为例。在计算机中01存储,那么要获取x的值,概率在2的256次方分之一,无疑这个概率还是很小的。


谜题友好


如果对于任意的n位的输出值y,y=H(x),无法在较小时间内找到x的值,通过之前的概率的说明,这样的H哈希函数被认为谜题友好。


在区块链技术中的SHA-256算法目前认为是一种安全的哈希算法,在2009年中本聪创造区块链技术中选择了SHA-256算法。


SHA-256:一种将接受固定长度转变为接受任意长度输入的哈希函数,这个称为MD转换,也可称为压缩函数,所谓压缩函数就是输入m长度的值,产生一些长度短一点的n的输出,输入可以任意大小,被分为m-n的区块,然后将每个区块和之前区块的输出一起代入压缩函数,输出长度就变成了(m-n)+n=m,对第一个区块来说,没有之前的初始向量了,没有就补一个初始向量,每次调用哈希函数,这些数字就再使用一次,最后一个区块就是返回结果。SHA-256算法把输入长度不超过2^64bit,按照512bit分组进行处理,产生一个256bit的报文摘要。

 

具体步骤:


  • 附加填充比特,对输入进行填充,使其长度满足length=448 mod 512,长度为448模512同余,最高位为1,其余位为0,填充范围在1到512。输入值后加1,再一直加0,加至长度满足mod 512=448


  • 附加长度值,将之前原始输入值的位长度添加在之前的填充结果中。


  • 初始化缓存,使用一个256bit的缓存来存放计算过程中的值和最终结果。该缓存表示为A=0x6A09E667 , B=0xBB67AE85 , C=0x3C6EF372 , D=0xA54FF53A, E=0x510E527F , F=0x9B05688C , G=0x1F83D9AB , H=0x5BE0CD19


  • 处理512bit输入的分组序列,使用六种逻辑函数迭代运算。由64 步迭代运算组成。每步都以256-bit 缓存值ABCDEFGH 为输入,然后更新缓存内容。 每步使用一个32-bit 常数值Kt 和一个32-bit Wt。

    

 

附代码实现,来自:

http://blog.csdn.net/c_duoduo/article/details/43889759


#include

#include

#define SHA256_ROTL(a,b) (((a>>(32-b))&(0x7fffffff>>(31-b)))|(a<<b))

#define SHA256_SR(a,b) ((a>>b)&(0x7fffffff>>(b-1)))

#define SHA256_Ch(x,y,z) ((x&y)^((~x)&z))

#define SHA256_Maj(x,y,z) ((x&y)^(x&z)^(y&z))

#define SHA256_E0(x) (SHA256_ROTL(x,30)^SHA256_ROTL(x,19)^SHA256_ROTL(x,10))

#define SHA256_E1(x) (SHA256_ROTL(x,26)^SHA256_ROTL(x,21)^SHA256_ROTL(x,7))

#define SHA256_O0(x) (SHA256_ROTL(x,25)^SHA256_ROTL(x,14)^SHA256_SR(x,3))

#define SHA256_O1(x) (SHA256_ROTL(x,15)^SHA256_ROTL(x,13)^SHA256_SR(x,10))

extern char* StrSHA256(const char* str, long long length, char* sha256){

    /*

    计算字符串SHA-256

    参数说明:

    str         字符串指针

    length      字符串长度

    sha256         用于保存SHA-256的字符串指针

    返回值为参数sha256

    */

    char *pp, *ppend;

    long l, i, W[64], T1, T2, A, B, C, D, E, F, G, H, H0, H1, H2, H3, H4, H5, H6, H7;

    H0 = 0x6a09e667, H1 = 0xbb67ae85, H2 = 0x3c6ef372, H3 = 0xa54ff53a;

    H4 = 0x510e527f, H5 = 0x9b05688c, H6 = 0x1f83d9ab, H7 = 0x5be0cd19;

    long K[64] = {

        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,

        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,

        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,

        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,

        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,

        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,

        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,

        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,

    };

    l = length + ((length % 64 >= 56) ? (128 - length % 64) : (64 - length % 64));

    if (!(pp = (char*)malloc((unsigned long)l))) return 0;

    for (i = 0; i < length; pp[i + 3 - 2 * (i % 4)] = str[i], i++);

    for (pp[i + 3 - 2 * (i % 4)] = 128, i++; i < l; pp[i + 3 - 2 * (i % 4)] = 0, i++);

    *((long*)(pp + l - 4)) = length << 3;

    *((long*)(pp + l - 8)) = length >> 29;

    for (ppend = pp + l; pp < ppend; pp += 64){

        for (i = 0; i < 16; W[i] = ((long*)pp)[i], i++);

        for (i = 16; i < 64; W[i] = (SHA256_O1(W[i - 2]) + W[i - 7] + SHA256_O0(W[i - 15]) + W[i - 16]), i++);

        A = H0, B = H1, C = H2, D = H3, E = H4, F = H5, G = H6, H = H7;

        for (i = 0; i < 64; i++){

            T1 = H + SHA256_E1(E) + SHA256_Ch(E, F, G) + K[i] + W[i];

            T2 = SHA256_E0(A) + SHA256_Maj(A, B, C);

            H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;

        }

        H0 += A, H1 += B, H2 += C, H3 += D, H4 += E, H5 += F, H6 += G, H7 += H;

    }

    free(pp - l);

    sprintf(sha256, "%08X%08X%08X%08X%08X%08X%08X%08X", H0, H1, H2, H3, H4, H5, H6, H7);

    return sha256;

}

extern char* FileSHA256(const char* file, char* sha256){

    /*

    计算文件SHA-256

    参数说明:

    file        文件路径字符串指针

    sha256         用于保存SHA-256的字符串指针

    返回值为参数sha256

    */

    FILE* fh;

    char* addlp, T[64];

    long addlsize, j, W[64], T1, T2, A, B, C, D, E, F, G, H, H0, H1, H2, H3, H4, H5, H6, H7;

    long long length, i, cpys;

    void *pp, *ppend;

    H0 = 0x6a09e667, H1 = 0xbb67ae85, H2 = 0x3c6ef372, H3 = 0xa54ff53a;

    H4 = 0x510e527f, H5 = 0x9b05688c, H6 = 0x1f83d9ab, H7 = 0x5be0cd19;

    long K[64] = {

        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,

        0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,

        0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,

        0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,

        0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,

        0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,

        0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,

        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,

    };

    fh = fopen(file, "rb);

    fseek(fh, 0, SEEK_END);

    length = _ftelli64(fh);

    addlsize = (56 - length % 64 > 0) ? (64) : (128);

    if (!(addlp = (char*)malloc(addlsize))) return 0;

    cpys = ((length - (56 - length % 64)) > 0) ? (length - length % 64) : (0);

    j = (long)(length - cpys);

    if (!(pp = (char*)malloc(j))) return 0;

    fseek(fh, -j, SEEK_END);

    fread(pp, 1, j, fh);

    for (i = 0; i < j; addlp[i + 3 - 2 * (i % 4)] = ((char*)pp)[i], i++);

    free(pp);

    for (addlp[i + 3 - 2 * (i % 4)] = 128, i++; i < addlsize; addlp[i + 3 - 2 * (i % 4)] = 0, i++);

    *((long*)(addlp + addlsize - 4)) = length << 3;

    *((long*)(addlp + addlsize - 8)) = length >> 29;

    for (rewind(fh); 64 == fread(W, 1, 64, fh);){

        for (i = 0; i < 64; T[i + 3 - 2 * (i % 4)] = ((char*)W)[i], i++);

        for (i = 0; i < 16; W[i] = ((long*)T)[i], i++);

        for (i = 16; i < 64; W[i] = (SHA256_O1(W[i - 2]) + W[i - 7] + SHA256_O0(W[i - 15]) + W[i - 16]), i++);

        A = H0, B = H1, C = H2, D = H3, E = H4, F = H5, G = H6, H = H7;

        for (i = 0; i < 64; i++){

            T1 = H + SHA256_E1(E) + SHA256_Ch(E, F, G) + K[i] + W[i];

            T2 = SHA256_E0(A) + SHA256_Maj(A, B, C);

            H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;

        }

        H0 += A, H1 += B, H2 += C, H3 += D, H4 += E, H5 += F, H6 += G, H7 += H;

    }

    for (pp = addlp, ppend = addlp + addlsize; pp < ppend; pp = (long*)pp + 16){

        for (i = 0; i < 16; W[i] = ((long*)pp)[i], i++);

        for (i = 16; i < 64; W[i] = (SHA256_O1(W[i - 2]) + W[i - 7] + SHA256_O0(W[i - 15]) + W[i - 16]), i++);

        A = H0, B = H1, C = H2, D = H3, E = H4, F = H5, G = H6, H = H7;

        for (i = 0; i < 64; i++){

            T1 = H + SHA256_E1(E) + SHA256_Ch(E, F, G) + K[i] + W[i];

            T2 = SHA256_E0(A) + SHA256_Maj(A, B, C);

            H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;

        }

        H0 += A, H1 += B, H2 += C, H3 += D, H4 += E, H5 += F, H6 += G, H7 += H;

    }

    free(addlp); fclose(fh);

    sprintf(sha256, "%08X%08X%08X%08X%08X%08X%08X%08X", H0, H1, H2, H3, H4, H5, H6, H7);

    return sha256;

}


2

RIPEMD160


RIPEMD(RACE Integrity Primitives Evaluation Message Digest),中文译为“RACE原始完整性校验消息摘要”,是比利时鲁汶大学COSIC研究小组开发的散列函数算法。1996年首次发布RIPEMD-128版本,160位版本RIPEMD-160是对RIPEMD-128的改进,并且是RIPEMD家族中最常见的版本。


RIPEMD家族中共有四种算法:RIPEMD-128、RIPEMD-160、RIPEMD-256、RIPEMD-320。


RIPEMD-160采用输出160位的哈希值,160位的缓存区来存放中间计算过程和最终输出的值,由5个32位寄存器来构成,核心处理通过10个循环的压缩函数,每个循环需要16个处理步骤。


区块链入门时候最难理解的应该就时候这个椭圆加密算法,椭圆加密算法用于生成公钥生成,现在国密SM2算法的也是基于椭圆机密算法的非对称算法,这里对椭圆加密算法做个最简单的介绍。


参考:

http://www.pediy.com/kssd/pediy06/pediy6014.htm


椭圆加密算法是一种公钥加密体制,最初由Koblitz和Miller两人于1985年提出,其数学基础是利用椭圆曲线上的有理点构成Abel加法群上椭圆离散对数的计算困难性。


有理点:一个n维空间中的几何物体,它的每一点的坐标可以用(x_1,x_2,...,x_n)表示。如果所有x_i都是有理数,则称该点为有理点。


平行线和射影平面:初中数学中有个定理,两条平行线永不相交。那么这里我们换一种思考方式,两条平行线在无穷远处会相交,有一个交点。


(不要和之前学的数学去较真)然后根据这个理解,出来下面几个无穷远处点的性质:


  • 一条直线,无穷远处点就一个。(一条线你还能要求它有几个点)

  • 在平面上一组互相平行的平行线在无穷远处有公共的无穷远处点。

  • 平面上相交的两条线在无穷远处有不同的无穷远处点。

  • 平面上所有无穷远处点构成一条直线,叫无穷远处直线,那平面上的无穷远处点和正常点构成一个射影平面。


引入一个射影平面坐标系,联系下之前初中数学学的平面直角坐标系:


 

 

那么把坐标系的任意点(x,y),改变成x=X/Z ,y=Y/Z(Z≠0)则坐标系内点可以表示为(X:Y:Z)。有三个参量的坐标就建立了新的坐标体系。例:平面(4,8),射影平面坐标(4Z,8Z,Z),那么Z不等于0,(4,8,1)(8,16,2)(6,12,1.5)这些都是(4,8)在射影平面坐标下的点。再根据初中的坐标直线方程求解,aX+bY+c1Z =0; aX+bY+c2Z =0  (c1≠c2),方程联立求解,c2Z= c1Z= -(aX+bY)且c1≠c2,aX+bY=0,那么解得(X,Y,0)来表示无穷远点。那么表示这类型的坐标体系为射影平面坐标系。


根据上述的方程式,在射影平面坐标系中的椭圆曲线的定义:


 

该方程名为维尔维斯特拉斯方程,椭圆曲线的形状不是椭圆,只是因为其描述的方程类似于计算一个椭圆周长的方程。到这里才明白这个名字的来历。


加法法则 :任意取椭圆曲线上两点P、Q (若P、Q两点重合,则做P点的切线)做直线交于椭圆曲线的另一点R’,过R’做y轴的平行线交于R。我们规定P+Q=R。


 

曲线上三个点A,B,C处于一条直线上,则A+B+C=O∞  下面,我们利用P、Q点的坐标(x1,y1),(x2,y2),求出R=P+Q的坐标(x4,y4)。 P,Q,R'共线,设为y=kx+b, 若P≠Q,k=(y1-y2)/(x1-x2) 若P=Q,k=(3x2+2a2x+a4 -a1y) /(2y+a1x+a3)  解方程组得到:  x4=k2+ka1-a2-x1-x2;   y4=k(x1-x4)-y1-a1x4-a3;


到这里说椭圆曲线在密码学中的应用,其实之前把整个函数理解成一个曲线光滑的连续曲线,结合笔者之前文章讲加密中质数分解的说明,加密必须是离散的,那么把椭圆曲线定义在一个有限域上。


给出一个有限域Fp,这个域只有有限个元素。


Fp中只有p(p为素数)个元素0,1,2 …… p-2,p-1;

Fp 的加法(a+b)法则是 a+b≡c (mod p);即,(a+c)÷p的余数 和c÷p的余数相同。

Fp 的乘法(a×b)法则是  a×b≡c (mod p);

Fp 的除法(a÷b)法则是  a/b≡c (mod p);即 a×b-1≡c  (mod p);(b-1也是一个0到p-1之间的整数,但满足b×b-1≡1 (mod p);)。

Fp 的单位元是1,零元是 0。


同时,并不是所有的椭圆曲线都适合加密。y2=x3+ax+b是一类可以用来加密的椭圆曲线,也是最为简单的一类。下面我们就把y2=x3+ax+b 这条曲线定义在Fp上:


选择两个满足下列条件的小于p(p为素数)的非负整数a、b

      4a3+27b2≠0 (mod p)


则满足下列方程的所有点(x,y),再加上 无穷远点O∞ ,构成一条椭圆曲线。

     y2=x3+ax+b  (mod p)


其中 x,y属于0到p-1间的整数,并将这条椭圆曲线记为Ep(a,b)。


我们看一下y2=x3+x+1  (mod 23)的图像


 

椭圆曲线这里成为了离散的点。


接下来就是加密解密:


定义个等式:K=kG  [其中 K,G为Ep(a,b)上的点,k为小于n(n是点G的阶)的整数]


根据加法法则,计算K很容易;但给定K和G,求k就相对困难了。 我们把点G称为基点(base point),k(k<n,n为基点G的阶)称为私有密钥(privte key),K称为公开密钥(public key)。


整个加密通信过程:

  • 用户A选定一条椭圆曲线Ep(a,b),并取椭圆曲线上一点,作为基点G。

  • 用户A选择一个私有密钥k,并生成公开密钥K=kG。

  • 用户A将Ep(a,b)和点K,G传给用户B。

  • 用户B接到信息后 ,将待传输的明文编码到Ep(a,b)上一点M(编码方法很多,这里不作讨论),并产生一个随机整数r(r<n)。

  • 用户B计算点C1=M+rK;C2=rG。

  • 用户B将C1、C2传给用户A。

  • 用户A接到信息后,计算C1-kC2,结果就是点M。


因为C1-kC2=M+rK-k(rG)=M+rK-r(kG)=M 再对点M进行解码就可以得到明文。


最后说下椭圆曲线优点:与经典的RSA,DSA等公钥密码体制相比安全性高,160位的椭圆密钥与1024位的RSA密钥安全性相同。处理速度快。在私钥的加密解密速度上,ecc算法比RSA、DSA速度更快。存储空间占用小。带宽要求低。


3

SM2国密算法


SM2国密算法是非对称密码算法,基于椭圆加密算法。在目前国内商用密码中用来替换RSA算法。


上文中椭圆曲线方程中:y2=x3+ax+b,在SM2算法通过制定公式中a,b的系统,确定唯一标准曲线。同时为了让曲线映射为加密算法,也确定其他参数,为算法程序使用。SM2算法一般做为签名、密钥交换、加密应用。


算法标准过程:

  • 签名、验签计算过程。

  • 加密、解密计算过程。

  • 密钥协商计算过程。


在计算速度来说,SM2签名速度快、验签速度较慢。在签名原始数据无限制,签名结果为64字节。


SM2代码可参考:

http://download.csdn.net/download/goldboar/3833072

参考:http://www.docin.com/p-682659780.html

版权申明:本内容来自于互联网,属第三方汇集推荐平台。本文的版权归原作者所有,文章言论不代表链门户的观点,链门户不承担任何法律责任。如有侵权请联系QQ:3341927519进行反馈。
相关新闻
发表评论

请先 注册/登录 后参与评论

    回顶部