AES加解密简单介绍

上面一篇文章介绍了使用DES方式进行加解密(DES方式加解密的简单介绍),我们说了DES由于使用8个字节(64bit)密钥进行加解密,所以安全性不够(当然这里的不够都是相对的),所以现在使用了密钥更多的AES方式进行对称加密提高安全性,AES加密方式的全称是Advanced Encryption Standard,这里的Advanced当然是相对于DES来说的。AES加密根据其使用的密钥长度又细分成AES-128、AES-192和AES-256这三种AES加密方式,其中AES-128对应128bit密钥长度,AES-192对应192bit,AES-256对应256bit,从道理上说密钥长度越长,机密的安全等级就越高,但是密钥越长加解密对硬件的性能消耗就越厉害,所以这里以AES-128为例来讲解AES加密方式在Java中的实现(实际上实现了128加密,另外两种也就简单了)。

1、AES加密

我们这里还是先实现AES的字节方式加密

/**
 * AES加密二进制数据
 *
 * @param data 二进制待加密数据
 * @param key  二进制密钥
 * @return 二进制加密后的数据
 * @throws Exception
 */
public static byte[] encrypt(byte[] data, byte[] key) throws Exception {
    //构造密钥生成器,指定AES算法
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
 
    //根据传入的密钥字节生成一个可信任的随机数据源
    SecureRandom secureRandom = new SecureRandom(key);
 
    //初始化一个128的密钥生成器
    keyGenerator.init(128,secureRandom);
 
    //生成一个原始的对称密钥
    SecretKey originSecretKey = keyGenerator.generateKey();
 
    //根据原始对称密钥生成一个AES密钥
    byte[] raw = originSecretKey.getEncoded();
    SecretKeySpec secretKey = new SecretKeySpec(raw,"AES");
 
    //声明一个Cipher对象
    Cipher cipher = Cipher.getInstance("AES");
 
    //使用密钥初始化cipher
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
 
    //进行解密操作,实际上执行的还是Cipher的doFinal方法
    return cipher.doFinal(data);
}

代码中对字节加密实现说的很详细了,这里提一下的就是由于这里使用了AES-128的加密方式,所以代码中的secretKey是16个字节(128bit)的,如果我们换成AES-192那么这里的secretKey就应该是24个字节。同时也要注意和DES实现加密一样,这里实际上的加密工作还是由Java中的Cipher类来完成的,我们所做的事情只不过是一些初始化的工作。

同样的,由于平时使用的都是针对字符串的加解密,所以这里得实现一个字符串的加密方法

/**
 * 重载encrypt方法,使得数据源和密钥可使用字符串
 *
 * @param data 字符串数据源
 * @param key  字符串密钥
 * @return 返回字符串类型的
 * @throws Exception
 */
public static String encrypt(String data, String key) throws Exception {
    byte[] bt = encrypt(data.getBytes(), key.getBytes());
    String str = Base64.encodeBase64URLSafeString(bt);
    return str;
}

这里还是使用了Base64进行byte和String之间的转换,不能直接用new String(bytes)方式来转换,具体原因见DES那篇文章。

2、AES解密

同样的,这里来实现AES的字节解密方式

/**
 * AES解密二进制数据
 *
 * @param data AES机密过的二进制数据
 * @param key  用来解密的二进制密钥
 * @return 返回解密后的数据
 * @throws Exception
 */
public static byte[] decrypt(byte[] data, byte[] key) throws Exception {
    //构造密钥生成器,指定AES算法
    KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
 
    //根据传入的密钥字节生成一个可信任的随机数据源
    SecureRandom secureRandom = new SecureRandom(key);
 
    //初始化一个128的密钥生成器
    keyGenerator.init(128,secureRandom);
 
    //生成一个原始的对称密钥
    SecretKey originSecretKey = keyGenerator.generateKey();
 
    //根据原始对称密钥生成一个AES密钥
    byte[] raw = originSecretKey.getEncoded();
    SecretKeySpec secretKey = new SecretKeySpec(raw,"AES");
 
    //声明一个Cipher对象
    Cipher cipher = Cipher.getInstance("AES");
    /***到这里的字节解密代码都和机密代码一样***/
 
    //使用密钥初始化cipher,这里和加密操作的唯一区别是设置的MODE不一样
    cipher.init(Cipher.DECRYPT_MODE, secretKey);
 
    //进行解密操作,实际上执行的还是Cipher的doFinal方法
    return cipher.doFinal(data);
 
}

看的出来,这里的字节解密方法实现和加密方法实现只有cipher.init代码设置的Mode方式不一样而已,最后还是通过Cipher类来进行的解密操作。

这里还是来实现一个针对字符串的解密方式

/**
 * 重载decrypt方法,输入加密过的数据源和密钥输出解密后的字符串
 * @param data  加密后的字符串数据源
 * @param key   用来加密的字符串密钥
 * @return  解密后的字符串
 * @throws Exception
 */
