• SM3国密算法标准中两个实例的实现


    来源于CSDN博客:https://blog.csdn.net/ErErFei/article/details/50998162
    代码新增内容:在原博客的基础上,整合了各个类的方法,同时增添了SM3国密标准中的第二个案例的验证,并尝试将原代码中的缓冲区长度修改为64*2,本代码作者是在命令行里面运行通过的。如有运行问题,请各位能够反馈,互相学习;

    public class ren_SM3
    {
    /**IV为256比特初始值,32个字节,修饰为静态最终变量,不可改变,比如0x80值(128)范围超过byte表示范围(-128~127),所以需要强制转换*/
    private static final byte[] IV = { 0x73, (byte)0x80, 0x16, 0x6f, 0x49, 0x14, (byte) 0xb2, (byte) 0xb9, 0x17, 0x24, 0x42, (byte) 0xd7, (byte) 0xda, (byte) 0x8a, 0x06, 0x00, (byte) 0xa9, 0x6f, 0x30, (byte) 0xbc, (byte) 0x16, 0x31, 0x38, (byte) 0xaa, (byte) 0xe3, (byte) 0x8d, (byte) 0xee, 0x4d, (byte) 0xb0, (byte)0xfb, (byte)0x0e, 0x4e };

    /**由于IV不可改变,而在64次迭代过程中需要一个不断改变的V,所以重新定义一个。*/
    private byte[] V= IV.clone();
    
    /** SM3分组长度 */
    private static final int BLOCK_LENGTH = 64;
    
    /** 缓冲区长度 */
    private static final int BUFFER_LENGTH = BLOCK_LENGTH * 2;
    
    /*缓冲区偏移量*/
    private int xBufOff;
    
    /*缓冲区,缓冲区长度是64,这个缓冲区指的什么?指的明文进入内存后,算法中要求需要将消息进行512比特分组,
    然后对每组进行迭代,由于对消息原文是不能有改变的,所以需要将分组后的消息进行复制一份。*/
    private byte[] xBuf = new byte[BUFFER_LENGTH];
    
    private int cntBlock = 0;//用于记录明文分组的个数,计算消息长度时需要用到。
    
    public static int[] Tj = new int[64];
     
    static
    {
        for (int i = 0; i < 16; i++)
        {
            Tj[i] = 0x79cc4519;
        }
     
        for (int i = 16; i < 64; i++)
        {
            Tj[i] = 0x7a879d8a;
        }
    }
    /*
    *@param in明文输入缓冲区
    *@param inOff明文输入缓冲区偏移量
    *@param len明文输入长度
    */
    public void update(byte[] in,int inOff)
    {
    	
    	int inputLen = in.length;//明文的长度
    	int dPos = inOff;//明文输入缓冲区偏移量,一开始是0
    	if(BUFFER_LENGTH<inputLen)//如果缓冲区长度小于明文长度
    	{
    		System.arraycopy(in,dPos,xBuf,0,BUFFER_LENGTH);
    		inputLen =  inputLen - BUFFER_LENGTH;//明文输入长度减去进入缓冲区后剩下的长度
    		dPos = dPos+ BUFFER_LENGTH;
    		doUpdate();
    		while(inputLen>BUFFER_LENGTH)
    		{
    			System.arraycopy(in,dPos,xBuf,0,BUFFER_LENGTH);
    			inputLen = inputLen - BUFFER_LENGTH;
    			dPos = dPos+BUFFER_LENGTH;
    			doUpdate();
    		}
    	}
    	if(inputLen>0)
    	{
    		System.arraycopy(in,dPos,xBuf,0,inputLen);
    		xBufOff = inputLen;
    	}
    }
    public void doUpdate()//将缓冲区的内容复制到一份新的字节数组中。然后对字节数组作用。
    {
    	byte [] B = new byte[BLOCK_LENGTH];
    	for(int i=0;i<BUFFER_LENGTH;i=i+BLOCK_LENGTH)
    		{
    			System.arraycopy(xBuf,i,B,0,BLOCK_LENGTH);
    			doHash(B);
    		}
    	xBufOff=0;
    }
    private void doHash(byte[] B)
    {
    	V = CF(V,B);
    	//System.arraycopy(tmp,0,V,0,V.length);
    		
    	cntBlock++;
    }
    private byte[] CF(byte[] V,byte[] B)
    {
    	int[] v,b;
    	v = convert(V);
    	b = convert(B);
    	return convert(CF(v,b));
    }
    private int[] convert(byte[] arr)
    {
    	int[] out = new int[arr.length/4];
    	byte[] tmp = new byte[4];
    	for(int i =0;i<arr.length;i+=4)
    		{
    			System.arraycopy(arr,i,tmp,0,4);
    			out[i/4]=bigEndianByteToInt(tmp);
    		}
    		return out;
    }
    private int bigEndianByteToInt(byte[] in)
    {
    	int num = 0;
        int temp;
        temp = (0x000000ff & (in[3])) << 0;
        num = num | temp;
        temp = (0x000000ff & (in[2])) << 8;
        num = num | temp;
        temp = (0x000000ff & (in[1])) << 16;
        num = num | temp;
        temp = (0x000000ff & (in[0])) << 24;
        num = num | temp;
        return num;
    }
    public int[] CF(int[] v,int[] n)
    {
    	int a,b,c,d,e,f,g,h;
    	int ss1,ss2,tt1,tt2;
    	a = v[0];
    	b=v[1];
    	c=v[2];
    	d=v[3];
    	e=v[4];
    	f=v[5];
    	g=v[6];
    	h=v[7];
    	System.out.println(getHexString(bigEndianIntToByte(a))+getHexString(bigEndianIntToByte(b))+" "
    					  +getHexString(bigEndianIntToByte(c))+getHexString(bigEndianIntToByte(d))+" "
    				      +getHexString(bigEndianIntToByte(e))+getHexString(bigEndianIntToByte(f))+" "
    					  +getHexString(bigEndianIntToByte(g))+getHexString(bigEndianIntToByte(h)));
    	int[][]arr = expand(n);
    	int []W=arr[0];
    	int []W1 = arr[1];
    	System.out.println("扩展后W[]的值为:");
    	for(int j =0;j<68;j++)
    	{
    		System.out.print(getHexString(bigEndianIntToByte(W[j]))+" ");
    		if((j+1)%8==0)
    			System.out.println();
    	}
    	System.out.println();
    	System.out.println("扩展后W1[]的值为:");
    	for(int j =0;j<64;j++)
    	{
    		System.out.print(getHexString(bigEndianIntToByte(W[j]))+" ");
    		if((j+1)%8==0)
    			System.out.println();
    	}
    	System.out.println();
    	for(int j =0;j<64;j++)
    	{
    		ss1 = bitCycleLeft(a,12)+e+bitCycleLeft(Tj[j],j%32);
    		ss1 = bitCycleLeft(ss1,7);
    		ss2 = ss1^bitCycleLeft(a,12);
    		tt1 = FFj(a,b,c,j)+d+ss2+W1[j];
    		tt2 = GGj(e,f,g,j)+h+ss1+W[j];
    		d=c;
    		c = bitCycleLeft(b,9);
    		b=a;
    		a = tt1;
    		h=g;
    		g=bitCycleLeft(f,19);
    		f=e;
    		e=P0(tt2);
    		System.out.println(j+":  "+getHexString(bigEndianIntToByte(a))+getHexString(bigEndianIntToByte(b))+" "
    						  +getHexString(bigEndianIntToByte(c))+getHexString(bigEndianIntToByte(d))+" "
    						  +getHexString(bigEndianIntToByte(e))+getHexString(bigEndianIntToByte(f))+" "
    						  +getHexString(bigEndianIntToByte(g))+getHexString(bigEndianIntToByte(h)));
    	}
    	int []out = new int[8];
    	out[0] = a^v[0];
    	out[1] = b^v[1];
    	out[2] = c^v[2];
    	out[3]= d^v[3];
    	out[4] = e^v[4];
    	out[5] = f^v[5];
    	out[6] = g^v[6];
    	out[7] = h^v[7];
    	return out;
    }
    public int[][] expand(int[] b)
    {
    	int []W =new int[68];
    	int[] W1 = new int[64];
    	for(int i=0;i<16;i++)
    	{
    		W[i] = b[i];
    	}
    	for(int i =16;i<68;i++)
    	{
    	W[i] = P1(W[i-16]^W[i-9]^bitCycleLeft(W[i-3],15))^bitCycleLeft(W[i-13],7)^W[i-6];
    	}
    	for(int i =0;i<64;i++)
    	{
    		W1[i] = W[i]^W[i+4];
    	}
    	int[][] arr = new int[][]{W,W1};
    	return arr;
    }
    public int bitCycleLeft(int target,int bitLen)
    {
    	byte[] tmp = bigEndianIntToByte(target);
    	int byteLen = bitLen/8;
    	int len = bitLen%8;
    	if(byteLen>0)
    	{
    		tmp = byteCycleLeft(tmp,byteLen);
    	}
    	if(len>0)
    	{
    		tmp = bitSmall8CycleLeft(tmp,len);
    	}
    	return bigEndianByteToInt(tmp);
    }
    public byte[] bigEndianIntToByte(int n)
    {
    	byte[] tmp = new byte[4];
    	tmp[3] = (byte)(n>>0);
    	tmp[2] = (byte)(n>>8);
    	tmp[1] = (byte)(n>>16);
    	tmp[0] = (byte)(n>>24);
    	return tmp;
    }	
    public byte[] byteCycleLeft(byte[] in,int n)
    {
    	byte[] tmp = new byte[in.length];
        System.arraycopy(in, n, tmp, 0, in.length - n);
        System.arraycopy(in, 0, tmp, in.length - n, n);
        return tmp;
    }
    public byte[] bitSmall8CycleLeft(byte[] in,int n)
    {
    	byte[] tmp = new byte[in.length];
    	int t1, t2, t3;
    	for(int j=0;j<tmp.length;j++)
    	{
    		t1 = (byte)((in[j])<<n);
    		t2 = (byte)(((in[(j+1)%tmp.length])&0x000000ff)>>(8-n));
    		t3 = (byte)(t1|t2);
    		tmp[j]=(byte)t3;
    	}
    	return tmp;
    }
    public int FFj(int a,int b ,int c,int j)
    {
    	if(j>=0&&j<=15)
    	{
    		return a^b^c;
    	}
    	else
    	{
    		return (a&b)|(a&c)|(b&c);
    	}
    }
    public int GGj(int a,int b ,int c,int j)
    {
    	if(j>=0&&j<=15)
    	{
    		return a^b^c;
    	}
    	else
    	{
    		return (a&b)|(~a&c);
    	}
    }
    public int P0(int a)
    {
    	int tmp = a^bitCycleLeft(a,9)^bitCycleLeft(a,17);
    	return tmp;
    }
    public int P1(int a)
    {
    	int tmp = a^bitCycleLeft(a,15)^bitCycleLeft(a,23);
    	return tmp;
    }
    public byte[] convert(int[] v)
    {
    	byte[] out = new byte[v.length*4];
    	int[] in = new int[v.length];
    	for(int i=0;i<v.length;i++)
    	{
    		System.arraycopy(v,0,in,0,v.length);
    		out[4*i+3] = (byte)(in[i]>>0);
    		out[4*i+2] = (byte)(in[i]>>8);
    		out[4*i+1] = (byte)(in[i]>>16);
    		out[4*i+0] = (byte)(in[i]>>24);
    	}
    	return out;
    }
    public byte[] doFinal()
    {
    	byte[] B= new byte[BLOCK_LENGTH];
    	byte[] buffer = new byte[xBufOff];
    	System.arraycopy(xBuf,0,buffer,0,buffer.length);
    	byte[] tmp = padding(buffer,cntBlock);
    	for(int i=0;i<tmp.length;i+=64)//此处填充后tmp长度可能为64*2,也可能为64
    	{
    		System.arraycopy(tmp,i,B,0,B.length);
    		doHash(B);
    	}
    	
    	return V;
    }
    /*
    *@param in需要填充的最后一组字节数组
    *@param blen消息的分组次数
    *return 填充后的字节数组,注意当填充前数组为64字节时,填充后数组会比原来多一组。
    */
    public byte[] padding(byte[] in,int blen)
    {
    	long l= blen*BUFFER_LENGTH*8+in.length*8;
    	int k = 448-(in.length*8+8)%512;
    	if(k<0)
    	{
    		k= 960-(in.length*8+8)%512;
    	}
    	byte[] padd=new byte[k/8+1];
    	padd[0]=(byte)0x80;
    	byte[] out = new byte[in.length+k/8+1+64/8];
    	int pos = 0;
    	System.arraycopy(in,0,out,pos,in.length);
    	pos = pos+in.length;
    	System.arraycopy(padd,0,out,pos,k/8+1);
    	pos = pos+k/8+1;
    	byte[] tmp = longToBytes(l);
    	System.arraycopy(tmp,0,out,pos,64/8);
    	return out;
    }
    public byte[] longToBytes(long n)
    {
    	byte[] bytes = new byte[8];
    	for(int i=0;i<8;i++)
    	{
    		bytes[7-i] = (byte)(0xff&(n>>(i*8)));
    	}
    	return bytes;
    }
    public String getHexString(byte[] bt)
    {
    	String str = "";
    	for(int i = 0;i<bt.length;i++)
    	{
    		
    		str+=String.format("%02x",bt[i]&0xff);
    		if(i%4==3)
    			str+=" ";
    	}
    	return str;
    }
    public static void main(String[] args)
    {
                byte[] md = new byte[32];
    	byte[] msg1 = {0x61,0x62,0x63};
                ren1_SM3 sm3 = new ren1_SM3();
                sm3.update(msg1, 0);
                md = sm3.doFinal();
    	System.out.println("第一个例子的摘要值为"+sm3.getHexString(md));
    	byte[] msg2 = {0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
    					0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
    					0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,
    					0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64,0x61,0x62,0x63,0x64};
    	ren1_SM3 sm3_1 = new ren1_SM3();
    	sm3_1.update(msg2, 0);
                md = sm3_1.doFinal();
    	System.out.println("第二个例子的摘要值为"+sm3_1.getHexString(md));
    }
    

    }

  • 相关阅读:
    struct{} //长篇更新
    channel //长篇更新
    切片 //长篇更新
    引用
    核心:数据篇
    ARM指令解析
    arm寄存器解析
    Java-Selenium,获取下拉框中的每个选项的值,并随机选择某个选项
    log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
    eclipse安装springsource-tool-suite遇到的问题及解决方案
  • 原文地址:https://www.cnblogs.com/xpren/p/11392045.html
Copyright © 2020-2023  润新知