Criptografia do Caminho de Crescimento do Programador - Explicação Detalhada do Modo de Criptografia de Cifra de Bloco e IV (Offset)

Cipher.getInstance("AES/ECB/PKCS5Padding");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Ao fazer a programação de criptografia e descriptografia, muitos amigos devem ter sido expostos às frases acima, mas você entendeu o significado e a diferença de ECB/CBC e o significado de PKCS5Padding durante o processo de codificação? Se você não tem certeza, espero que este artigo possa ajudá-lo.

O que é uma cifra de bloco?

Uma cifra de bloco é um algoritmo de criptografia e descriptografia que criptografa texto simples/descriptografa texto cifrado de acordo com caracteres de comprimento fixo. Os mais comuns são DES, AES, etc. Especificamente como mostrado na figura abaixo
insira a descrição da imagem aqui

O que é IV (offset)?

Pode ser entendido como uma variável variável definida durante o processo de criptografia e descriptografia, que pode ser um timestamp, uuid ou outros valores aleatórios, com o objetivo de aumentar a confusão e reduzir o risco de ser decifrado.

O que é o modo de criptografia de bloco?

Para criptografia e descriptografia geral (ou ECB), apenas chamamos o bloco de função de criptografia e descriptografia de criptografia e acabou, mas se um ataque de repetição (a mesma solicitação for iniciada várias vezes), o hacker poderá interceptar facilmente o texto cifrado Descriptografia de acordo com o grupo, isso representará uma ameaça à segurança do sistema neste momento. Para evitar que isso aconteça, podemos tomar certas medidas para processar iterativamente a cifra de bloco. O ECB (modo de livro de código eletrônico)/CBC (modo de encadeamento de bloco de texto cifrado) mencionado acima pertence ao modo de criptografia de bloco. Além disso, CFB (modo de feedback de texto cifrado) também pertence ao modo de criptografia de bloco.
Vamos analisar o significado dos diferentes modos de criptografia de bloco e suas respectivas vantagens e desvantagens, um por um.


insira a descrição da imagem aqui
Processo/Princípio ECB (Electronic Codebook Mode)
: Este modo de criptografia de bloco pertence ao modo de criptografia de bloco não processado mais simples e criptografa ou descriptografa diretamente texto simples ou texto cifrado por grupo para obter o resultado.

Vantagens:
-Suporte a processamento assíncrono multi-threaded, alta eficiência
-Não há necessidade de agrupar rodadas de cálculos iterativos e a quantidade de cálculos é menor

Desvantagens:
- Baixo desempenho de segurança, fácil de ser violado


