SM4国密算法Java实现

1、基本密码部件,S盒置换,非线性变换τ,L变换,T变换

public class BasicComponents {
	private int[][] SBOX={{0xd6,0x90,0xe9,0xfe,0xcc,0xe1,0x3d,0xb7,0x16,0xb6,0x14,0xc2,0x28,0xfb,0x2c,0x05},
            {0x2b,0x67,0x9a,0x76,0x2a,0xbe,0x04,0xc3,0xaa,0x44,0x13,0x26,0x49,0x86,0x06,0x99},
            {0x9c,0x42,0x50,0xf4,0x91,0xef,0x98,0x7a,0x33,0x54,0x0b,0x43,0xed,0xcf,0xac,0x62},
            {0xe4,0xb3,0x1c,0xa9,0xc9,0x08,0xe8,0x95,0x80,0xdf,0x94,0xfa,0x75,0x8f,0x3f,0xa6},
            {0x47,0x07,0xa7,0xfc,0xf3,0x73,0x17,0xba,0x83,0x59,0x3c,0x19,0xe6,0x85,0x4f,0xa8},
            {0x68,0x6b,0x81,0xb2,0x71,0x64,0xda,0x8b,0xf8,0xeb,0x0f,0x4b,0x70,0x56,0x9d,0x35},
            {0x1e,0x24,0x0e,0x5e,0x63,0x58,0xd1,0xa2,0x25,0x22,0x7c,0x3b,0x01,0x21,0x78,0x87},
            {0xd4,0x00,0x46,0x57,0x9f,0xd3,0x27,0x52,0x4c,0x36,0x02,0xe7,0xa0,0xc4,0xc8,0x9e},
            {0xea,0xbf,0x8a,0xd2,0x40,0xc7,0x38,0xb5,0xa3,0xf7,0xf2,0xce,0xf9,0x61,0x15,0xa1},
            {0xe0,0xae,0x5d,0xa4,0x9b,0x34,0x1a,0x55,0xad,0x93,0x32,0x30,0xf5,0x8c,0xb1,0xe3},
            {0x1d,0xf6,0xe2,0x2e,0x82,0x66,0xca,0x60,0xc0,0x29,0x23,0xab,0x0d,0x53,0x4e,0x6f},
            {0xd5,0xdb,0x37,0x45,0xde,0xfd,0x8e,0x2f,0x03,0xff,0x6a,0x72,0x6d,0x6c,0x5b,0x51},
            {0x8d,0x1b,0xaf,0x92,0xbb,0xdd,0xbc,0x7f,0x11,0xd9,0x5c,0x41,0x1f,0x10,0x5a,0xd8},
            {0x0a,0xc1,0x31,0x88,0xa5,0xcd,0x7b,0xbd,0x2d,0x74,0xd0,0x12,0xb8,0xe5,0xb4,0xb0},
            {0x89,0x69,0x97,0x4a,0x0c,0x96,0x77,0x7e,0x65,0xb9,0xf1,0x09,0xc5,0x6e,0xc6,0x84},
            {0x18,0xf0,0x7d,0xec,0x3a,0xdc,0x4d,0x20,0x79,0xee,0x5f,0x3e,0xd7,0xcb,0x39,0x48}
			};
	
	
	//S盒置换,输入8位,输出8位,输入一个两位的16进制数
	int S_Box(int n){
		if(n<0||n>255){
			System.out.println("S盒输入错误");
			return 0;
		}
		int j = n%16;  //j为第二位的数
		int i = (n-j)/16;   //i为第一位的数
		//System.out.println("i:" + i + ",j:" + j);
		int result = SBOX[i][j];
		return result;
	}
	
	//非线性变换τ,4个S盒并行置换,输入32位,输出32位,输入4个两位的16进制数
	int[] PIChange(int[] n1){
		if(n1.length!=4){
			System.out.println("τ变换输入错误");
			return null;
		}
		for(int i=0;i<4;i++){
			if(n1[i]<0||n1[i]>255){
				System.out.println("τ变换输入错误");
				return null;
			}
		}
		int[] res = new int[4];
		for(int i=0;i<4;i++){
			res[i] = S_Box(n1[i]);
		}
		return res;
	}
	
