java实现AES对称加密demo
最近公司需要学习到数据传输的加密,我也看了对称加密的文档,所谓的对称加密就是说加密和解密共用一套密钥,于是我选用了常用的AES对称加密,下图是一个基本原理。
-
首先需要生成密钥,在SecureRandom.getInstance()方法里面需要加入参数"SHA1PRNG",不然在linux系统上解密失败报错Given final block not properly padded. Such issues can arise if a bad key is used during decryption.,具体原因不知;下面加密设置了种子,这样每次生成的密钥都会是相同的,也可以去掉,这样生成的密钥就会有所不同。
private SecretKey geneKey() throws Exception { //获取一个密钥生成器实例 KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); random.setSeed("123456".getBytes());//设置加密用的种子,密钥 keyGenerator.init(random); SecretKey secretKey = keyGenerator.generateKey(); //把上面的密钥存起来 Path keyPath = Paths.get("D://aes.key"); Files.write(keyPath, secretKey.getEncoded()); return secretKey; }
-
然后用生成的密钥对所需要的数据进行加密,这里还对加密后的内容进行了base64编码,反之解密的时候也需要先base64解码
public String encrypt(String encryptStr) throws Exception { //1、指定算法、获取Cipher对象 Cipher cipher = Cipher.getInstance(ALGORITHM);//算法是AES //2、生成/读取用于加解密的密钥 SecretKey secretKey = this.geneKey(); //3、用指定的密钥初始化Cipher对象,指定是加密模式,还是解密模式 cipher.init(Cipher.ENCRYPT_MODE, secretKey); //4、更新需要加密的内容 cipher.update(encryptStr.getBytes()); //5、进行最终的加解密操作 byte[] result = cipher.doFinal();//加密后的字节数组 //也可以把4、5步组合到一起,但是如果保留了4步,同时又是如下这样使用的话,加密的内容将是之前update传递的内容和doFinal传递的内容的和。 // byte[] result = cipher.doFinal(content.getBytes()); String base64Result = Base64.getEncoder().encodeToString(result);//对加密后的字节数组进行Base64编码 return base64Result; }
-
解密
public String decrpyt(String desrpytStr) throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM); SecretKey secretKey = this.geneKey(); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] encodedBytes = Base64.getDecoder().decode(desrpytStr.getBytes()); byte[] result = cipher.doFinal(encodedBytes);//对加密后的字节数组进行解密 return new String(result); }
也可以根据路径去读取密钥,如下(推荐,这样就不用重新生成密钥)
private SecretKey readKey(Path keyPath) throws Exception { //读取存起来的密钥 byte[] keyBytes = Files.readAllBytes(keyPath); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM); return keySpec; } public String decrpyt(String desrpytStr) throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM); Path keyPath = Paths.get(keyUrl); SecretKey secretKey = this.readKey(keyPath); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] encodedBytes = Base64.getDecoder().decode(desrpytStr.getBytes()); byte[] result = cipher.doFinal(encodedBytes);//对加密后的字节数组进行解密 return new String(result); }
-
最后给出全部代码
import javax.crypto.Cipher; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.SecureRandom; import java.util.Base64; public class AESUtil { private static final String ALGORITHM = "AES"; //密钥的存放位置 private String keyUrl = "D:/aes.key"; /** * 生成密钥 * @return * @throws Exception */ private SecretKey geneKey() throws Exception { //获取一个密钥生成器实例 KeyGenerator keyGenerator = KeyGenerator.getInstance(ALGORITHM); SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); random.setSeed("123456".getBytes());//设置加密用的种子,密钥,这个可不操作,固定了的话每次出来的密钥时一样的 keyGenerator.init(random); SecretKey secretKey = keyGenerator.generateKey(); //把上面的密钥存起来 Path keyPath = Paths.get(keyUrl); Files.write(keyPath, secretKey.getEncoded()); return secretKey; } /** * 读取存储的密钥 * @param keyPath * @return * @throws Exception */ private SecretKey readKey(Path keyPath) throws Exception { //读取存起来的密钥 byte[] keyBytes = Files.readAllBytes(keyPath); SecretKeySpec keySpec = new SecretKeySpec(keyBytes, ALGORITHM); return keySpec; } /** * 加密 */ public String encrypt(String encryptStr) throws Exception { //1、指定算法、获取Cipher对象 Cipher cipher = Cipher.getInstance(ALGORITHM);//算法是AES //2、生成/读取用于加解密的密钥 SecretKey secretKey = this.geneKey(); //3、用指定的密钥初始化Cipher对象,指定是加密模式,还是解密模式 cipher.init(Cipher.ENCRYPT_MODE, secretKey); //4、更新需要加密的内容 cipher.update(encryptStr.getBytes()); //5、进行最终的加解密操作 byte[] result = cipher.doFinal();//加密后的字节数组 //也可以把4、5步组合到一起,但是如果保留了4步,同时又是如下这样使用的话,加密的内容将是之前update传递的内容和doFinal传递的内容的和。 // byte[] result = cipher.doFinal(content.getBytes()); String base64Result = Base64.getEncoder().encodeToString(result);//对加密后的字节数组进行Base64编码 return base64Result; } /** * 解密 */ public String decrpyt(String desrpytStr) throws Exception { Cipher cipher = Cipher.getInstance(ALGORITHM); Path keyPath = Paths.get(keyUrl); SecretKey secretKey = this.readKey(keyPath); cipher.init(Cipher.DECRYPT_MODE, secretKey); byte[] encodedBytes = Base64.getDecoder().decode(desrpytStr.getBytes()); byte[] result = cipher.doFinal(encodedBytes);//对加密后的字节数组进行解密 return new String(result); } public static void main(String[] args) throws Exception { AESUtil aesUtil = new AESUtil(); String enctyptStr = aesUtil.encrypt("123456aaa"); System.err.println(enctyptStr); String decrpytStr = aesUtil.decrpyt(enctyptStr); System.err.println(decrpytStr); } }