insira a descrição da imagem aqui
Processo/princípio CBC (modo de encadeamento de blocos de texto cifrado)
: Criptografia:
primeira rodada: gera vetor de inicialização iv e criptografa em conjunto com o primeiro grupo de operações XOR de bloco de texto simples.
Acompanhamento: Pegue o resultado da última rodada da operação CBC e a operação XOR de texto simples do bloco atual e, em seguida, criptografe.
Descriptografia:
A primeira rodada: gerar um vetor de inicialização iv, primeiro descriptografar o primeiro grupo de blocos de texto cifrado e, em seguida, executar uma operação XOR com o vetor de inicialização.
Acompanhamento: primeiro descriptografe o grupo de texto cifrado atual e, em seguida, execute a operação XOR com a rodada anterior do grupo de texto cifrado
Criptografia e princípio de descriptografia:
A XOR B XOR B = A
Por exemplo, o primeiro grupo de texto cifrado e1 = Ek após a primeira rodada de criptografia (iv xou o primeiro grupo de texto simples)
então o primeiro grupo de texto simples após a primeira rodada de descriptografia d1 = (Ek'(primeiro grupo de texto cifrado) xor iv) = (iv xou primeiro grupo de texto simples) xor iv = primeiro grupo de texto simples

Vantagens:
-Usar iv como uma variável aleatória aumenta a dificuldade de decifrar, tornando os resultados de cada criptografia do mesmo texto simples inconsistentes
-A criptografia usa a saída da rodada anterior como a entrada da próxima rodada

Desvantagens:
-Aumentar a quantidade de cálculo e aumentar a sobrecarga de cálculo


insira a descrição da imagem aqui
Processo/princípio CFB (Ciphertext Feedback Mode)
: Criptografia:
Primeira rodada: Gera o vetor de inicialização iv, realiza primeiro o cálculo da criptografia e, em seguida, executa a operação XOR com o primeiro grupo de grupos de texto simples.
Acompanhamento: Pegue o resultado da última rodada da operação CFB e criptografe-o primeiro, depois execute a operação XOR com o texto simples do grupo atual.
Descriptografia:
A primeira rodada: gere o vetor de inicialização iv, execute o cálculo de criptografia primeiro e, em seguida, execute a operação XOR com o primeiro grupo de grupos de texto cifrado.
Acompanhamento: pegue o resultado da última rodada da operação CFB e criptografe-o primeiro, depois execute a operação XOR com o texto cifrado do bloco atual.
Princípio de criptografia e descriptografia:
A XOR B XOR B = A
Por exemplo, o primeiro grupo de texto cifrado e1 após a primeira rodada de criptografia = Ek(iv) xor o primeiro grupo de texto simples,
depois o primeiro grupo de texto simples após a primeira rodada de descriptografia d1 = ( Ek(iv) xor primeiro conjunto de texto cifrado) = (Ek(iv) xor (Ek(iv) xor primeiro conjunto de texto simples) ) = primeiro conjunto de texto simples

Vantagens:
-Usar iv como variável aleatória aumenta a dificuldade de decifrar, tornando os resultados inconsistentes para cada criptografia do mesmo texto plano -A criptografia
usa a saída da rodada anterior como entrada da próxima rodada
-iv pode ser usado sozinho na usar o algoritmo de criptografia de bloqueio

Desvantagens:
-Aumentar a quantidade de cálculo e aumentar a sobrecarga de cálculo

Bloquear a implementação do código do modo de criptografia

Nota: Se você precisar do código AES, consulte o seguinte artigo para obter detalhes:
Criptografia no crescimento dos programadores - Explicação detalhada da descriptografia do algoritmo AES e apresentação do código https://blog.csdn.net/qq_31236027/article/details/131206018

tipo enumerado

public enum EncryptMode {
    
    
	CBC("CBC"),
	CFB("CFB");
	
	private String name;
	
	private EncryptMode(String name) {
    
    
		this.setName(name);
	}

	public String getName() {
    
    
		return name;
	}

	public void setName(String name) {
    
    
		this.name = name;
	}
}

parte criptografada

/**
	 * 分组加密(128位一组)【完整版】
	 * @param text 明文
	 * @param mode 加密模式(CFB、CBC)
	 * @param iv 偏移量
	 */
	@Override
	public String encrypt(String text, String iv, EncryptMode mode) {
    
    
		if(mode == null) {
    
    
			return encrypt(text);
		}
		String result = null;
		switch(mode) {
    
    
			case CBC: result = encryptCBC(text,iv); break;
			case CFB: result = encryptCFB(text,iv);break;
			default: result = encrypt(text);break;
		}
		return result;
	}
	

	/**
	 * 分组加密(128位一组)(无iv【偏移量】版)
	 * @param text 明文
	 */
	private 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(EncodeUtil.binaryToHexStr(baseEncrypt(substr)).trim());
		}
		return new BASE64Encoder().encode(sb.toString().trim().getBytes());
	}
	
	/**
	 * 分组加密(128位一组),(有iv【偏移量】CBC版,更安全)
	 * 
	 * CBC特性
	 * 1. 每一组分组的密文都依赖于上一组的结果
	 * 2. 加入了iv偏移量使得每次加密执行后的结果都不一致
	 * 
	 * @param text 明文
	 * @param iv 偏移量
	 */
	private String encryptCBC(String text,String iv) {
    
    
		StringBuilder sb = new StringBuilder();
		int textLen = text.length();
		//获取分组长度
		// DIV_LEN * CHAR_LEN = 128
		// 根据DIV_LEN进行分组,如CHAR_LEN=16位【UNICODE】,那么就每8个字符一组
		int divLen = textLen % AESConstant.DIV_LEN == 0 ? textLen / AESConstant.DIV_LEN : (textLen / AESConstant.DIV_LEN + 1);
		// CFB加密初始化向量
		String encryptedPart = iv;
		//分组加密处理
		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 += " ";
			}
			while(encryptedPart.length() < AESConstant.DIV_LEN) {
    
    
				encryptedPart += " ";
			}
			//CBC关键,需要拿明文与上一轮结果进行异或得到的结果共同加密作为下一轮的输入
			encryptedPart = EncodeUtil.binaryToStr(
					baseEncrypt(strXor(encryptedPart,substr)), 16
			);
			sb.append(encryptedPart);
		}
		//批量处理为16进制后base64运算
		String result = sb.toString().trim();
		result = EncodeUtil.strtoBinary(result, 16);
		result = EncodeUtil.binaryToHexStr(result);
		return new BASE64Encoder().encode(result.getBytes());
	}
	
	/**
	 * 分组加密(128位一组),(有iv【偏移量】CFB版,更安全)
	 * 
	 * CFB特性
	 * 
	 * @param text 明文
	 * @param iv 偏移量
	 */
	private String encryptCFB(String text,String iv) {
    
    
		StringBuilder sb = new StringBuilder();
		int textLen = text.length();
		//获取分组长度
		// DIV_LEN * CHAR_LEN = 128
		// 根据DIV_LEN进行分组,如CHAR_LEN=16位【UNICODE】,那么就每8个字符一组
		int divLen = textLen % AESConstant.DIV_LEN == 0 ? textLen / AESConstant.DIV_LEN : (textLen / AESConstant.DIV_LEN + 1);
		// CFB加密初始化向量
		String encryptedPart = iv;
		//分组加密处理
		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 += " ";
			}
			while(encryptedPart.length() < AESConstant.DIV_LEN) {
    
    
				encryptedPart += " ";
			}
			//CFB关键,需要拿明文与上一轮加密结果进行异或得到的结果作为下一轮的输入
			encryptedPart = strXor(EncodeUtil.binaryToStr(
					baseEncrypt(encryptedPart), 16
			),substr);
			sb.append(encryptedPart);
		}
		//批量处理为16进制后base64运算
		String result = sb.toString().trim();
		result = EncodeUtil.strtoBinary(result, 16);
		result = EncodeUtil.binaryToHexStr(result);
		return new BASE64Encoder().encode(result.getBytes());
	}