	//L变换,32位输入,32位输出,输入4个两位的16进制数
	int[] LChange(int[] n1){
		if(n1.length!=4){
			System.out.println("L变换输入错误");
			return null;
		}
		for(int i=0;i<4;i++){
			if(n1[i]<0||n1[i]>255){
				System.out.println("L变换输入错误");
				return null;
			}
		}
		Tools tool = new Tools();
		String res = "";
		String B = tool.HexToStr(n1);
		res = tool.XOR(B, tool.loopleftmove(B, 2));
		res = tool.XOR(res, tool.loopleftmove(B, 10));
		res = tool.XOR(res, tool.loopleftmove(B, 18));
		res = tool.XOR(res, tool.loopleftmove(B, 24));
		int[] result = tool.BinToIntArray(res);
		return result;
	}
	
	//T变换
	int[] TChange(int[] n1){
		int[] result = new int[4];
		result = PIChange(n1);
		result = LChange(result);
		return result;
	}
	
	//L'变换,32位输入,32位输出,输入4个两位的16进制数
	int[] L_1Change(int[] n1){
		if(n1.length!=4){
			System.out.println("L变换输入错误");
			return null;
		}
		for(int i=0;i<4;i++){
			if(n1[i]<0||n1[i]>255){
				System.out.println("L变换输入错误");
				return null;
			}
		}
		Tools tool = new Tools();
		String res = "";
		String B = tool.HexToStr(n1);
		res = tool.XOR(B, tool.loopleftmove(B, 13));
		res = tool.XOR(res, tool.loopleftmove(B, 23));
		int[] result = tool.BinToIntArray(res);
		return result;
	}
	
	//T'变换
	int[] T_1Change(int[] n1){
		int[] result = new int[4];
		result = PIChange(n1);
		result = L_1Change(result);
		return result;
	}
	
	public static void main(String[] args){
		BasicComponents bc = new BasicComponents();
		int[] n = {0x11,0x12,0x13,0x14};
		int[] m = bc.PIChange(n);
		for(int i=0;i<4;i++){
			System.out.println(m[i]);
		}
		
	}
	
}

2、轮函数

public class WheelFunction {
	//轮函数方法,输入128位,输出32位,输入4个32位字的数据和一个32位的轮密钥,输出一个32位字
	int[] F(int[] tn0, int[] tn1, int[] tn2, int[] tn3, int[] rk){
		if(tn0.length!=4||tn1.length!=4||tn2.length!=4||tn3.length!=4||rk.length!=4){
			System.out.println("轮函数输入错误");
			return null;
		}
		Tools tool = new Tools();
		BasicComponents bc = new BasicComponents();
		String str = "";
		str = tool.XOR(tool.HexToStr(tn1), tool.HexToStr(tn2));
		str = tool.XOR(str, tool.HexToStr(tn3));
		str = tool.XOR(str, tool.HexToStr(rk));
		int[] res = new int[4];
		res = tool.BinToIntArray(str);
		res = bc.TChange(res);
		str = tool.HexToStr(res);
		str = tool.XOR(tool.HexToStr(tn0), str);
		res = tool.BinToIntArray(str);
		return res;
	}
	
}

3、密钥拓展算法

public class KeyExpansion {
	private String FK0 = "a3b1bac6";
	private String FK1 = "56aa3350";
	private String FK2 = "677d9197";
	private String FK3 = "b27022dc";
	private String[] CK = {"00070e15","1c232a31","383f464d","545b6269",
						"70777e85","8c939aa1","a8afb6bd","c4cbd2d9",
						"e0e7eef5","fc030a11","181f262d","343b4249",
						"50575e65","6c737a81","888f969d","a4abb2b9",
						"c0c7ced5","dce3eaf1","f8ff060d","141b2229",
						"30373e45","4c535a61","686f767d","848b9299",
						"a0a7aeb5","bcc3cad1","d8dfe6ed","f4fb0209",
						"10171e25","2c333a41","484f565d","646b7279"
						};
	
