Criptografía en la ruta de crecimiento de los programadores: explicación detallada del descifrado del algoritmo AES y presentación del código

Hola a todos en csdn, estoy de regreso. Este artículo es un artículo complementario a la última introducción al algoritmo de cifrado AES. El enfoque estará en el proceso de descifrado del algoritmo AES y el código para el cifrado y descifrado AES. [Temporalmente no incluye iv o compensación]. Sígueme en el mundo del descifrado AES.

Explicación detallada del cifrado AES

Si tiene alguna pregunta sobre el algoritmo AES o el cifrado AES, puede consultar mi artículo anterior.
https://blog.csdn.net/qq_31236027/article/details/129796471

Descifrado AES

En comparación con el descifrado DES, que solo necesita intercambiar el orden del grupo de claves, el descifrado AES será más engorroso.

proceso general

Suponiendo que todos entiendan el proceso de encriptación de AES, entonces sabemos que hay 11 rondas de encriptación, y lo mismo ocurre con la desencriptación. En la primera ronda de cifrado, solo se realiza una ronda de adición de claves, y en la última ronda de cifrado, no se requiere confusión de columnas. El proceso de descifrado es todo lo contrario. Para el descifrado, primero invierte la última ronda de encriptación y luego avanza recursivamente hasta que se invierte la primera ronda de encriptación, como se muestra en la figura a continuación.
inserte la descripción de la imagen aquí
Después de comprender el proceso completo, usemos la idea de "divide y vencerás" para explicar las dificultades por separado.

clave redonda más

La clave participa en la operación de atrás hacia adelante, es decir, la clave de la última ronda de cifrado participa en la primera ronda de descifrado. Para la conveniencia de la programación, podemos usar variables globales para almacenar claves de cifrado y descifrado. Aquí no presentaré demasiado sobre el principio de disposición de la clave. Si tiene alguna pregunta, consulte mi blog anterior sobre el cifrado AES.

cambio de fila inverso

En el algoritmo de cifrado AES, la
primera fila de desplazamiento de fila permanece sin cambios, la segunda fila se desplaza cíclicamente un bit a la izquierda, la tercera fila se desplaza cíclicamente a la izquierda dos bits y la cuarta fila se desplaza cíclicamente a la izquierda por tres bits.
inserte la descripción de la imagen aquí
Es decir, B[0][1] -> B[1][2] en la matriz original 4*4 (B1 -> B5 en la figura) [Nota, esta matriz se lee de arriba hacia abajo , de arriba a abajo Leer de izquierda a derecha].
Para facilitar la comprensión y el cálculo, podemos convertir esta matriz en un arreglo unidimensional, es decir, B[0] = B[0][0] = B0, B[1] = B[0][1] = B1, B[2] = B[0][2] = B2 ... B[16] = B[3][3] = B15, luego usamos la inducción matemática, según B[1] ->
B [5 después de cambiar], B[2] -> B[10], B[3]->B[15] Fácil de obtener: B[i] = B[(4 * (i/4) + 5 * ( i % 4)) mod 16] [i es el subíndice] [combinado con la imagen es más fácil de entender]

Lo anterior es el algoritmo de cambio de fila en el cifrado.Después de comprender este punto, el cambio de fila inverso de descifrado se vuelve simple.
El descifrado no es más que cambiar el desplazamiento a la izquierda por el desplazamiento a la derecha, es decir, la primera fila no se mueve, la segunda fila se desplaza un bit a la derecha, la tercera fila se desplaza dos bits a la derecha y la cuarta fila se desplaza tres. bits a la derecha. Como se muestra en la figura a continuación,
inserte la descripción de la imagen aquí
se convierte en
inserte la descripción de la imagen aquí
【Nota, esta matriz se lee de arriba a abajo y de izquierda a derecha】.
Para facilitar la comprensión y el cálculo, podemos convertir esta matriz en un arreglo unidimensional, es decir, B[0] = B[0][0] = B0, B[1] = B[0][1] = B1, B[2] = B[0][2] = B2 ... B[16] = B[3][3] = B15, entonces podemos obtener fácilmente por inducción matemática: B[i] =
B [(4 * (i/4) + 13 * (i % 4))mod 16] [i es el subíndice] [combinado con imágenes para facilitar la comprensión]