parte de descriptografia

	/**
	 * 分组解密(128位一组)【完整版】
	 * @param encrytedText 密文
	 * @param mode 加密模式(CFB、CBC)
	 * @param iv 偏移量
	 */
	@Override
	public String decrypt(String encrytedText, String iv, EncryptMode mode) {
    
    
		if(mode == null) {
    
    
			return decrypt(encrytedText);
		}
		String result = null;
		switch(mode) {
    
    
			case CBC: result = decryptCBC(encrytedText,iv); break;
			case CFB: result = decryptCFB(encrytedText,iv);break;
			default: result = decrypt(encrytedText);break;
		}
		return result;
	}


	/**
	 * 分组解密
	 * @param encrytedText 密文
	 */
	private 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;
	}
	
	/**
	 * 分组解密(128位一组),(有iv【偏移量】CBC版)
	 * @param encrytedText 密文
	 * @param iv 偏移量
	 * @return 明文
	 */
	private String decryptCBC(String encrytedText,String iv) {
    
    
		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位)
			//CFB解密初始化向量
			String decryptedPart = iv;
			//分组解密
			for (int i = 0; i< divLen; i++) {
    
    
				int startIndex = i * (4*8);
				int endIndex = (startIndex + (4*8));
				String temp = str.substring(startIndex, endIndex);
				//尾部填充
				while(decryptedPart.length() < AESConstant.DIV_LEN) {
    
    
					decryptedPart += " ";
				}
				//转换成16位的字符,方便strXor运算
				sb.append(strXor(baseDecrypt(temp),decryptedPart));
				//位数转换
				decryptedPart = EncodeUtil.binaryToStr(EncodeUtil.toBinary(temp, EncodeRadix.HEX), 16);
			}
			return sb.toString();
		} catch (IOException e) {
    
    
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 分组解密(128位一组),(有iv【偏移量】CFB版)
	 * @param encrytedText 密文
	 * @param iv 偏移量
	 * @return 明文
	 */
	private String decryptCFB(String encrytedText,String iv) {
    
    
		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位)
			//CFB解密初始化向量(转为16进制方便计算
			String decryptedPart = iv;
			//分组解密
			for (int i = 0; i< divLen; i++) {
    
    
				int startIndex = i * (4*8);
				int endIndex = (startIndex + (4*8));
				String temp = str.substring(startIndex, endIndex);
				//转换成16位的字符,方便strXor运算
				temp = EncodeUtil.binaryToStr(EncodeUtil.toBinary(temp, EncodeRadix.HEX), 16);
				//尾部填充
				while(decryptedPart.length() < AESConstant.DIV_LEN) {
    
    
					decryptedPart += " ";
				}
				//转换成16位的字符,方便strXor运算
				sb.append(
					strXor(EncodeUtil.binaryToStr(baseEncrypt(decryptedPart), 16),temp)
				);
				decryptedPart = temp;
			}
			return sb.toString();
		} catch (IOException e) {
    
    
			e.printStackTrace();
		}
		return null;
	}

executar código

public static void main(String[] args) {
    
    
		AesUtil util = new AesUtil();
		//偏移量(8个字符,每个字符16位)
		String iv = UUID.randomUUID().toString().substring(0,8);
		//CFB(密文反馈模式)
		String encrytedStr = util.encrypt(
				"{\"code\":200,\"message\":\"成功!\",\"data\":{\"id\":\"2103813902831\",\"name\":\"章鱼哥是我啊\",\"gender\":\"男\"}}"
				,iv
				,EncryptMode.CFB
		);
		System.out.println("encrytedStr = " + encrytedStr);
		System.out.println("result= " + util.decrypt(encrytedStr,iv,EncryptMode.CFB));
	}

Finalmente, execute a captura de tela
insira a descrição da imagem aqui
———————————————PKCS5Padding será discutido mais tarde—————————————————————

Acho que você gosta

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