	//输入加密密钥4个32位字,输出轮密钥
	String[] wheelKey(String[] MK){
		Tools tool = new Tools();
		BasicComponents bc = new BasicComponents();
		String[] k = new String[36];  //k中存的是32位的比特串
		String[] rk = new String[32];
		String tmk = tool.HexToStr(tool.HexToIntArray(MK[0]));
		String tfk = tool.HexToStr(tool.HexToIntArray(FK0));
		k[0] = tool.XOR(tmk, tfk);
		tmk = tool.HexToStr(tool.HexToIntArray(MK[1]));
		tfk = tool.HexToStr(tool.HexToIntArray(FK1));
		k[1] = tool.XOR(tmk, tfk);
		tmk = tool.HexToStr(tool.HexToIntArray(MK[2]));
		tfk = tool.HexToStr(tool.HexToIntArray(FK2));
		k[2] = tool.XOR(tmk, tfk);
		tmk = tool.HexToStr(tool.HexToIntArray(MK[3]));
		tfk = tool.HexToStr(tool.HexToIntArray(FK3));
		k[3] = tool.XOR(tmk, tfk);
		for(int i=0;i<32;i++){
			String ts = "";
			ts = tool.XOR(k[i+1], k[i+2]);
			ts = tool.XOR(ts, k[i+3]);
			ts = tool.XOR(ts, tool.HexToStr(tool.HexToIntArray(CK[i])));
			ts = tool.HexToStr(bc.T_1Change(tool.BinToIntArray(ts)));
			ts = tool.XOR(k[i], ts);
			k[i+4] = ts;
			rk[i] = tool.IntArrayToStr(tool.BinToIntArray(ts));
		}
		return rk;
	}
	
}

4、加密算法

import java.util.ArrayList;

//加密算法

public class Encrypt {
	private String plaintext;  //明文
	private String[] MK;  //密钥
	
	public Encrypt(){
		
	}
	
	public Encrypt(String plaintext, String[] MK){
		this.plaintext = plaintext;
		this.MK = MK;
	}

	//加密入口,接受一个String类型的明文,将其依次转换成4个int数组放入encryptProcess中加密,获得输出,输出最后结果
	public ArrayList<int[]> encryptEntrance(){
		KeyExpansion ke = new KeyExpansion();
		String[] rk = ke.wheelKey(MK);  //根据密钥拓展得出轮密钥
		Tools tool = new Tools();
		plaintext = tool.fillNumber(plaintext);
		ArrayList<int[]> res = new ArrayList<int[]>();
		for(int n=0;n<plaintext.length()/16;n++){
			ArrayList<int[]> t = new ArrayList<int[]>();
			ArrayList<int[]> tres = new ArrayList<int[]>();
			String s = plaintext.substring(n*16, (n+1)*16);
			t = tool.StrToList(s);
			tres = encryptProcess(t.get(0),t.get(1),t.get(2),t.get(3),rk);
			res.add(tres.get(0));
			res.add(tres.get(1));
			res.add(tres.get(2));
			res.add(tres.get(3));
		}
		return res;
	}
	
	//加密过程,输入128位明文,4个长度为4的int数组(每一个元素为一个两位的十六进制数),输入轮密钥,输出128位密文
	ArrayList<int[]> encryptProcess(int[] n0, int[] n1, int[] n2,int[] n3, String[] rk){
		if(n0.length!=4||n1.length!=4||n2.length!=4||n3.length!=4){
			System.out.println("encrypt输入错误");
			return null;
		}
		Tools tool = new Tools();
		WheelFunction wf = new WheelFunction();
		ArrayList<int[]> x = new ArrayList<int[]>();
		x.add(n0);
		x.add(n1);
		x.add(n2);
		x.add(n3);
		for(int i=0;i<32;i++){
			int[] trk = tool.HexToIntArray(rk[i]);
			x.add(wf.F(x.get(i), x.get(i+1), x.get(i+2), x.get(i+3), trk));
		}
		ArrayList<int[]> res = new ArrayList<int[]>();
		res.add(x.get(35));
		res.add(x.get(34));
		res.add(x.get(33));
		res.add(x.get(32));
		return res;
	}
	
	
	public String getPlaintext() {
		return plaintext;
	}

	public void setPlaintext(String plaintext) {
		this.plaintext = plaintext;
	}

