암호화에서 암호화 알고리즘은 단방향 암호화와 양방향 암호화로 구분됩니다.
대칭 암호화는 AES 암호화, DES 암호화 등을 포함하여 암호화와 복호화가 동일한 키를 사용함을 의미합니다.
비대칭 암호화는 RSA 암호화 등을 포함하여 암호화와 복호화가 서로 다른 키를 사용한다는 의미입니다.
단방향 암호화에는 되돌릴 수 없는 MD5 및 SHA와 같은 다이제스트 알고리즘이 포함됩니다.
양방향 암호화에는 대칭 암호화와 비대칭 암호화가 포함됩니다. 양방향 암호화는 되돌릴 수 있으며 암호문에 대한 키가 존재합니다.
AES: 고급 암호화 표준(Advanced Encryption Standard)은 미국 연방 정부에서 채택한 블록 암호화 표준으로 현재 가장 널리 사용되는 대칭 암호화 알고리즘입니다. 코드>.
对称加密算法
。
是用来替代DES的新一代分组加密算法。
AES支持三种长度的密钥:128位、192位、256位。
AES的加解密过程和DES一样,都是通过分组加密
、分组解密。所谓分组加密,就是将待加解密的内容按照128位进行分组,将密钥按照128位、192位、256位进行分组,分别将分组后的明文与相应分组后的密钥进行加解密。
加密: 明文与密钥分组后,对每组:明文组与密钥组处理 -> 轮密钥加 -> 10轮加密 -> 密文组
解密: 对每组:密文组 -> 轮密钥加 -> 10轮解密 -> 明文组
明文分组: 每组长度相等,都是128位(16字节);
密钥分组: 有128位、192位、256位,推荐加密轮数分别为 10、12、14
密钥组处理: 以密钥分组每组128位为例(则推荐加密轮数为10,前9次执行操作一样,第十次有所不同) 类似地,128位密钥也是用字节为单位的矩阵表示,通过密钥编排函数,形成具有44个元素的序列W[0],W[1], … ,W[43](每个元素4个字节);其中,W[0],W[1],W[2],W[3]为原始密钥,其余40个元素分为10组,每组4个元素(4*4=16字节),分别用于10轮加密。
AES加密算法涉及4种操作: 字节替代
(SubBytes)、行移位
(ShiftRows)、列混淆
(MixColumns)和轮密钥加
(AddRoundKey)。
下图给出了AES加解密的流程:
AddRoundKey (轮密钥加)— 矩阵中的每一个字节都与该次轮密钥(round key)做XOR运算;每个子密钥由密钥生成方案产生。
SubBytes(字节替代) — 通过非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。
ShiftRows(行移位) — 将矩阵中的每个横列进行循环式移位。
MixColumns (列混淆)— 为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每列的四个字节。
假如一段明文长度是192bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding)。
填充涉及以下三种填充模式
:
NoPadding
:不做任何填充,但是要求明文必须是16字节的整数倍。
PKCS5Padding
(默认):如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。
比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6}
ISO10126Padding
3. AES 암호화 과정(AES 처리 단위: 바이트)
AES의 암호화 및 복호화 과정은
암호화:블록 암호화
와 그룹 복호화 모두 DES와 동일합니다. 소위 블록 암호화란 암호화 및 복호화할 내용을 128비트 단위로 그룹화하고, 키를 128비트, 192비트, 256비트 단위로 그룹화하고, 그룹화된 평문과 이에 상응하는 평문을 암호화 및 복호화하는 것입니다. 그룹화된 키입니다.일반 텍스트와 키를 그룹화한 후 각 그룹 처리: 일반 텍스트 그룹 및 키 그룹-> 10라운드 암호화-> 암호문 그룹
복호화:오른쪽 각 그룹: 암호 텍스트 그룹-> 라운드 키 추가-> 일반 텍스트 그룹
일반 텍스트 그룹: 🎜 각 그룹의 길이는 모두 128비트(16바이트)입니다. 그룹화: 🎜 권장되는 암호화 라운드는 각각 10, 12, 14비트입니다. 🎜🎜🎜키 그룹 처리: 🎜 그룹당 128비트의 키 그룹화를 예로 들어 보겠습니다. 권장 암호화 라운드 수는 10이며 처음 9번은 연산이 동일하고 10번은 다름) 마찬가지로 128비트 키도 바이트 단위의 행렬로 표현되며 키 배열 기능을 사용하여 44개 요소를 포함하는 시퀀스 W[0], W[1], &hellip, W[43](요소당 4바이트), W[0], W[1], W[2], W[3 ]는 원본 키이고, 나머지 40개 요소는 10개 그룹으로 나뉘며, 각 그룹에는 4개 요소(4*4=16바이트)가 있으며, 이는 각각 10라운드 암호화에 사용됩니다. 🎜🎜🎜AES 암호화 알고리즘에는 4가지 작업이 포함됩니다: 🎜바이트 대체
(SubBytes),행 이동
(ShiftRows),열 난독화
(MixColumns) 및라운드 키 추가
(AddRoundKey). 🎜🎜다음 그림은 AES 암호화 및 암호 해독 프로세스를 보여줍니다. 🎜🎜🎜🎜🎜AddRoundKey(라운드 키 추가)🎜— 매트릭스의 각 바이트는 라운드 키와 XOR됩니다. 각 하위 키는 키 생성 방식에 의해 생성됩니다. . 🎜🎜🎜🎜🎜SubBytes(바이트 대체)🎜 — 비선형 대체 함수를 통해 조회 테이블을 사용하여 각 바이트를 해당 바이트로 대체합니다. 🎜🎜🎜🎜🎜ShiftRows(행 이동)🎜 — 행렬의 각 열을 순환적으로 이동합니다. 🎜🎜🎜🎜🎜MixColumns (열 혼동)🎜— 행렬의 각 직선 행의 연산을 완전히 혼합하기 위해. 이 단계에서는 선형 변환을 사용하여 각 열의 4바이트를 혼합합니다. 🎜🎜🎜🎜🎜 🎜문단의 경우 평문의 길이가 192비트라면 128비트마다 하나의 평문 블록으로 분할되면 두 번째 평문 블록은 64비트에 불과해 128비트보다 작습니다. 이때 무엇을 해야 할까요? 일반 텍스트 블록을 패딩(Padding)하는 것이 필요합니다. 🎜🎜Padding에는 다음세 가지 패딩 모드
가 포함됩니다. 🎜🎜🎜🎜NoPadding
: 패딩은 수행되지 않지만 일반 텍스트는 16바이트의 정수 배수여야 합니다. 🎜🎜🎜🎜PKCS5Padding
(기본값): 일반 텍스트 블록이 16바이트(128비트) 미만인 경우 해당 문자 수가 일반 텍스트 블록 끝에 추가되고 각 바이트의 값 누락된 문자 번호와 같습니다. 🎜🎜🎜🎜예를 들어 일반 텍스트가 {1,2,3,4,5,a,b,c,d,e}인 경우 6바이트가 누락되면 완성은 {1,2, 3,4,5, a,b,c,d,e,6,6,6,6,6,6}🎜🎜🎜🎜ISO10126Padding
: 일반 텍스트 블록이 16바이트 미만인 경우 (128bit), 일반 텍스트에서 블록의 끝은 해당 바이트 수로 채워지고 마지막 문자 값은 누락된 문자 수와 동일하며 나머지 문자는 임의의 숫자로 채워집니다. 🎜🎜🎜🎜예를 들어 일반 텍스트: {1,2,3,4,5,a,b,c,d,e}, 6바이트가 누락된 경우 완성은 {1,2,3,4일 수 있습니다. ,5 ,a,b,c,d,e,5,c,3,G,$,6}🎜🎜4.Java 구현🎜🎜🎜참고: AES 암호화에는 Base64 암호화가 포함됩니다🎜🎜🎜🎜🎜암호화:🎜 AES 암호화-> Base64 암호화-> 암호문 🎜🎜🎜 복호화: 🎜 Base64 복호화-> 일반 텍스트 🎜🎜🎜 테스트 주소: 여기를 클릭하세요 🎜🎜
16개의 임의의 대문자, 소문자 및 숫자 생성:
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 数字和26个字母组成 private static final Random RANDOM = new SecureRandom(); /** * 获取长度为 6 的随机字母+数字 * @return 随机数字 */ public static String getRandomNumber() { char[] nonceChars = new char[16]; //指定长度为6位/自己可以要求设置 for (int index = 0; index < nonceChars.length; ++index) { nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length())); } return new String(nonceChars); }
import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.Base64Utils; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * AES加密工具类 * * @author ACGkaka * @since 2021-06-18 19:11:03 */ public class AESUtil { /** * 日志相关 */ private static final Logger LOGGER = LoggerFactory.getLogger(AESUtil.class); /** * 编码 */ private static final String ENCODING = "UTF-8"; /** * 算法定义 */ private static final String AES_ALGORITHM = "AES"; /** * 指定填充方式 */ private static final String CIPHER_PADDING = "AES/ECB/PKCS5Padding"; private static final String CIPHER_CBC_PADDING = "AES/CBC/PKCS5Padding"; /** * 偏移量(CBC中使用,增强加密算法强度) */ private static final String IV_SEED = "1234567812345678"; /** * AES加密 * @param content 待加密内容 * @param aesKey 密码 * @return */ public static String encrypt(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES encrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置加密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_PADDING); //选择加密 cipher.init(Cipher.ENCRYPT_MODE, skeySpec); //根据待加密内容生成字节数组 byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING)); //返回base64字符串 return Base64Utils.encodeToString(encrypted); } catch (Exception e) { LOGGER.info("AES encrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES encrypt: the aesKey is null or error!"); return null; } } /** * 解密 * * @param content 待解密内容 * @param aesKey 密码 * @return */ public static String decrypt(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES decrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置解密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_PADDING); //选择解密 cipher.init(Cipher.DECRYPT_MODE, skeySpec); //先进行Base64解码 byte[] decodeBase64 = Base64Utils.decodeFromString(content); //根据待解密内容进行解密 byte[] decrypted = cipher.doFinal(decodeBase64); //将字节数组转成字符串 return new String(decrypted, ENCODING); } catch (Exception e) { LOGGER.info("AES decrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES decrypt: the aesKey is null or error!"); return null; } } /** * AES_CBC加密 * * @param content 待加密内容 * @param aesKey 密码 * @return */ public static String encryptCBC(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES_CBC encrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置加密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING); //偏移 IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING)); //选择加密 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); //根据待加密内容生成字节数组 byte[] encrypted = cipher.doFinal(content.getBytes(ENCODING)); //返回base64字符串 return Base64Utils.encodeToString(encrypted); } catch (Exception e) { LOGGER.info("AES_CBC encrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES_CBC encrypt: the aesKey is null or error!"); return null; } } /** * AES_CBC解密 * * @param content 待解密内容 * @param aesKey 密码 * @return */ public static String decryptCBC(String content, String aesKey){ if(StringUtils.isBlank(content)){ LOGGER.info("AES_CBC decrypt: the content is null!"); return null; } //判断秘钥是否为16位 if(StringUtils.isNotBlank(aesKey) && aesKey.length() == 16){ try { //对密码进行编码 byte[] bytes = aesKey.getBytes(ENCODING); //设置解密算法,生成秘钥 SecretKeySpec skeySpec = new SecretKeySpec(bytes, AES_ALGORITHM); //偏移 IvParameterSpec iv = new IvParameterSpec(IV_SEED.getBytes(ENCODING)); // "算法/模式/补码方式" Cipher cipher = Cipher.getInstance(CIPHER_CBC_PADDING); //选择解密 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); //先进行Base64解码 byte[] decodeBase64 = Base64Utils.decodeFromString(content); //根据待解密内容进行解密 byte[] decrypted = cipher.doFinal(decodeBase64); //将字节数组转成字符串 return new String(decrypted, ENCODING); } catch (Exception e) { LOGGER.info("AES_CBC decrypt exception:" + e.getMessage()); throw new RuntimeException(e); } }else { LOGGER.info("AES_CBC decrypt: the aesKey is null or error!"); return null; } } public static void main(String[] args) { // AES支持三种长度的密钥:128位、192位、256位。 // 代码中这种就是128位的加密密钥,16字节 * 8位/字节 = 128位。 String random = RandomStringUtils.random(16, "abcdefghijklmnopqrstuvwxyz1234567890"); System.out.println("随机key:" + random); System.out.println(); System.out.println("---------加密---------"); String aesResult = encrypt("测试AES加密12", random); System.out.println("aes加密结果:" + aesResult); System.out.println(); System.out.println("---------解密---------"); String decrypt = decrypt(aesResult, random); System.out.println("aes解密结果:" + decrypt); System.out.println(); System.out.println("--------AES_CBC加密解密---------"); String cbcResult = encryptCBC("测试AES加密12456", random); System.out.println("aes_cbc加密结果:" + cbcResult); System.out.println(); System.out.println("---------解密CBC---------"); String cbcDecrypt = decryptCBC(cbcResult, random); System.out.println("aes解密结果:" + cbcDecrypt); System.out.println(); } }
随机key:golrtt58318fx7ol ---------加密--------- aes加密结果:Xy8W9lCeVue9Ao36z+duM7D7WeS5tdBihIMb1q9KpNg= ---------解密--------- aes解密结果:测试AES加密12 --------AES_CBC加密解密--------- aes_cbc加密结果:xs3ypQXyd62P9jB0+RvOqxFnHIHBIlVdqoZLuqYNBLw= ---------解密CBC--------- aes解密结果:测试AES加密12456
위 내용은 Java에서 AES 암호화 및 암호 해독 작업을 수행하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!