0


SM3加密与解密校验

SM3密码杂凑算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准。具体算法标准原始文本参见参考文献[1]。该算法于2012年发布为密码行业标准(GM/T 0004-2012),2016年发布为国家密码杂凑算法标准(GB/T 32905-2016)。

SM3适用于商用密码应用中的数字签名和验证,是在[SHA-256]基础上改进实现的一种算法,其安全性和SHA-256相当。SM3和MD5的迭代过程类似,也采用Merkle-Damgard结构。消息分组长度为512位,摘要值长度为256位。

整个算法的执行过程可以概括成四个步骤:消息填充、消息扩展、迭代压缩、输出结果。

在这里插入图片描述

消息填充

SM3的消息扩展步骤是以512位的数据分组作为输入的。因此,我们需要在一开始就把数据长度填充至512位的倍数。数据填充规则和MD5一样,具体步骤如下:

1、先填充一个“1”,后面加上k个“0”。其中k是满足(n+1+k) mod 512 = 448的最小正整数。

2、追加64位的数据长度(bit为单位,大端序存放1。观察算法标准原文附录A运算示例可以推知。)

image-20211201092756591

消息扩展

SM3的迭代压缩步骤没有直接使用数据分组进行运算,而是使用这个步骤产生的132个消息字。(一个消息字的长度为32位/4个字节/8个16j进制数字)概括来说,先将一个512位数据分组划分为16个消息字,并且作为生成的132个消息字的前16个。再用这16个消息字递推生成剩余的116个消息字。
在这里插入图片描述

迭代压缩

SM3的迭代过程和MD5类似,也是Merkle-Damgard结构。但和MD5不同的是,SM3使用消息扩展得到的消息字进行运算。这个迭代过程可以用这幅图表示:
在这里插入图片描述
初值IV被放在A、B、C、D、E、F、G、H八个32位变量中,其具体数值参见参考文献[1]。整个算法中最核心、也最复杂的地方就在于压缩函数。压缩函数将这八个变量进行64轮相同的计算,一轮的计算过程如下图所示:
在这里插入图片描述
在这里插入图片描述
图中不同的数据流向用不同颜色的箭头表示。

最后,再将计算完成的A、B、C、D、E、F、G、H和原来的A、B、C、D、E、F、G、H分别进行异或,就是压缩函数的输出。这个输出再作为下一次调用压缩函数时的初值。依次类推,直到用完最后一组132个消息字为止。

输出结果

将得到的A、B、C、D、E、F、G、H八个变量拼接输出,就是SM3算法的输出。
在这里插入图片描述

JAVA实现SM3加密与校验

  • 导入Maven依赖
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on --><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.70</version></dependency>
  • SM3Utils