	public String[] getMK() {
		return MK;
	}

	public void setMK(String[] mK) {
		MK = mK;
	}
}

5、解密算法

import java.util.ArrayList;

public class Decrypt {
	private ArrayList<int[]> ciphertext;  //密文
	private String[] MK;  //密钥
	
	public Decrypt(){
		
	}
	
	public Decrypt(ArrayList<int[]> ciphertext, String[] MK){
		this.ciphertext = ciphertext;
		this.MK = MK;
	}

	//解密入口
	public String decryptEntrance(){
		KeyExpansion ke = new KeyExpansion();
		String[] rk = ke.wheelKey(MK);  //根据密钥拓展得出轮密钥
		Tools tool = new Tools();
		String res = ""; 
		for(int n=0;n<ciphertext.size()/4;n++){
			ArrayList<int[]> tal = new ArrayList<int[]>();
			tal = decryptProcess(ciphertext.get(n*4),ciphertext.get(n*4+1),ciphertext.get(n*4+2),ciphertext.get(n*4+3),rk);
			res += tool.ListToStr(tal);
		}
		res = tool.restore(res);
		return res;
	}
	
	

	//解密过程,输入128位密文,4个长度为4的int数组(每一个元素为一个两位的十六进制数),输入轮密钥,输出128位明文
	ArrayList<int[]> decryptProcess(int[] n0, int[] n1, int[] n2,int[] n3, String[] rk){
		if(n0.length!=4||n1.length!=4||n2.length!=4||n3.length!=4){
			System.out.println("decrypt输入错误");
			return null;
		}
		Tools tool = new Tools();
		WheelFunction wf = new WheelFunction();
		ArrayList<int[]> x = new ArrayList<int[]>();
		x.add(n0);
		x.add(n1);
		x.add(n2);
		x.add(n3);
		for(int i=0;i<32;i++){
			int[] trk = tool.HexToIntArray(rk[31-i]);
			x.add(wf.F(x.get(i), x.get(i+1), x.get(i+2), x.get(i+3), trk));
		}
		ArrayList<int[]> res = new ArrayList<int[]>();
		res.add(x.get(35));
		res.add(x.get(34));
		res.add(x.get(33));
		res.add(x.get(32));
		return res;
	}
	

	public void setCiphertext(ArrayList<int[]> ciphertext) {
		this.ciphertext = ciphertext;
	}
	
	public ArrayList<int[]> getCiphertext() {
		return ciphertext;
	}

	public String[] getMK() {
		return MK;
	}

	public void setMK(String[] mK) {
		MK = mK;
	}
	
}

6、工具类

import java.util.ArrayList;

public class Tools {
	//将0到255之间int类型的数转换为8位二进制的String类型表示
	public String IntToBin(int i){
		if(i<0||i>255){
			System.out.println("IntToStr输入错误");
			return null;
		}
		String str = "";
		for(int n=7;n>=0;n--){
			int t = 1<<n;  //1<<n等于2的n次方
			if(i>=t){
				str = str + "1";
				i = i-t;
			}else{
				str = str + "0";
			}
		}
		return str;
	}
	
	//把8位String类型的二进制表示转换为int类型的数
	public int BinToInt(String str){
		if(str.length()!=8){
			System.out.println("BinToInt输入错误");
			return 0;
		}
		int result = 0;
		for(int i=0;i<8;i++){
			if(str.charAt(i)=='1'){
				result += 1<<(7-i);
			}
		}
		return result;
	}
	
	//把一个包含4个两位十六进制数的数组转换成32位(二进制表示)的字符串
	public String HexToStr(int[] n1){
		String res = "";
		for(int i=0;i<n1.length;i++){
			res += IntToBin(n1[i]);
		}
		return res;
	}
	
	//将一个32位的比特串转换成一个int数组
	public int[] BinToIntArray(String str){
		if(str.length()!=32){
			System.out.println("BinToIntArray输入错误");
			return null;
		}
		int[] result = new int[4];
		result[0] = BinToInt(str.substring(0, 8));
		result[1] = BinToInt(str.substring(8, 16));
		result[2] = BinToInt(str.substring(16, 24));
		result[3] = BinToInt(str.substring(24, 32));
		return result;
	}
	
