技术经验分享:JAVAAES加密与解密

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 技术经验分享:JAVAAES加密与解密

本博文出自


一、AES加密简介


AES加密算法是密码学中的高级加密标准(Advanced Encryption Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。


AES 是一个新的可以用于保护电子数据的加密算法。明确地说,AES 是一个迭代的、对称密钥分组的密码,它可以使用128、192 和 256 位密钥,并且用 128 位(16字节)分组加密和解密数据。与公共密钥密码使用密钥对不同,对称密钥密码使用相同的密钥加密和解密数据。通过分组密码返回的加密数据 的位数与输入数据相同。迭代加密使用一个循环结构,在该循环中重复置换(permutations )和替换(substitutions)输入数据。


AES加密有很多轮的重复和变换。大致步骤如下:


1、密钥扩展(KeyExpansion)。


2、初始轮(Initial Round)。


3、重复轮(Rounds),每一轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey。


4、最终轮(Final Round),最终轮没有MixColumns。


二、AES在JAVA中的使用


JCE,Java Cryptography Extension,在早期JDK版本中,由于受美国的密码出口条例约束,Java中涉及加解密功能的API被限制出口,所以Java中安全组件被分成了两部分: 不含加密功能的JCA(Java Cryptography Architecture )和含加密功能的JCE(Java Cryptography Extension)。


JCA和JCE的API体系架构


JCE的API都在javax.crypto包下,核心功能包括:加解密、密钥生成(对称)、MAC生成、密钥协商。


(1). 加解密


加解密功能由Cipher组件提供,其也是JCE中最核心的组件。


1. Cipher的几个知识点:


a. Cipher在使用时需以参数方式指定transformation


b. transformation的格式为algorithm/mode/padding,其中algorithm为必输项,如: AES/DES/CBC/PKCS5Padding


c. 缺省的mode为ECB,缺省的padding为PKCS5Padding


d. 在block算法与流加密模式组合时, 需在mode后面指定每次处理的bit数, 如DES/CFB8/NoPadding, 如未指定则使用缺省值, SunJCE缺省值为64bits


e. Cipher有4种操作模式: ENCRYPT_MODE(加密), DECRYPT_MODE(解密), WRAP_MODE(导出Key), UNWRAP_MODE(导入Key),初始化时需指定某种操作模式


算法/模式/填充 16字节加密后数据长度 不满16字节加密后长度


AES/CBC/NoPadding 16 不支持


AES/CBC/PKCS5Padding 32 16


AES/CBC/ISO10126Padding 32 16


AES/CFB/NoPadding 16 原始数据长度


AES/CFB/PKCS5Padding 32 16


AES/CFB/ISO10126Padding 32 16


AES/ECB/NoPadding 16 不支持


AES/ECB/PKCS5Padding 32 16


AES/ECB/ISO10126Padding 32 16


AES/OFB/NoPadding 16 原始数据长度


AES/OFB/PKCS5Padding 32 16


AES/OFB/ISO10126Padding 32 16


AES/PCBC/NoPadding 16 不支持


AES/PCBC/PKCS5Padding 32 16


AES/PCBC/ISO10126Padding 32 16


可以看到,在原始数据长度为16的整数倍时,假如原始数据长度等于16n,则使用NoPadding时加密后数据长度等于16n,其它情况下加密数据长 度等于16(n+1)。在不足16的整数倍的情况下,假如原始数据长度等于16n+m【其中m小于16】,除了NoPadding填充之外的任何方 式,加密数据长度都等于16(n+1);NoPadding填充情况下,CBC、ECB和PCBC三种模式是不支持的,CFB、OFB两种模式下则加密 数据长度等于原始数据长度。


2. 对称加密的算法与密钥长度选择


算法名称 密钥长 块长 速度 说明


DES 56 64 64 慢 不安全, 不要使用


3DES 112/168 64 很慢 中等安全, 适合加密较小的数据


AES 128, 192, 256 128 快 安全


Blowfish (4至56)8 64 快 快 应该安全, 在安全界尚未被充分分析、论证


RC4 40-1024 64 很快 安全性不明确


推荐使用AES算法。一般认为128bits的密钥已足够安全,如果可以请选择256bits的密钥。注意:


a. 密钥长度是在生成密钥时指定的,如:


KeyGenerator generator = KeyGenerator.getInstance("AES/CBC/PKCS5PADDING");


generator.init(256);


SecretKey key = generator.generateKey();


3. 加密示例代码


/


根据密钥对指定的明文plainText进行加密.



@param plainText 明文


@return 加密后的密文.


*/


public static final String encrypt(String plainText) {


Key secretKey = getKey("fendo888");


try {


Cipher cipher = Cipher.getInstance("AES");


cipher.init(Cipher.ENCRYPT_MODE, secretKey);


byte【】 p = plainText.getBytes("UTF-8");


byte【】 result = cipher.doFinal(p);


BASE64Encoder encoder = new BASE64Encoder();


String encoded = encoder.encode(result)//代码效果参考:http://hnjlyzjd.com/xl/wz_24477.html

;

return encoded;


} catch (Exception e) {


throw new RuntimeException(e);


}


}


4. 解密示例代码


/


根据密钥对指定的密文cipherText进行解密.



@param cipherText 密文


@return 解密后的明文.


/


public static final String decrypt(String cipherText) {


Key secretKey = getKey("fendo888");


try {


Cipher cipher = Cipher.getInstance("AES");


cipher.init(Cipher.DECRYPT_MODE, secretKey);


BASE64Decoder decoder = new BASE64Decoder();


byte【】 c = decoder.decodeBuffer(cipherText);


byte【】 result = cipher.doFinal(c);


String plainText = new String(result, "UTF-8");


return plainText;


} catch (Exception e) {


throw new RuntimeException(e);


}


}


其中的getKey()


public static Key getKey(String keySeed) {


if (keySeed == null) {


keySeed = System.getenv("AES_SYS_KEY");


}


if (keySeed == null) {


keySeed = System.getProperty("AES_SYS_KEY");


}


if (keySeed == null || keySeed.trim().length() == 0) {


keySeed = "abcd1234!@#$";// 默认种子


}


try {


SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");


secureRandom.setSeed(keySeed.getBytes());


KeyGenerator generator = KeyGenerator.getInstance("AES");


generator.init(secureRandom);


return generator.generateKey();


} catch (Exception e) {


throw new RuntimeException(e);


}


}


三.AESUtils帮助类


package com.fendo.MD5;


import java.io.IOException;


import java.io.UnsupportedEncodingException;


import java.security.InvalidKeyException;


import java.security.NoSuchAlgorithmException;


import java.security.SecureRandom;


import javax.crypto.BadPaddingException;


import javax.crypto.Cipher;


import javax.crypto.IllegalBlockSizeException;


import javax.crypto.KeyGenerator;


import javax.crypto.NoSuchPaddingException;


import javax.crypto.SecretKey;


import javax.crypto.spec.SecretKeySpec;


import org.apache.commons.lang3.StringUtils;


import sun.misc.BASE64Decoder;


import sun.misc.BASE64Encoder;


/**


@Title: AESUtils.java


@Package com.fendo.MD5


@Description: TODO


@author fendo


@date 2017年9月11日 下午5:48:17


@version V1.0


/


public class AESUtils {


private static final String encodeRules = "fendo";


/


加密


1.构造密钥生成器


2.根据ecnodeRules规则初始化密钥生成器


3.产生密钥


4.创建和初始化密码器


5.内容加密


6.返回字符串


/


public static String AESEncode(String content) {


try {


//1.构造密钥生成器,指定为AES算法,不区分大小写


KeyGenerator keygen = KeyGenerator.getInstance("AES");


//2.根据ecnodeRules规则初始化密钥生成器


//生成一个128位的随机源,根据传入的字节数组


SecureRandom random = SecureRandom.getInstance("SHA1PRNG");


random.setSeed(encodeRules.getBytes());


keygen.init(128, random);


//3.产生原始对称密钥


SecretKey original_key = keygen.generateKey();


//4.获得原始对称密钥的字节数组


byte【】 raw = original_key.getEncoded();


//5.根据字节数组生成AES密钥


SecretKey key = new SecretKeySpec(raw, "AES");


//6.根据指定算法AES自成密码器


Cipher cipher = Cipher.getInstance("AES");


//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY


cipher.init(Cipher.ENCRYPT_MODE, key);


//8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码


byte【】 byte_encode = content.getBytes("utf-8");


//9.根据密码器的初始化方式--加密:将数据加密


byte【】 byte_AES = cipher.doFinal(byte_encode);


//10.将加密后的数据转换为字符串


//这里用Base64Encoder中会找不到包


//解决办法:


//在项目的Build path中先移除JRE System Library,再添加库JRE System Library,重新编译后就一切正常了。


String AES_encode = new String(new BASE64Encoder().encode(byte_AES));


//11.将字符串返回


return AES_encode;


} 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 (UnsupportedEncodingException e) {


e.printStackTrace();


}


//如果有错就返加nulll


return null;


}


/


AES加密


@param content 待加密的内容


@param encryptKey 加密密钥


@return 加密后的byte【】


@throws Exception


/


public static byte【】 aesEncryptToBytes(String content, String encryptKey) throws Exception {


KeyGenerator kgen = KeyGenerator.getInstance("AES");


kgen.init(128, new SecureRandom(encryptKey.getBytes()));


Cipher cipher = Cipher.getInstance("AES");


cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));


return cipher.doFinal(content.getBytes("utf-8"));


}


/


解密


解密过程:


1.同加密1-4步


2.将加密后的字符串反纺成byte【】数组


3.将加密内容解密


/


public static String AESDecode(String content) {


try {


//1.构造密钥生成器,指定为AES算法,不区分大小写


KeyGenerator keygen = KeyGenerator.getInstance("AES");


//2.根据ecnodeRules规则初始化密钥生成器


//生成一个128位的随机源,根据传入的字节数组


SecureRandom random = SecureRandom.getInstance("SHA1PRNG");


random.setSeed(encodeRules.getBytes());


keygen.init(128, random);


//3.产生原始对称密钥


SecretKey original_key = keygen.generateKey();


//4.获得原始对称密钥的字节数组


byte【】 raw = original_key.getEncoded();


//5.根据字节数组生成AES密钥


SecretKey key = new SecretKeySpec(raw, "AES");


//6.根据指定算法AES自成密码器


Cipher cipher = Cipher.getInstance("AES");


//7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密(Decrypt_mode)操作,第二个参数为使用的KEY


cipher.init(Cipher.DECRYPT_MODE, key);


//8.将加密并编码后的内容解码成字节数组


byte【】 byte_content = new BASE64Decoder().decodeBuffer(content);


/


解密


*/


byte【】 byte_decode = cipher.doFinal(byte_content);


String AES_decode = new String(byte_decode, "utf-8");


return AES_decode;


} catch (NoSuchAlgorithmException e) {


e.printStackTrace();


} catch (NoSuchPaddingException e) {


e.printStackTrace();


} catch (InvalidKeyException e) {


e.printStackTrace();


} catch (IOException e) {


e.printStackTrace();


} catch (IllegalBlockSizeException e) {


e.printStackTrace();


} catch (BadPaddingException e) {


e.printStackTrace();


}


