プログラマーの成長過程における暗号化 - AES アルゴリズムの復号化とコード表示の詳細な説明

csdn の皆さん、こんにちは。再び戻ってきました。この記事は、AES 暗号化アルゴリズムの前回の紹介の関連記事です。焦点は、AES アルゴリズムの復号化プロセスと、AES 暗号化と復号化のコードにあります。[一時的に iv またはオフセットは含まれません]。AES 復号化の世界へ私に従ってください。

AES暗号化について詳しく解説

AES アルゴリズムまたは AES 暗号化について質問がある場合は、以前の記事を参照してください。
https://blog.csdn.net/qq_31236027/article/details/129796471

AES復号化

鍵グループの順序を入れ替えるだけで済む DES 復号に比べ、AES 復号は煩雑になります。

全体的なプロセス

誰もが AES の暗号化プロセスを理解していると仮定すると、暗号化には 11 ラウンドがあり、復号化にも同じことが当てはまります。最初の暗号化ラウンドでは、1 ラウンドのキー追加のみが実行され、最後の暗号化ラウンドでは列の混乱は必要ありません。復号化プロセスはその逆で、次の図に示すように、復号化では、最初に最後のラウンドの暗号化が逆にされ、次に最初のラウンドの暗号化が逆にされるまで再帰的に先に進みます。
ここに画像の説明を挿入
完全なプロセスを理解した後、「分割統治」の考え方を使用して、困難を個別に説明してみましょう。

ラウンドキープラス

キーは後ろから前への操作に参加します。つまり、最後のラウンドの暗号化のキーが最初の復号化ラウンドに参加します。プログラミングの便宜のために、グローバル変数を使用して暗号化キーと復号化キーを保存できます。鍵の配置原理についてはここではあまり紹介しませんので、ご不明な点がございましたら、AES 暗号化に関する以前のブログをご参照ください。

逆行シフト

AES 暗号化アルゴリズムでは、行シフトの
最初の行は変更されず、2 行目は左に 1 ビット循環シフトされ、3 行目は左に 2 ビット循環シフトされ、4 行目は左に循環シフトされます。 3ビットずつ。
ここに画像の説明を挿入
つまり、元の 4*4 行列では B[0][1] -> B[1][2] (図では B1 -> B5) [注、この行列は上から下に読まれます] 、上から下へ 左から右へ読んでください]。
理解と計算を容易にするために、この行列を 1 次元配列、つまり B[0] = B[0][0] = B0、B[1] = B[0][1] に変換できます。 = B1、B[2] = B[0][2] = B2 ... B[16] = B[3][3] = B15 の場合、B[1] -> B に従って数学的帰納法を使用します
。 [シフト後の 5 ]、B[2] -> B[10]、B[3] -> B[15] 簡単に取得できます: B[i] = B[(4 * (i/4) + 5 * ( i % 4)) mod 16] [i は添え字です] [図と組み合わせるとわかりやすいです]

以上が暗号化における行シフトのアルゴリズムですが、これを理解すると復号化の逆行シフトも簡単になります。
復号化は、左シフトを右シフトに変更するだけです。つまり、最初の行は移動せず、2 行目は右に 1 ビットシフト、3 行目は右に 2 ビットシフト、4 行目は 3 ビットシフトします。右にビット。下図のように、【注意、この行列は上から下、左から右に読みます】
ここに画像の説明を挿入
となります。理解と計算を容易にするために、この行列を 1 次元配列、つまり B[0] = B[0][0] = B0、B[1] = B[0][1] に変換できます。 = B1, B[2] = B[0][2] = B2 ... B[16] = B[3][3] = B15 であれば、数学的帰納法で簡単に次の結果を得ることができます: B[i] = B [(4 * (i/4) + 13 * (i % 4))mod 16] [i は下付き文字です] [わかりやすくするために図を組み合わせます]
ここに画像の説明を挿入


逆列難読化

AES 暗号化アルゴリズムにおける列の難読化
ガロア体の演算の加算と乗算を使用する [ガロア体の詳細については、AES の紹介記事を参照してください。演算はすべてモジュロ演算です] 暗号文行列と列混同固定行列の積を計算し、次に、結果行列を取得します。固定行列を以下の図に示します。
ここに画像の説明を挿入
計算の便宜上、行列を 1 次元化し、係数演算に使用することもできます。ここでは、比較的高速なモジュロ演算スキームを使用します。
/**
* アルゴリズムの説明:
* ガロア体の乗算のデフォルトはモジュロ演算
* (110)2 * (11)2 => (x^2 + x ) * (x + 1) => x^3 + x^2 + x^2 + x => x^3 + x => (1010)2 ※まず(110)2を左に1ビットシフトすると理解できます とXOR演算を
行う(110) to get => (1010)2
*/`
while (i < 法 2 の長さ) { result ^=(num << (法 2 の長さ - i)); //法 1 を示します値がシフトされますn ビット左への値が結果に格納され、前の値と XOR 演算されます。詳細については、「アルゴリズムの説明」を参照してください。i self-increment }ここで、numb は法 1 の値です。その後、行列法演算の結果が 8 ビットを超える場合は、自然化する必要があります。つまり、既約多項式 m(x)=x8+x4+x3+x+1 (0X11B) で XOR 演算されます。



AES アルゴリズムの列難読化を理解すると、AES 復号化の列難読化は簡単になり、次のように固定行列を変更するだけで済みます: {"0E", "0B", "0D", "09" }
,
{"09"、"0E"、"0B"、"0D"}、
{"0D"、"09"、"0E"、"0B"}、
{"0B"、"0D"、"09"、" 0E"}

逆バイト置換

これは比較的単純で、暗号化と同様に、8 桁の暗号文の最初の 4 桁を行数として使用し、最後の 4 桁を列数として使用して、逆向きの s ボックスの値を取得します。

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"}
	};

デザインのアイデア

復号化プロセスとアルゴリズムのアイデアを習得したら、復号化を設計できます。

  1. まず、暗号文のグループ化は復号化メソッドによって実現されます。
  2. 各グループの復号化は、baseDecrypt メソッドを通じて実行されます。
  3. 反復復号は、decLoop メソッド (ラウンドキーの加算、列の混乱、行の置換、バイト置換をその中に記述する) によって実現されます。
  4. 平文を出力します。

公式コードは次のとおりです。
バイナリ システムの変換の詳細については、記事を参照してください:
プログラマーの成長に関する暗号化番外章 ----- 文字列 (ascii) からバイナリへ https://blog.csdn.net/qq_31236027/記事/詳細/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));
	}
}

走行結果
ここに画像の説明を挿入
——————————————————————————————————————————————— —————————————————————————————

おすすめ

転載: blog.csdn.net/qq_31236027/article/details/131206018