加密算法浅析及AES ZeroPadding的java实现

目录

1、加密算法概述

2、DES(Data Encryption Algorithm)加密算法

3、AES(Advanced Encryption Standard)加密算法

3.1、关于加解密模式和填充方式

3.1.1、加密模式

3.1.2、常见的填充方式

3.2、Java基于AES实现ZeroPadding

4、不可逆算法MD5、SHA简述


1、加密算法概述

加密算法分成对称加密、非对称加密、不可逆加密算法。对称和非对称算法是可逆的,即如果有加密算法、密文,能够解密出明文。对称算法是指加密解密使用相同的秘钥,不对称算法的加解密秘钥互不相同。不管对称与否,秘钥的保存也是一个难题,因此出现了不可逆算法。不可逆算法是即使有加密算法、密文,也不能解析出明文。

比较著名的对称加密算法有:DES、AES;

比较著名的非对称加密算法有:RSA、DSA;

非对称加密算法工作原理

1.A要向B发送信息,A和B都要产生一对用于加密和解密的公钥和私钥。

2.A的私钥保密,A的公钥告诉B;B的私钥保密,B的公钥告诉A。

3.A要给B发送信息时,A用B的公钥加密信息,因为A知道B的公钥。

4.A将这个消息发给B(已经用B的公钥加密消息)。

5.B收到这个消息后,B用自己的私钥解密A的消息。其他所有收到这个报文的人都无法解密,因为只有B才有B的私钥。

非对称加密算法工作原理参考:公钥加密_百度百科

比较著名的不可逆机密算法有:MD5、SHA;本质上不可逆加密其实是Hash,使用时双方先对自己的明文进行加密得到密文,再和对方以同样算法加密后的密文进行比较,若相等则意味着双方持有相同的明文。

md5设计论文:http://www.ietf.org/rfc/rfc1321.txt

2、DES(Data Encryption Algorithm)加密算法

DES(Data Encryption Algorithm,DEA)是一种对称加密算法,很可能是使用最广泛的密钥系统,特别是在保护金融数据的安全中,最初开发的DEA是嵌入硬件中的。通常,自动取款机(Automated Teller Machine,ATM)都使用DEA。它出自IBM的研究工作,IBM也曾对它拥有几年的专利权,但是在1983年已到期后,允许在特定条件下可以免除专利使用费而使用。1977年被美国政府正式采纳。

3、AES(Advanced Encryption Standard)加密算法

AES(Advanced Encryption Standard),在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院(NIST)于2001年11月26日发布于FIPS PUB 1997,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。

AES加密又分成AES-128、AES-196、AES-256,其中128、196、256是针对加解密密钥长度的要求,即128位(16字节),196位(24字节),256位(32字节);

Java中,一般的加解密初始化时,都要声明加解密方式,类似如下:

1

2

3

4

5

Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");

  

//其中:   AES 为算法;

//          CBC 为加解密模式;

//          NoPadding 为填充方式;

那么,什么是加密模式,填充方式呢?

3.1、关于加解密模式和填充方式

针对待加解密明文、密文,长度有严格要求,即必须为16字节的整数倍(所以针对不同长度的数据,需要对齐,不够16位的需要填充数据,由此产生了不同的填充方式)。整个加解密的过程是对所有分割成16个字节长度的数据块进行循环加解密,最后合并起来形成最终结果集(加解密过程的不同产生了不同的加解密模式)。

3.1.1、加密模式

针对AES,潜在的其他的加密模式如下:

所有的加解密模式

加解密名称

算法描述

ECB