//如果有错就返加nulll


return null;


}


/


AES解密


@param encryptBytes 待解密的byte【】


@param decryptKey 解密密钥


@return 解密后的String


@throws Exception


/


public static String aesDecryptByBytes(byte【】 encryptBytes, String decryptKey) throws Exception {


KeyGenerator kgen = KeyGenerator.getInstance("AES");


kgen.init(128, new SecureRandom(decryptKey.getBytes()));


Cipher cipher = Cipher.getInstance("AES");


cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));


byte【】 decryptBytes = cipher.doFinal(encryptBytes);


return new String(decryptBytes);


}


/


base 64 加密


@param bytes 待编码的byte【】


@return 编码后的base 64 code


/


public static String base64Encode(byte【】 bytes){


return new BASE64Encoder().encode(bytes);


}


/


base 64 解密


@param base64Code 待解码的base 64 code


@return 解码后的byte【】


@throws Exception


/


public static byte【】 base64Decode(String base64Code) throws Exception{


return StringUtils.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);


}


/**


将base 64 code AES解密


@param encryptStr 待解密的base 64 code


@param decryptKey 解密密钥


@return 解密后的string


@throws Exception


/


public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {


return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);


}


/**


AES加密为base 64 code


@param content 待加密的内容


@param encryptKey 加密密钥


@return 加密后的base 64 code


@throws Exception


*/