privatestaticfinalString ENCODING ="UTF-8";/**
     * 加密
     *
     * @param src 明文
     * @param key 密钥
     * @return
     * @throws Exception
     */publicstaticStringencrypt(String src,String key)throwsException{returnByteUtils.toHexString(getEncryptByKey(src, key));}/**
     * SM3加密方式之: 根据自定义密钥进行加密,返回加密后长度为32位的16进制字符串
     *
     * @param src 源数据
     * @param key 密钥
     * @return 加密后长度为32位的16进制字符串
     * @throws Exception
     */publicstaticbyte[]getEncryptByKey(String src,String key)throwsException{byte[] srcByte = src.getBytes(ENCODING);byte[] keyByte = key.getBytes(ENCODING);KeyParameter keyParameter =newKeyParameter(keyByte);SM3Digest sm3 =newSM3Digest();HMac hMac =newHMac(sm3);
        hMac.init(keyParameter);
        hMac.update(srcByte,0, srcByte.length);byte[] result =newbyte[hMac.getMacSize()];
        hMac.doFinal(result,0);return result;}/**
     * 利用源数据+密钥校验与密文是否一致
     *
     * @param src       源数据
     * @param key       密钥
     * @param sm3HexStr 密文
     * @return
     * @throws Exception
     */publicstaticbooleanverify(String src,String key,String sm3HexStr)throwsException{byte[] sm3HashCode =ByteUtils.fromHexString(sm3HexStr);byte[] newHashCode =getEncryptByKey(src, key);returnArrays.equals(newHashCode, sm3HashCode);}/**
     * SM3加密方式之:不提供密钥的方式 SM3加密,返回加密后长度为64位的16进制字符串
     *
     * @param src 明文
     * @return 加密后长度为64位的16进制字符串
     */publicstaticStringencrypt(String src){returnByteUtils.toHexString(getEncryptBySrcByte(src.getBytes()));}/**
     * 返回长度为32位的加密后的byte数组
     *
     * @param srcByte
     * @return
     */publicstaticbyte[]getEncryptBySrcByte(byte[] srcByte){SM3Digest sm3 =newSM3Digest();
        sm3.update(srcByte,0, srcByte.length);byte[] encryptByte =newbyte[sm3.getDigestSize()];
        sm3.doFinal(encryptByte,0);return encryptByte;}/**
     * 校验源数据与加密数据是否一致
     *
     * @param src       源数据
     * @param sm3HexStr 16进制的加密数据
     * @return
     * @throws Exception
     */publicstaticbooleanverify(String src,String sm3HexStr)throwsException{byte[] sm3HashCode =ByteUtils.fromHexString(sm3HexStr);byte[] newHashCode =getEncryptBySrcByte(src.getBytes(ENCODING));returnArrays.equals(newHashCode, sm3HashCode);}publicstaticvoidmain(String[] args)throwsException{String srcStr ="今天天气很晴朗";String key ="zjqzjq";// ******************************自定义密钥加密及校验*****************************************String hexStrByKey =SM3Utils.encrypt(srcStr, key);System.out.println("带密钥加密后的密文:"+ hexStrByKey);System.out.println("明文(带密钥)与密文校验结果:"+SM3Utils.verify(srcStr, key, hexStrByKey));// ******************************无密钥的加密及校验******************************************String hexStrNoKey =SM3Utils.encrypt(srcStr);System.out.println("不带密钥加密后的密文:"+ hexStrNoKey);System.out.println("明文(不带密钥)与密文校验结果:"+SM3Utils.verify(srcStr, hexStrNoKey));}

注:SM3算法的实现

importjava.io.ByteArrayOutputStream;importjava.io.File;importjava.io.FileInputStream;importjava.io.FileNotFoundException;importjava.io.IOException;importjava.io.InputStream;importjava.math.BigInteger;importjava.util.Arrays;importltd.snowland.utils.NumberTool;importltd.snowland.utils.StreamTool;/**
 * SM3杂凑算法实现
 * 
 * @author Potato
 *
 */publicclass SM3 {privatestaticchar[] hexDigits ={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};privatestaticfinalString ivHexStr ="7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e";privatestaticfinalBigInteger IV =newBigInteger(ivHexStr.replaceAll(" ",""),16);privatestaticfinalIntegerTj15=Integer.valueOf("79cc4519",16);privatestaticfinalIntegerTj63=Integer.valueOf("7a879d8a",16);privatestaticfinalbyte[]FirstPadding={(byte)0x80};privatestaticfinalbyte[]ZeroPadding={(byte)0x00};privatestaticintT(int j){if(j >=0&& j <=15){returnTj15.intValue();}elseif(j >=16&& j <=63){returnTj63.intValue();}else{thrownewRuntimeException("data invalid");}}privatestaticIntegerFF(Integer x,Integer y,Integer z,int j){if(j >=0&& j <=15){returnInteger.valueOf(x.intValue()^ y.intValue()^ z.intValue());}elseif(j >=16&& j <=63){returnInteger.valueOf((x.intValue()& y.intValue())|(x.intValue()& z.intValue())|(y.intValue()& z.intValue()));}else{thrownewRuntimeException("data invalid");}}privatestaticIntegerGG(Integer x,Integer y,Integer z,int j){if(j >=0&& j <=15){returnInteger.valueOf(x.intValue()^ y.intValue()^ z.intValue());}elseif(j >=16&& j <=63){returnInteger.valueOf((x.intValue()& y.intValue())|(~x.intValue()& z.intValue()));}else{thrownewRuntimeException("data invalid");}}privatestaticIntegerP0(Integer x){returnInteger.valueOf(x.intValue()^Integer.rotateLeft(x.intValue(),9)^Integer.rotateLeft(x.intValue(),17));}privatestaticIntegerP1(Integer x){returnInteger.valueOf(x.intValue()^Integer.rotateLeft(x.intValue(),15)^Integer.rotateLeft(x.intValue(),23));}privatestaticbyte[]padding(byte[] source)throwsIOException{if(source.length >=0x2000000000000000l){thrownewRuntimeException("src data invalid.");}long l = source.length *8;long k =448-(l +1)%512;if(k <0){
            k = k +512;}ByteArrayOutputStream baos =newByteArrayOutputStream();
        baos.write(source);
        baos.write(FirstPadding);long i = k -7;while(i >0){
            baos.write(ZeroPadding);
            i -=8;}
        baos.write(long2bytes(l));return baos.toByteArray();}privatestaticbyte[]long2bytes(long l){byte[] bytes =newbyte[8];for(int i =0; i <8; i++){
            bytes[i]=(byte)(l >>>((7- i)*8));}return bytes;}publicstaticbyte[]hash(byte[] source)throwsIOException{byte[] m1 =padding(source);int n = m1.length /(512/8);byte[] b;byte[] vi = IV.toByteArray();byte[] vi1 =null;for(int i =0; i < n; i++){
            b =Arrays.copyOfRange(m1, i *64,(i +1)*64);
            vi1 =CF(vi, b);
            vi = vi1;}return vi1;}publicstaticbyte[]hash(String source)throwsException{returnhash(source.getBytes());}publicstaticbyte[]hash(File file)throwsException{if(file.exists()){InputStream inStream =newFileInputStream(file);returnhash(StreamTool.readInputStream2ByteArray(inStream));}else{thrownewFileNotFoundException();}}privatestaticbyte[]CF(byte[] vi,byte[] bi)throwsIOException{int a, b, c, d, e, f, g, h;
        a =toInteger(vi,0);
        b =toInteger(vi,1);
        c =toInteger(vi,2);
        d =toInteger(vi,3);
        e =toInteger(vi,4);
        f =toInteger(vi,5);
        g =toInteger(vi,6);
        h =toInteger(vi,7);int[] w =newint[68];int[] w1 =newint[64];for(int i =0; i <16; i++){
            w[i]=toInteger(bi, i);}for(int j =16; j <68; j++){
            w[j]=P1(w[j -16]^ w[j -9]^Integer.rotateLeft(w[j -3],15))^Integer.rotateLeft(w[j -13],7)^ w[j -6];}for(int j =0; j <64; j++){
            w1[j]= w[j]^ w[j +4];}int ss1, ss2, tt1, tt2;for(int j =0; j <64; j++){
            ss1 =Integer.rotateLeft(Integer.rotateLeft(a,12)+ e +Integer.rotateLeft(T(j), j),7);
            ss2 = ss1 ^Integer.rotateLeft(a,12);
            tt1 =FF(a, b, c, j)+ d + ss2 + w1[j];
            tt2 =GG(e, f, g, j)+ h + ss1 + w[j];
            d = c;
            c =Integer.rotateLeft(b,9);
            b = a;
            a = tt1;
            h = g;
            g =Integer.rotateLeft(f,19);
            f = e;
            e =P0(tt2);}byte[] v =toByteArray(a, b, c, d, e, f, g, h);for(int i =0; i < v.length; i++){
            v[i]=(byte)(v[i]^ vi[i]);}return v;}privatestaticinttoInteger(byte[] source,int index){StringBuilder valueStr =newStringBuilder("");for(int i =0; i <4; i++){
            valueStr.append(hexDigits[(byte)((source[index *4+ i]&0xF0)>>4)]);
            valueStr.append(hexDigits[(byte)(source[index *4+ i]&0x0F)]);}returnLong.valueOf(valueStr.toString(),16).intValue();}privatestaticbyte[]toByteArray(int a,int b,int c,int d,int e,int f,int g,int h)throwsIOException{ByteArrayOutputStream baos =newByteArrayOutputStream(32);
        baos.write(toByteArray(a));
        baos.write(toByteArray(b));
        baos.write(toByteArray(c));
        baos.write(toByteArray(d));
        baos.write(toByteArray(e));
        baos.write(toByteArray(f));
        baos.write(toByteArray(g));
        baos.write(toByteArray(h));return baos.toByteArray();}publicstaticbyte[]toByteArray(int i){byte[] byteArray =newbyte[4];
        byteArray[0]=(byte)(i >>>24);
        byteArray[1]=(byte)((i &0xFFFFFF)>>>16);
        byteArray[2]=(byte)((i &0xFFFF)>>>8);
        byteArray[3]=(byte)(i &0xFF);return byteArray;}privatestaticStringbyteToHexString(byte b){int n = b;if(n <0)
            n =256+ n;int d1 = n /16;int d2 = n %16;return""+ hexDigits[d1]+ hexDigits[d2];}publicstaticStringbyteArrayToHexString(byte[] b){StringBuffer resultSb =newStringBuffer();for(int i =0; i < b.length; i++){
            resultSb.append(byteToHexString(b[i]));}return resultSb.toString();}publicstaticStringhashHex(byte[] b){try{return SM3.byteArrayToHexString(SM3.hash(b));}catch(IOException e){
            e.printStackTrace();}returnnull;}publicstaticStringhashHex(String str){returnhashHex(str.getBytes());}publicstaticvoidmain(String[] args)throwsIOException{System.out.println(SM3.byteArrayToHexString(SM3.hash("abc".getBytes())));}}
标签: java 算法 安全

本文转载自: https://blog.csdn.net/weixin_42123075/article/details/125819176
版权归原作者 猿猴一号(lxd) 所有, 如有侵权,请联系我们删除。

“SM3加密与解密校验”的评论:

还没有评论