public static String decrypt(String data, String key) throws Exception {
    byte[] buf = Base64.decodeBase64(data);
    byte[] bt = decrypt(buf, key.getBytes());
    return new String(bt);
}

到这里AES方式在Java中实现加解密的功能就算完成了,至于AES加解密的详情这里就细究了,毕竟DES的实现原理博主都觉得一时半会搞不定更不用说更加复杂的AES了。有了加解密方法,小伙伴们就很容易实现自己的AesUtil工具类了,不过在android中请记得用android.util.Base64的对应方法来处理Byte和String。

 下面是我的详细使用代码,base64编码和二进制十六进制转换两种方式。

注:Base64 key定义为16位字符,十六进制的key字母范围是a-f.

import java.util.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;


/**
 * @author x_san3
 * Description: 加解密
 */
public class AESUtil {
	
	private static String algorithm = "AES";
	private static String key = "abcdefghijklm123";

	public static void main(String[] args) throws Exception {
		 
		String data = "654321";
		/*String secretKey = "abcdefabcdefabcdefabcdefabcdef09";
		String enStr = AESUtil.encrypt(data, secretKey);
		System.out.println("加密后:" + enStr);
		String deStr = AESUtil.decrypt(enStr, secretKey);
		System.out.println("解密后:" + deStr);*/
		
		String ciphertext = AESUtil.encrypt(data);
		System.out.println("加密后:" + ciphertext);
		String deStr = AESUtil.decrypt(ciphertext);
		System.out.println("解密后:" + deStr);

	}
	
	/**
	 * Description: 加密
	 * @param secret
	 * @return 加密后的值
	 * @throws Exception
	 */
	public static String encrypt(String data) throws Exception {
		// Cipher负责完成加密或解密工作,生成Cipher对象,指定其支持的算法
		Cipher cipher = Cipher.getInstance(algorithm);
		// 生成特定的密钥
		SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
		// 根据密钥,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式
		cipher.init(Cipher.ENCRYPT_MODE, skey);
		byte[] result = cipher.doFinal(data.getBytes());
		// org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString(result);
		return Base64.getEncoder().encodeToString(result);
	}

	/**
	 * Description: 解密
	 * @param ciphertext
	 * @return 解密后的值
	 * @throws Exception
	 */
	public static String decrypt(String ciphertext) throws Exception {
		//byte[] old = org.apache.commons.codec.binary.Base64.decodeBase64(ciphertext);
		byte[] ciphertextByte = Base64.getDecoder().decode(ciphertext);
		// Cipher负责完成加密或解密工作,生成Cipher对象,指定其支持的算法
		Cipher cipher = Cipher.getInstance(algorithm);
		// 生成特定的密钥
		SecretKeySpec skey = new SecretKeySpec(key.getBytes(), algorithm);
		// 根据密钥,对Cipher对象进行初始化,ENCRYPT_MODE表示加密模式
		cipher.init(Cipher.DECRYPT_MODE, skey);
		byte[] result = cipher.doFinal(ciphertextByte);
		return new String(result);
	}

	/*
	 * 加密
	 */
	public static String encrypt(String data, String secretKey) throws Exception {
		byte[] key = hexStr2Byte(secretKey);
		SecretKeySpec sKey = new SecretKeySpec(key, algorithm);
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.ENCRYPT_MODE, sKey);
		byte[] encrypted = cipher.doFinal(data.getBytes());
		return byte2HexStr(encrypted);
	}

	/*
	 * 解密
	 */
	public static String decrypt(String ciphertext, String secretKey) throws Exception {
		byte[] tmp = hexStr2Byte(ciphertext);
		byte[] key = hexStr2Byte(secretKey);
		SecretKeySpec sKey = new SecretKeySpec(key, algorithm);
		Cipher cipher = Cipher.getInstance(algorithm);
		cipher.init(Cipher.DECRYPT_MODE, sKey);
		byte[] decrypted = cipher.doFinal(tmp);
		return new String(decrypted);
		
	}
	
	/*
	 * 转为二进制
	 */
	private static byte[] hexStr2Byte(String secret_key) {
		if (secret_key.length() < 1)
			return null;
		byte[] encrypted = new byte[secret_key.length() / 2];
		for (int i = 0; i < secret_key.length() / 2; i++) {
			int high = Integer.parseInt(secret_key.substring(i * 2, i * 2 + 1), 16);//偶数位
			int low = Integer.parseInt(secret_key.substring(i * 2 + 1, i * 2 + 2), 16);//奇数位
			encrypted[i] = (byte) (high * 16 + low);
		}
		return encrypted;
	}
	
	/*
	 * 转为十六进制
	 */
	private static String byte2HexStr(byte buf[]) {
		StringBuffer strbuf = new StringBuffer(buf.length * 2);
		int i;
		for (i = 0; i < buf.length; i++) {
			if (((int) buf[i] & 0xff) < 0x10)
				strbuf.append("0");
			strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
		}
		return strbuf.toString();
	}

	
}

 

                ---------------------------------------------欢迎关注公众号(生活不止有代码)-------------------------------------------------------

                                                                      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值