	//循环左移n位方法
	public String loopleftmove(String str,int n){
		if(n>32){
			return null;
		}
		String s1,s2,res;
		s1 = str.substring(0, n);
		s2 = str.substring(n,32);
		res = s2 + s1;
		return res;
	}
	
	//String类型的异或运算,相同为零,不同为一
	public String XOR(String str1,String str2){
		if(str1.length()!=str2.length()){
			System.out.println("XOR方法输入错误,参数长度不同");
			return null;
		}
		String res = "";
		for(int i=0;i<str1.length();i++){
			if(str1.charAt(i)==str2.charAt(i)){
				res += "0";
			}else{
				res += "1";
			}
		}
		return res;
	}	
	
	//将String表示的4个两位十六进制数转换成一个int数组
	public int[] HexToIntArray(String str){
		if(str.length()!=8){
			System.out.println("HexToIntArray输入错误");
			return null;
		}
		int[] res = new int[4];
		for(int i=0;i<4;i++){
			int sum = 0;
			if(str.charAt(2*i)>=48&&str.charAt(2*i)<=57){
				sum += (str.charAt(2*i)-48)*16;
			}else{
				sum += (str.charAt(2*i)-87)*16;
			}
			if(str.charAt(2*i+1)>=48&&str.charAt(2*i+1)<=57){
				sum += str.charAt(2*i+1)-48;
			}else{
				sum += str.charAt(2*i+1)-87;
			}
			res[i] = sum;
		}
		return res;
	}
	
	//将一个长度为4的int数组装换成String类型的十六进制表示
	public String IntArrayToStr(int[] n1){
		if(n1.length!=4){
			System.out.println("IntArrayToStr输入错误");
			return null;
		}
		String res = "";
		for(int i=0;i<4;i++){
			res += IntToHex(n1[i]);
		}
		return res;
	}
	
	//将一个int数转换成一个两位的十六进制数
	public String IntToHex(int i){
		String res = "";
		//第一位数是n,第二位是变换后的i
		int n=15;
		for(;n>=0;n--){
			if(n*16<=i){
				i = i-n*16;
				break;
			}
		}
		if(n>9){
			res = res + (char)(n+87);
		}else{
			res = res + n;
		}
		if(i>9){
			res = res + (char)(i+87);
		}else{
			res = res + i;
		}
		return res;
	}
	
	//若str不能整除16则用" "补齐位数
	public String fillNumber(String str){
		int m = str.length()%16;
		if(m!=0){
			for(int n=0;n<(16-m%16);n++){
				str += " ";
			}
		}
		return str;
	}
	
	//若str末尾有" ",则将末尾的" "全都去掉
	public String restore(String str){
		while(str.charAt(str.length()-1)==' '){
			str = str.substring(0, str.length()-1);
		}
		return str;
	}
	
	//将一个16位的字符串转化成4个长度为4的int数组存入ArrayList中
	public ArrayList<int[]> StrToList(String str){
		if(str.length()!=16){
			System.out.println("StrToList输入错误");
			return null;
		}
		ArrayList<int[]> res = new ArrayList<int[]>();
		for(int n=0;n<4;n++){
			int[] t = new int[4];
			t[0] = str.charAt(n*4);
			t[1] = str.charAt(n*4+1);
			t[2] = str.charAt(n*4+2);
			t[3] = str.charAt(n*4+3);
			res.add(t);
		}
		return res;
	}
	
	//将ArrayList中的数提出来转换为String
	public String ListToStr(ArrayList<int[]> al){
		String res = "";
		for(int n=0;n<4;n++){
			int[] t = al.get(n);
			for(int i=0;i<4;i++){
				res += (char)t[i];
			}
		}
		return res;
	}
	
	public static void main(String[] args){
		Tools tool = new Tools();
		String s = "abcdABCDjigi1234";
		ArrayList<int[]> a = tool.StrToList(s);
		System.out.println(tool.ListToStr(a));
		
	}
	
}

猜你喜欢

转载自blog.csdn.net/MessiNine/article/details/79998791
今日推荐