电码本模式(Electronic Codebook Book (ECB)

这种模式是将整个明文分成若干段相同的小段,然后对每一小段进行加密。

CBC密码分组链接模式(Cipher Block Chaining (CBC))

这种模式是先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密。

CTR计算器模式(Counter (CTR))

计算器模式不常见,在CTR模式中, 有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文,相当于一次一密。

这种加密方式简单快速,安全可靠,而且可以并行加密,但是在计算器不能维持很长的情况下,密钥只能使用一次。

CFB密码反馈模式(Cipher FeedBack (CFB))
OFB输出反馈模式(Output FeedBack (OFB)

参考:https://www.cnblogs.com/starwolf/p/3365834.html

3.1.2、常见的填充方式

填充方式

备注

NoPadding不填充,需要程序满足数据场地为16字节整数倍的要求。
PKCS5Padding是PKCS7Padding子集,并规定块长度为8字节(这里指的是填充块的长度);
PKCS7Padding

假设块长度为bs,则:

数据长度需要填充n(n>0)个字节才对齐,那么填充n个字节,每个字节都是n;

如果数据长度刚好为块大小的整数倍,则填充bs长度的,且值为bs的块到末尾;

ZeroPadding数据长度不对齐时使用0填充,否则不填充

oracle jdk_8u131没有发现有该实现

3.2、Java基于AES实现ZeroPadding

package com.pajk.datax.common.util.endecrypt;

import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class TestAES2 {
	/**
	 * 加密
	 * 
	 * @param content  需要加密的内容
	 * @param password 加密密码
	 * @return
	 */
	private static String AESKey = "dbaisbestooooooo";
	public static byte[] encrypt(String content, String password) {
		try {
			// Step 1: padding
			int length = content.length();
			//ZeroPadding实现
			for (int i = 0; i < (16 - length % 16); i++) {
				content = content + '\0';
			}
			
			SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(password.getBytes()); //强烈注意:CBC必须要

			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");// 创建密码器
			byte[] byteContent = content.getBytes("utf-8");
			cipher.init(Cipher.ENCRYPT_MODE, key, ivspec);// 初始化
			byte[] result = cipher.doFinal(byteContent);
			return result; // 加密
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解密 解密的时候要传入byte数组
	 * 
	 * @param content  待解密内容
	 * @param password 解密密钥
	 * @return
	 */
	public static byte[] decrypt(byte[] content, String password) {
		try {
			SecretKeySpec key = new SecretKeySpec(password.getBytes(), "AES");
			IvParameterSpec ivspec = new IvParameterSpec(password.getBytes());//强烈注意:CBC必须要

			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");// 创建密码器
			cipher.init(Cipher.DECRYPT_MODE, key, ivspec);			// 初始化
			byte[] result = cipher.doFinal(content);
			return result; // 加密
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 将二进制转换成16进制
	 * 
	 * @param buf
	 * @return
	 */
	public static String parseByte2HexStr(byte buf[]) {
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < buf.length; i++) {
			String hex = Integer.toHexString(buf[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex.toUpperCase());
		}
		return sb.toString();
	}

	/**
	 * 将16进制转换为二进制
	 * 
	 * @param hexStr
	 * @return
	 */
	public static byte[] parseHexStr2Byte(String hexStr) {
		if (hexStr.length() < 1)
			return null;
		byte[] result = new byte[hexStr.length() / 2];
		for (int i = 0; i < hexStr.length() / 2; i++) {
			int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
			int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
			result[i] = (byte) (high * 16 + low);
		}
		return result;
	}


	public static void main(String[] args) {
		String content = "1";

		for (int i = 0; i < 10; i++) {
			String data = content + "-" + i;
			StringBuilder sb = new StringBuilder();
			// 加密
			sb.append("加密前:" + data + ",\t");
			byte[] encryptResult = encrypt(data, AESKey);
			String encryptResultStr = parseByte2HexStr(encryptResult);
			sb.append("加密后:" + encryptResultStr + "(" + encryptResultStr.length() + ")" + ",\t");

			// 解密
			byte[] decryptFrom = parseHexStr2Byte(encryptResultStr);
			byte[] decryptResult = decrypt(decryptFrom, AESKey);
			String ns = new String(decryptResult);
			sb.append("解密后:" + ns + "");
			
			System.out.println(sb.toString());
		}
	}
}

4、不可逆算法MD5、SHA简述

MD5(Secure-Digest Algorithm,信息摘要算法),SHA(Secure Hash Algorithm,安全散列算法)是常见的不可逆加密算法,确切地说是不同的Hash算法。而既然是Hash算法,本质就是摘要,就意味着不追求可逆,同时存在一定的Hash碰撞。针对碰撞,解决的办法就是扩大整个Hash值的范围(捂脸笑吧)。

而MD5、SHA256,具体算法上面的数字,则代表了揭秘结果值的位数(8位一个字节),位数越长,整个Hash值范围越大,碰撞的几率越低。如SHA256表示加密后的结果值长度位256位,即256/8=32字节(注意:每个字节表示的范围是0~256,转换为16进制,因此整个字符串长度会变成32字节*2即64字节),整个SHA的值范围是2的256次方。

MD5系列有分成MD2、MD4、MD5,长度都是160位。其中MD2、MD5在Java JDK中都由实现,常用的算法是MD5。
SHA系列有分成SHA1、SHA256、SHA384、SHA512,成都分别为160位,256位,384位,512位。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
AES(Advanced Encryption Standard)是一种对称加密算法,可以用于加密和解密数据。在Java中,可以使用javax.crypto包中的类来实现AES加密算法。 下面是一个简单的示例代码,演示如何使用AES加密算法进行加密和解密: ```java import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.util.Base64; public class AESExample { private static final String ALGORITHM = "AES"; private static final String KEY = "0123456789abcdef"; // 密钥,长度必须为16字节 public static String encrypt(String data) throws Exception { SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.ENCRYPT_MODE, keySpec); byte[] encryptedBytes = cipher.doFinal(data.getBytes()); return Base64.getEncoder().encodeToString(encryptedBytes); } public static String decrypt(String encryptedData) throws Exception { SecretKeySpec keySpec = new SecretKeySpec(KEY.getBytes(), ALGORITHM); Cipher cipher = Cipher.getInstance(ALGORITHM); cipher.init(Cipher.DECRYPT_MODE, keySpec); byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedData)); return new String(decryptedBytes); } public static void main(String[] args) { try { String originalData = "Hello, AES!"; System.out.println("原始数据: " + originalData); String encryptedData = encrypt(originalData); System.out.println("加密后的数据: " + encryptedData); String decryptedData = decrypt(encryptedData); System.out.println("解密后的数据: " + decryptedData); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上面的示例代码中,我们使用AES算法加密和解密数据。密钥长度必须为16字节(128位),可以根据需要修改。`encrypt`方法用于加密数据,`decrypt`方法用于解密数据。 请注意,这只是一个简单的示例,实际应用中需要注意密钥的安全性和其他加密参数的设置。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值