public static String aesEncrypt(String content, String encryptKey) throws Exception {


return base64Encode(aesEncryptToBytes(content, encryptKey));


}


public static void main(String【】 args) {


String【】 keys = {


"", "root"


};


System.out.println("key | AESEncode | AESDecode");


for (String key : keys) {


System.out.print("key:"+key + " | ");


String encryptString = AESEncode(key);


System.out.print(encryptString + " | ");


String decryptString = AESDecode(encryptString);


System.out.println(decryptString);


}


}


}


————————————————


版权声明:本文为CSDN博主「码农致富」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。


原文链接:


————————————————


版权声明:本文为CSDN博主「码农致富」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。


原文链接:

相关文章
|
21天前
|
存储 安全 算法
C#一分钟浅谈:数据加密与解密技术
【10月更文挑战第3天】在数字化时代,信息安全至关重要。数据加密作为保障信息不被未授权访问的有效手段,通过特定算法将明文转换为密文,确保即使数据被截获也难以解读。本文从基础概念入手,介绍C#中实现数据加密的方法,涵盖对称加密(如AES、DES)与非对称加密(如RSA),并通过具体示例代码演示如何使用`System.Security.Cryptography.Aes`类完成AES加密和解密过程。此外,还强调了密钥管理及安全策略的重要性。
33 4
|
24天前
|
安全 测试技术 Go
Python 和 Go 实现 AES 加密算法的技术详解
Python 和 Go 实现 AES 加密算法的技术详解
55 0
|
2月前
|
存储 安全 算法
RSA在手,安全我有!Python加密解密技术,让你的数据密码坚不可摧
【9月更文挑战第11天】在数字化时代,信息安全至关重要。传统的加密方法已难以应对日益复杂的网络攻击。RSA加密算法凭借其强大的安全性和广泛的应用场景,成为保护敏感数据的首选。本文介绍RSA的基本原理及在Python中的实现方法,并探讨其优势与挑战。通过使用PyCryptodome库,我们展示了RSA加密解密的完整流程,帮助读者理解如何利用RSA为数据提供安全保障。
88 5
|
2月前
|
存储 安全 算法
显微镜下的安全战!Python加密解密技术,透视数字世界的每一个安全细节
【9月更文挑战第7天】在数字世界中,数据安全至关重要。Python加密解密技术如同显微镜下的精密工具,确保信息的私密性和完整性。以大型医疗机构为例,通过AES和RSA算法的结合,既能高效加密大量医疗数据,又能安全传输密钥,防止数据泄露。以下是使用Python的`pycryptodome`库实现AES加密和RSA密钥交换的简化示例。此方案不仅提高了数据安全性,还为数字世界的每个细节提供了坚实保障,引领我们迈向更安全的未来。
33 1
|
3月前
|
存储 安全 算法
|
3月前
|
安全 开发者 数据安全/隐私保护
Xamarin 的安全性考虑与最佳实践:从数据加密到网络防护,全面解析构建安全移动应用的六大核心技术要点与实战代码示例
【8月更文挑战第31天】Xamarin 的安全性考虑与最佳实践对于构建安全可靠的跨平台移动应用至关重要。本文探讨了 Xamarin 开发中的关键安全因素,如数据加密、网络通信安全、权限管理等,并提供了 AES 加密算法的代码示例。
52 0
|
3月前
|
安全 物联网 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享未来技术浪潮中的领航者:区块链、物联网与虚拟现实
【8月更文挑战第30天】在数字化时代,网络安全和信息安全已成为我们生活中不可或缺的一部分。本文将介绍网络安全漏洞、加密技术和安全意识等方面的知识,帮助读者更好地了解网络安全的重要性,并提供一些实用的技巧和建议来保护个人信息和数据安全。
|
5天前
|
存储 安全 网络安全
网络安全的屏障与钥匙:漏洞防御与加密技术深度解析
【10月更文挑战第20天】在数字世界的迷宫中,网络安全是守护我们数据宝藏的坚固盾牌和锋利钥匙。本篇文章将带您穿梭于网络的缝隙之间,揭示那些潜藏的脆弱点—网络安全漏洞,同时探索如何通过现代加密技术加固我们的数字堡垒。从基本概念到实战策略,我们将一同揭开网络安全的神秘面纱,提升您的安全意识,保护个人信息不受侵犯。
38 25
|
3天前
|
安全 算法 网络安全
网络安全的守护者:漏洞、加密与安全意识
【10月更文挑战第22天】在数字时代的浪潮中,网络安全成为了我们无法回避的话题。本文将深入探讨网络安全的三大支柱:网络漏洞、加密技术和安全意识。我们将通过实例和代码示例,揭示网络攻击的常见手段,展示如何利用加密技术保护数据,以及如何提升个人和组织的安全意识。无论你是IT专家还是普通用户,这篇文章都将为你提供宝贵的知识和技能,帮助你在网络世界中更安全地航行。
|
5天前
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
【10月更文挑战第20天】在信息技术飞速发展的今天,网络安全和信息安全问题日益突出。本文将围绕网络安全漏洞、加密技术和安全意识等方面进行深入探讨,旨在提高读者对网络安全的认识和重视程度。文章首先介绍了网络安全漏洞的概念、分类和成因,然后详细阐述了加密技术的基本原理和应用,最后强调了提高个人和组织安全意识的重要性。通过本文的学习,读者将能够更好地理解网络安全的重要性,掌握一些实用的防护措施,并在日常生活中提高自己的安全意识。
46 10