ofuscación de columna inversa

Ofuscación de columna en el algoritmo de encriptación AES
Use la suma y la multiplicación de la operación de campo de Galois [Para obtener detalles sobre el campo de Galois, consulte el artículo de introducción de AES, todas las operaciones son operaciones de módulo] Calcule el producto de la matriz de texto cifrado y la confusión de columna solucionada matriz y luego obtener la matriz resultante. La matriz fija se muestra en la figura a continuación:
inserte la descripción de la imagen aquí
para facilitar el cálculo, la matriz también puede ser unidimensional y luego usarse para operaciones de módulo. Aquí utilizo un esquema de operación de módulo relativamente rápido:
/**
* Explicación del algoritmo:
* La multiplicación de campos de Galois tiene como valor predeterminado la operación de módulo
* (110)2 * (11)2 => (x^2 + x ) * (x + 1) => x^3 + x^2 + x^2 + x => x^3 + x => (1010)2 * Puede entenderse como el primer desplazamiento de (110)2 a la izquierda un bit Realice la operación XOR
con (110) para obtener => (1010)2
*/`
while (i < longitud del módulo 2) { resultado ^=(numb << (longitud del módulo 2 - i)); //Indica el módulo 1 El valor cambiado a la izquierda por n bits se almacena en resultado y XORed con el valor anterior. Ver Explicación del algoritmo para más detalles. i self-increment } donde numb es el valor del módulo 1. Posteriormente, si el resultado de la operación de módulo matricial supera los 8 bits, se debe naturalizar, es decir, se hará XOR con el polinomio irreducible m(x)=x8+x4+x3+x+1 (0X11B)



Después de comprender la ofuscación de la columna del algoritmo AES, la ofuscación de la columna del descifrado AES se vuelve simple. Solo necesita modificar la matriz fija, como se muestra a continuación: {"0E", "0B", "0D", "09" }
,
{"09", "0E", "0B", "0D"},
{"0D", "09", "0E", "0B"},
{"0B", "0D", "09", " 0E"}

sustitución inversa de bytes

Esto es relativamente simple Al igual que el cifrado, los primeros 4 dígitos del texto cifrado de 8 dígitos se usan como el número de filas, y los últimos 4 dígitos se usan como el número de columnas para obtener el valor en el cuadro s invertido.

Invertir la caja s:

/**
	 * 逆向s-盒
	 */
	public static final String[][] REVERSE_SBOX = {
    
    
			{
    
    "52","09","6A","D5","30","36","A5","38","BF","40","A3","9E","81","F3","D7","FB"},
			{
    
    "7C","E3","39","82","9B","2F","FF","87","34","8E","43","44","C4","DE","E9","CB"},
			{
    
    "54","7B","94","32","A6","C2","23","3D","EE","4C","95","0B","42","FA","C3","4E"},
			{
    
    "08","2E","A1","66","28","D9","24","B2","76","5B","A2","49","6D","8B","D1","25"},
			{
    
    "72","F8","F6","64","86","68","98","16","D4","A4","5C","CC","5D","65","B6","92"},
			{
    
    "6C","70","48","50","FD","ED","B9","DA","5E","15","46","57","A7","8D","9D","84"},
			{
    
    "90","D8","AB","00","8C","BC","D3","0A","F7","E4","58","05","B8","B3","45","06"},
			{
    
    "D0","2C","1E","8F","CA","3F","0F","02","C1","AF","BD","03","01","13","8A","6b"},
			{
    
    "3A","91","11","41","4F","67","DC","EA","97","F2","CF","CE","F0","B4","E6","73"},
			{
    
    "96","AC","74","22","E7","AD","35","85","E2","F9","37","E8","1C","75","DF","6E"},
			{
    
    "47","F1","1A","71","1D","29","C5","89","6F","B7","62","0E","AA","18","BE","1B"},
			{
    
    "FC","56","3E","4B","C6","D2","79","20","9A","DB","C0","FE","78","CD","5A","F4"},
			{
    
    "1F","DD","A8","33","88","07","C7","31","B1","12","10","59","27","80","EC","5F"},
			{
    
    "60","51","7F","A9","19","B5","4A","0D","2D","E5","7A","9F","93","C9","9C","EF"},
			{
    
    "A0","E0","3B","4D","AE","2A","F5","B0","C8","EB","BB","3C","83","53","99","61"},
			{
    
    "17","2B","04","7E","BA","77","D6","26","E1","69","14","63","55","21","0C","7d"}
	};

Ideas de diseño

Después de dominar el proceso de descifrado y las ideas de algoritmos, podemos diseñar el descifrado.

  1. En primer lugar, la agrupación de texto cifrado se realiza mediante un método de descifrado.
  2. El descifrado de cada grupo se logra a través del método baseDecrypt.
  3. El descifrado iterativo se realiza a través del método decLoop (escriba la adición de clave redonda, la confusión de columnas, el desplazamiento de filas y la sustitución de bytes en él).
  4. Salida de texto sin formato.

El siguiente es el código oficial:
consulte el artículo para obtener detalles sobre la conversión del sistema binario:
Criptografía Capítulo adicional sobre el crecimiento de los programadores ----- Cadena (ascii) a binario https://blog.csdn.net/qq_31236027/ artículo/detalles/128579451

package aes;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import common.EncodeUtil;
import common.IEncrytion;
import common.EncodeUtil.EncodeRadix;
import constant.AESConstant;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * aes 加解密工具(无iv【偏移量】版)
 * @author zygswo
 *
 */
public class AesUtil implements IEncrytion{
    
    
	
	/**
	 * 密钥对象
	 */
	private KeyUtil subKeyObj = new KeyUtil().init(); 
	/**
	 * subkeys
	 */
	public List<String> subKeys = Collections.synchronizedList(new ArrayList<>());

	/**
	 * 分组加密(128位一组)
	 * @param text 明文
	 */
	@Override
	public String encrypt(String text) {
    
    
		StringBuilder sb = new StringBuilder();
		int textLen = text.length();
		//获取分组长度
		// DIV_LEN * CHAR_LEN = 128
		// 根据DIV_LEN进行分组,如CHAR_LEN=16位,那么就每8个字符一组
		int divLen = textLen % AESConstant.DIV_LEN == 0 ? textLen / AESConstant.DIV_LEN : (textLen / AESConstant.DIV_LEN + 1);
		//份组加密处理
		for (int i = 0; i < divLen; i++) {
    
    
			int startIndex = i * AESConstant.DIV_LEN;
			int endIndex = (startIndex + AESConstant.DIV_LEN) >= textLen ? textLen : (startIndex + AESConstant.DIV_LEN);
			String substr = text.substring(startIndex, endIndex);
			//尾部填充
			while(substr.length() < AESConstant.DIV_LEN) {
    
    
				substr += " ";
			}
			sb.append(baseEncrypt(substr));
		}
		return new BASE64Encoder().encode(sb.toString().toLowerCase().trim().getBytes());
	}
	
	/**
	 * 加密(每个密文都是128位)
	 * @param text 需要加密的文本
	 * @return
	 */
	private String baseEncrypt(String text) {
    
    
		//获取11组密钥
		if (subKeys == null || subKeys.isEmpty()) {
    
    
			subKeys = subKeyObj.generateKeys();
		}
		if (subKeys.size() != 11) {
    
    
			throw new IllegalArgumentException("密钥长度有误");
		}
		//转成16进制
		return EncodeUtil.binaryToHexStr(
				encloops(text, subKeys)
		).trim();
	}

	/**
	 * 10轮循环加密
	 * @param step1Result 初始置换后的结果
	 * @param subKeys 16组子密钥
	 * @return 循环加密结果
	 */
	private String encloops(String text, List<String> subKeys) {
    
    
		//转二进制
		String binTempStr = EncodeUtil.strtoBinary(text, AESConstant.CHAR_LEN);
		//1.初始化密钥加法层
//		System.out.println("binTempStr0 = " + binTempStr);
		binTempStr = xor(binTempStr, subKeys.get(0));
		//第一轮至第十轮
		for(int level = 1; level <= 10; level++) {
    
    
//			System.out.println("binTempStr1 = " + binTempStr);
			//2.字节代换层
			String[] temp = replace(binTempStr, AESConstant.SBOX);
			//3.扩撒层
			//3.1 行位移
			temp = shiftRow(temp);
			//3.2列混淆
			if (level < 10) {
    
    
				binTempStr = mixColumn(temp);
//				System.out.println("binTempStr3 = " + binTempStr);
			} else {
    
    
				binTempStr = "";
				for(String str:temp) {
    
    
					binTempStr += str;
				}
			}
//			System.out.println("binTempStr4 = " + binTempStr);
			//4.密钥加法层
			binTempStr = xor(binTempStr, subKeys.get(level));
//			System.out.println("binTempStr5 = " + binTempStr);
		}
//		System.out.println("binTempStr6 = " + binTempStr);
		return binTempStr;
	}
	
	/**
	 * 列混淆 【重点】
	 * @param _8bitArr 8位字符串数组 (2进制)
	 * @return 返回2进制字符串,方便后续的密钥加法
	 */
	private String mixColumn(String[] _8bitArr) {
    
    
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < _8bitArr.length; i+=4) {
    
    
			/**
			 * 注意:在列混淆中,每一位代表着x的指数,如(2)16=>(10)2 => x, (3)16=>(11)2 => x+1、 (25)16 => (0010 0101)2【采用十六进制】
			 * 使用矩阵乘积后的结果作为每一字节位上的结果,矩阵相乘用到了异或和或运算,异或模拟GF(2^8)域相乘,或模拟不同位相加
			 * 
			 * 如
			 * (01)16*(25)16=>		 x^5 	   + x^2 	 + 1
			 * (01)16*(25)16=> 		 x^5 	   + x^2	 + 1
			 * (02)16*(25)16=> x^6 		 + x^3 		 + x
			 * (03)16*(25)16=> x^6 + x^5 + x^3 + x^2 + x + 1
			 * +____________________________________________
			 * 				   		 x^5 	   + x^2 	 + 1
			 * 
			 * 注意如果度》8 要进行模约简
			 * 模约简方式,与不可约多项式m(x)=x8+x4+x3+x+1(十六进制表示为'11B')进行相加运算(异或)
			 */
			for (int j = 0; j < AESConstant.MIX_COLUMN_BOX.length; j++) {
    
    
				int res = 0;
				int rowNb = j;
				for (int m = 0; m < AESConstant.MIX_COLUMN_BOX[0].length; m++) {
    
    
					res ^= Integer.parseInt(
						EncodeUtil.binaryToDec(
								multiply(_8bitArr[i+j], AESConstant.MIX_COLUMN_BOX[rowNb][m])
						)	
					);
				}
				//超过了8位就和不可约多项式进行异或
				if (res >= 0x100) {
    
    
					res ^= 0x11B;  //11B => 不可约多项式m(x)=x8+x4+x3+x+1
				}
				//转二进制
				String finalRes = EncodeUtil.toBinary(res + "",EncodeRadix.DEC);
				//扩充
				while(finalRes.length() < 8) {
    
    
					finalRes = "0" + finalRes;
				}
				sb.append(finalRes);
			}
		}
		return sb.toString();
	}

	/**
	 * 二进制相乘
	 * @param source - 要处理的数(2进制)
	 * @param columnBox - 列混淆box(16进制)
	 * @return 相乘后结果(2进制)
	 */
	private String multiply(String source, String columnBox) {
    
    
		//将乘数十六进制转为二进制
		String temp = EncodeUtil.toBinary(columnBox, EncodeRadix.HEX);
		int result = 0;
		for (int i = 0; i < temp.length(); i++) {
    
    
			//如果开头位为0就跳过
			if (temp.charAt(i) == '0') {
    
    
				continue;
			}
			//否则就进行计算
			//转10进制
			int numb = Integer.parseInt(
				EncodeUtil.binaryToDec(source)
			);
			/**
			 * 算法解释:
			 * 伽罗瓦域乘法默认为模数运算
			 * (110)2 * (11)2 => (x^2 + x) * (x + 1) => x^3 + x^2 + x^2  + x => x^3 + x => (1010)2 
			 * 可以理解为先将(110)2左移一位后与(110)进行异或运算 得到 => (1010)2
			 */
			result ^=(numb << (temp.length()-1-i));
			/**
			 * 注意如果度》8 要进行模约简
			 * 模约简方式,与不可约多项式m(x)=x8+x4+x3+x+1(十六进制表示为'11B')进行相加运算(异或)
			 */
			if (result >= 0x100) {
    
    
				result ^= 0x11B;  //11B => 不可约多项式m(x)=x8+x4+x3+x+1
			}
		}
		return EncodeUtil.toBinary(result+"", EncodeRadix.DEC);
	}

	/**
	 * 行位移 
	 * @param _8bitArr 8位字符串数组【16进制】
	 * @return 按行输出(2进制)
	 */
	private String[] shiftRow(String[] _8bitArr) {
    
    
		String[] res = new String[_8bitArr.length];
		for(int i = 0; i < _8bitArr.length / 4;i++) {
    
    
			for (int j = 0; j < 4; j++) {
    
    
				int index = i*4 + j%4;
				//经过行位移后, 原来B0B1B2B3 -> B0B5B10B15, B4B5B6B7 -> B4B9B14B3 。。。 于是找到了这个规律
				res[index] = EncodeUtil.toBinary(
						_8bitArr[(4*i + 5*j)% _8bitArr.length], EncodeRadix.HEX
				); 
				//扩充
				while(res[index].length() < 8) {
    
    
					res[index]= "0" + res[index];
				}
			}
		}
		return res;
	}

	/**
	 * 字节代换层
	 * @param binStr 二进制流
	 * @param _128bitsStr 128位字符串
	 * @return 16进制数据
	 */
	private String[] replace(String _128bitsStr, String[][] sbox) {
    
    
		String[] result = new String[16];
		//分组计算
		for (int i = 0; i <result.length; i++) {
    
    
			String rowNb = EncodeUtil.binaryToDec(_128bitsStr.substring(i * 8, i * 8 + 4));
			String colNb = EncodeUtil.binaryToDec(_128bitsStr.substring(i * 8 + 4, i * 8 + 8));
			result[i] = sbox[Integer.parseInt(rowNb)][Integer.parseInt(colNb)];
		}
		return result;
	}

	/**
	 * 异或运算
	 * @param text1 text1 
	 * @param text2 text2
	 * @return
	 */
	private String xor(String text1, String text2) {
    
    
		if (text1 == null || text2 == null || text1.length() != text2.length()) {
    
    
			throw new IllegalArgumentException("异或运算失败");
		}
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < text1.length();i++) {
    
    
			char ch1 = text1.charAt(i);
			char ch2 = text2.charAt(i);
			sb.append((ch1) ^ (ch2));
		}
		return sb.toString().trim();
	}


	/**
	 * 分组解密
	 * @param encrytedText 密文
	 */
	@Override
	public String decrypt(String encrytedText) {
    
    
		try {
    
    
			//base64解码
			byte[] bytes = new BASE64Decoder().decodeBuffer(encrytedText);
			String str = new String(bytes,Charset.forName("UTF8"));
			int textLen = str.length();
			StringBuilder sb = new StringBuilder();
			int divLen = textLen < 32 ? 1 : (int)(Math.ceil(textLen/(4*8*1.0))); //因为加密后会自动填充所以长度必为字符长度的倍数(HEX 4位)
			//分组解密
			for (int i = 0; i< divLen; i++) {
    
    
				int startIndex = i * (4*8);
				int endIndex = (startIndex + (4*8));
				String temp = str.substring(startIndex, endIndex);
				sb.append(baseDecrypt(temp));
			}
			return sb.toString();
		} catch (IOException e) {
    
    
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 解密
	 * @param encHexStr 加密16进制文本
	 * @return
	 */
	private String baseDecrypt(String encHexStr) {
    
    
		//1. 获取密钥
		if (subKeys == null || subKeys.isEmpty()) {
    
    
			throw new IllegalArgumentException("密钥获取失败");
		}
		if (subKeys.size() != 11) {
    
    
			throw new IllegalArgumentException("密钥长度有误");
		}
		//2. 讲16进制转二进制并迭代解密输出结果
		return EncodeUtil.binaryToStr(
				decLoop(encHexStr,subKeys),
				AESConstant.CHAR_LEN
		);
	}
	
	/**
	 * 迭代递归解密
	 * @param encHexStr 加密16进制文本
	 * @param subKeys 子密钥
	 * @return 解密结果
	 */
	private String decLoop(String encHexStr, List<String> subKeys) {
    
    
		//1.16进制转二进制
		String binTempStr = EncodeUtil.toBinary(
				encHexStr, EncodeRadix.HEX);
		//2.逆向迭代解密
		for (int level=10;level > 0;level--) {
    
    
			//密钥加法层
//			System.out.println("reverseReplace binTempStr1 = " + binTempStr);
			binTempStr = xor(binTempStr, subKeys.get(level)); //没问题
//			System.out.println("reverseReplace binTempStr2 = " + binTempStr);
			String[] temp = new String[AESConstant.ARR_LEN];
			//转成字符串数组
			int len = 8; //字节数组
			for (int i = 0; i < AESConstant.ARR_LEN; i++) {
    
    
				temp[i] = binTempStr.substring(i* len, (i+1)*len);
			}
			//逆向列混淆层
			if (level < 10) {
    
    
				binTempStr = reverseMixColumn(temp);
//				System.out.println("reverseReplace binTempStr3 = " + binTempStr);
				for (int i = 0; i < AESConstant.ARR_LEN; i++) {
    
    
					temp[i] = binTempStr.substring(i* len, (i+1)*len);
				}
			}
			//逆向行位移层
			binTempStr = reverseShiftRow(temp);
//			System.out.println("reverseReplace binTempStr4 = " + binTempStr);
			//逆向字节代换
			binTempStr = reverseReplace(binTempStr, AESConstant.REVERSE_SBOX);
//			System.out.println("reverseReplace binTempStr5 = " + binTempStr);
		}
		//密钥加法层
//		System.out.println("reverseReplace binTempStr6 = " + binTempStr);
		binTempStr = xor(binTempStr, subKeys.get(0));
//		System.out.println("reverseReplace binTempStr7 = " + binTempStr);
		return binTempStr;
	}
	
	/**
	 * 逆向字节代换层
	 * @param binStr 二进制流
	 * @param _128bitsStr 128位字符串
	 * @return 2进制进制数据
	 */
	private String reverseReplace(String _128bitsStr, String[][] sbox) {
    
    
		StringBuilder result = new StringBuilder();
		//分组计算
		for (int i = 0; i < AESConstant.ARR_LEN; i++) {
    
    
			String rowNb = EncodeUtil.binaryToDec(_128bitsStr.substring(i * 8, i * 8 + 4));
			String colNb = EncodeUtil.binaryToDec(_128bitsStr.substring(i * 8 + 4, i * 8 + 8));
			result.append(EncodeUtil.toBinary(sbox[Integer.parseInt(rowNb)][Integer.parseInt(colNb)], EncodeRadix.HEX));
		}
		return result.toString();
	}
	
	/**
	 * 逆向行位移 
	 * @param _8bitArr 字符串数组(16位)【2进制】
	 * @return 按行输出(2进制)
	 */
	private String reverseShiftRow(String[] _8bitArr) {
    
    
		StringBuilder res = new StringBuilder();
		for(int i = 0; i < _8bitArr.length / 4;i++) {
    
    
			for (int j = 0; j < 4; j++) {
    
    
				//经过逆向行位移后, 原来B0B1B2B3 -> B0B13B10B7, B4B5B6B7 -> B4B1B14B11 。。。 于是找到了这个规律
				String temp =_8bitArr[(4*i + 13*j)% _8bitArr.length];
				//扩充
				while(temp.length() < 8) {
    
    
					temp = "0" + temp;
				}
				res.append(temp);
			}
		}
		return res.toString();
	}
	
	/**
	 * 列混淆 【重点】
	 * @param _8bitArr 8位字符串数组 (2进制)
	 * @return 返回2进制字符串,方便后续的密钥加法
	 */
	private String reverseMixColumn(String[] _8bitArr) {
    
    
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < _8bitArr.length; i+=4) {
    
    
			/**
			 * 注意:在列混淆中,每一位代表着x的指数,如(2)16=>(10)2 => x, (3)16=>(11)2 => x+1、 (25)16 => (0010 0101)2【采用十六进制】
			 * 使用矩阵乘积后的结果作为每一字节位上的结果,矩阵相乘用到了异或和或运算,异或模拟GF(2^8)域相乘,或模拟不同位相加
			 * 
			 * 如
			 * (01)16*(25)16=>		 x^5 	   + x^2 	 + 1
			 * (01)16*(25)16=> 		 x^5 	   + x^2	 + 1
			 * (02)16*(25)16=> x^6 		 + x^3 		 + x
			 * (03)16*(25)16=> x^6 + x^5 + x^3 + x^2 + x + 1
			 * +____________________________________________
			 * 				   		 x^5 	   + x^2 	 + 1
			 * 
			 * 注意如果度》8 要进行模约简
			 * 模约简方式,与不可约多项式m(x)=x8+x4+x3+x+1(十六进制表示为'11B')进行相加运算(异或)
			 */
			for (int j = 0; j < AESConstant.REVERSE_MIX_COLUMN_BOX.length; j++) {
    
    
				int res = 0;
				int rowNb = j;
				int initLen = _8bitArr[i+j].length();
				for (int m = 0; m < AESConstant.REVERSE_MIX_COLUMN_BOX[0].length; m++) {
    
    
					res ^= Integer.parseInt(
						EncodeUtil.binaryToDec(
								multiply(_8bitArr[i+j], AESConstant.REVERSE_MIX_COLUMN_BOX[rowNb][m])
						)	
					);
				}
				//超过了8位就和不可约多项式进行异或
				if (res >= 0x100) {
    
    
					res ^= 0x11B;  //11B => 不可约多项式m(x)=x8+x4+x3+x+1
				}
				//转二进制
				String finalRes = EncodeUtil.toBinary(res + "",EncodeRadix.DEC);
				//扩充
				while(finalRes.length() < initLen) {
    
    
					finalRes = "0" + finalRes;
				}
				sb.append(finalRes);
			}
		}
		return sb.toString();
	}

	public static void main(String[] args) {
    
    
		AesUtil util = new AesUtil();
		String encrytedStr = util.encrypt("{\"code\":200,\"message\":\"成功!\",\"data\":{\"id\":\"2103813902831\",\"name\":\"章鱼哥是我哦\"}}");
		System.out.println("encrytedStr = " + encrytedStr);
		System.out.println("result= " + util.decrypt(encrytedStr));
	}
}

Resultados de ejecución
inserte la descripción de la imagen aquí
————————————————————————————————————————————————— —————————————————————————————

Supongo que te gusta

Origin blog.csdn.net/qq_31236027/article/details/131206018
Recomendado
Clasificación