欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 八卦 > Java实现Js crypto-js加密

Java实现Js crypto-js加密

2024/10/24 19:27:50 来源:https://blog.csdn.net/putMap/article/details/140627550  浏览:    关键词:Java实现Js crypto-js加密

AES 加密算法采用分组密码体制,每个分组数据的长度为128位16个字节,密钥长度可以是128位16个字节、192位或256位,一共有四种加密模式,我们通常采用需要初始向量 IV 的 CBC 模式,初始向量的长度也是128位16个字节。 AES 加密的五个关键词,分别是:分组密码体制、Padding、密钥、初始向量 IV 和四种加密模式

5.1 分组密码体制 所谓分组密码体制就是指将明文切成一段一段的来加密,然后再把一段一段的密文拼起来形成最终密文的加密方式。AES 采用分组密码体制,即 AES 加密会首先把明文切成一段一段的,而且每段数据的长度要求必须是128位16个字节,如果最后一段不够16个字节了,就需要用 Padding 来把这段数据填满16个字节,然后分别对每段数据进行加密,最后再把每段加密数据拼起来形成最终的密文。

5.2 Padding Padding 就是用来把不满16个字节的分组数据填满16个字节用的,它有三种模式 PKCS5、PKCS7 和NOPADDING。PKCS5 是指分组数据缺少几个字节,就在数据的末尾填充几个字节的几,比如缺少5个字节,就在末尾填充5个字节的5。PKCS7 是指分组数据缺少几个字节,就在数据的末尾填充几个字节的0,比如缺少7个字节,就在末尾填充7个字节的0。NoPadding 是指不需要填充,也就是说数据的发送方肯定会保证最后一段数据也正好是16个字节。那如果在PKCS5 模式下,最后一段数据的内容刚好就是16个16怎么办?那解密端就不知道这一段数据到底是有效数据还是填充数据了,因此对于这种情况,PKCS5 模式会自动帮我们在最后一段数据后再添加16个字节的数据,而且填充数据也是16个16,这样解密段就能知道谁是有效数据谁是填充数据了。PKCS7 最后一段数据的内容是16个0,也是同样的道理。解密端需要使用和加密端同样的 Padding 模式,才能准确的识别有效数据和填充数据。我们开发通常采用 PKCS7 Padding 模式。

5.3 初始向量IV 初始向量 IV 的作用是使加密更加安全可靠,我们使用 AES 加密时需要主动提供初始向量,而且只需要提供一个初始向量就够了,后面每段数据的加密向量都是前面一段的密文。初始向量 IV 的长度规定为128位16个字节,初始向量的来源为随机生成。至于为什么初始向量能使加密更安全可靠,会在下面的加密模式中提到。

5.4 密钥 AES 要求密钥的长度可以是128位16个字节、192位或者256位,位数越高,加密强度自然越大,但是加密的效率自然会低一些,因此要做好衡量。我们开发通常采用128位16个字节的密钥,我们使用 AES 加密时需要主动提供密钥,而且只需要提供一个密钥就够了,每段数据加密使用的都是这一个密钥,密钥来源为随机生成(我们开发时传入的那个为初始密钥,除了初始密钥以外,后面每一轮的密钥都是由上一轮的密钥扩展而来的,密钥扩展有四个步骤:排列、置换、与轮常量异或、生成下一轮密钥的其他列)。

5.5 四种加密模式 AES 一共有四种加密模式,分别是 ECB(电子密码本模式)、CBC(密码分组链接模式)、CFB、OFB,我们一般使用的是 CBC 模式。四种模式中除了 ECB 相对不安全之外,其它三种模式的区别并没有那么大(ECB 模式是最基本的加密模式,即仅仅使用明文和密钥来加密数据,相同的明文块会被加密成相同的密文块,这样明文和密文的结构将是完全一样的,就会更容易被破解,相对来说不是那么安全,因此很少使用,而 CBC 模式则比 ECB 模式多了一个初始向量 IV,加密的时候,第一个明文块会首先和初始向量 IV 做异或操作,然后再经过密钥加密,然后第一个密文块又会作为第二个明文块的加密向量来异或,依次类推下去,这样相同的明文块加密出的密文块就是不同的,明文的结构和密文的结构也将是不同的,因此更加安全,我们常用的就是 CBC 加密模式)。 原文链接:https://blog.csdn.net/u014294681/article/details/86690241
1.AES硬编码密钥

package org.jeecg.modules.util;import lombok.extern.slf4j.Slf4j;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Base64;@Slf4j
public class AESUtils {private static final String ALGORITHM = "AES";private static final int KEY_SIZE = 128;private static final String TRANSFORMATION = ALGORITHM + "/ECB/PKCS5Padding";//加密public static String encrypt(String data, String key) throws Exception {log.info("加密前的数据:{}", data);// 使用平台默认的字符集进行转换,但在生产环境中,为了确保跨平台的一致性,建议显式指定字符集,例如使用 getBytes(StandardCharsets.UTF_8)Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);Cipher cipher = Cipher.getInstance(TRANSFORMATION);cipher.init(Cipher.ENCRYPT_MODE, secretKey);// 解决加密中文乱码问题byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));log.info("加密后的数据:{}", Base64.getEncoder().encodeToString(encryptedBytes));return Base64.getEncoder().encodeToString(encryptedBytes);}//解密public static String decrypt(String encryptedData, String key) throws Exception {log.info("解密前的数据:{}", encryptedData);// 使用平台默认的字符集进行转换,但在生产环境中,为了确保跨平台的一致性,建议显式指定字符集,例如使用 getBytes(StandardCharsets.UTF_8)Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);Cipher cipher = Cipher.getInstance(TRANSFORMATION);cipher.init(Cipher.DECRYPT_MODE, secretKey);byte[] decodedBytes = Base64.getDecoder().decode(encryptedData);byte[] decryptedBytes = cipher.doFinal(decodedBytes);log.info("解密后的数据:{}", new String(decryptedBytes));// 解决中文乱码问题return new String(decryptedBytes, StandardCharsets.UTF_8);}public static void main(String[] args) throws Exception {
//        String str = "6It99ux/BK2oQlY4PVqgsC0HCuWTLqBkIPrWDqEgh9k9ri3P32NzY86/dMWal/HTtcN75gRwXxZLK/0d+bs88BHLCULS49M5Zv7IkiVRbyAIYth+tctCockmhDL0WH1XE5DPthVmLnIMB9QCC0vl4Q==";
//        System.out.println(decrypt(str, "5ff7db748e8397825ff7db748e839782"));
//        System.out.println("encrypt(\"[]\", KEY) = " + encrypt("[]", "5ff7db748e8397825ff7db748e839782"));String str1 = "[{\"cndData\":{},\"limit\":20,\"params\":{\"ageBgn\":null,\"ageEnd\":null,\"dtBgn\":[\"2024-07-22 00:00:00\",\"2024-07-22 23:59:59\"],\"naDiag\":null,\"naPi\":\"蔡昱铭\",\"sdTpl\":\"2\"},\"sort\":null,\"start\":0}]";String encrypt1 = encrypt(str1, "5ff7db748e8397825ff7db748e839782");System.out.println(encrypt1);String str2 = "E4mJq1NcvNWNvdro4HMo8DkoHBRcokjwKJHMQsnXnyahweY+gYlQQOmAFdlwp7vDCI57FWtOjDHBAxbbLUkaYop5vNXU4jQVvsCK7uuHuuS3v8TIKJytwkUe4/KBadAuSzMSWDUjsp8y6ZWFdIqnfqBbnOFZLQxP/pdzKdXmofURriu9C+0JmVR5nEZyC4LSQLCEahRGyT+JB76Nq8H8ZOvDZx7mm06Xur7cDnD8sn4VmaIHaU+MSqUqdk450kU0";String decrypt1 = decrypt(str2, "5ff7db748e8397825ff7db748e839782");System.out.println(decrypt1);}
}

2.AES使用SecureRandom生成随机密钥

package org.jeecg.common.util;import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import java.security.Key;
import java.security.SecureRandom;@Component
public class AESUtils {private static Key key;public static String keyStr;private static String CHARSETNAME = "UTF-8";private static String ALGORITHM = "AES";@Value("${encrypt.key:NmehU6NWTkk6E}")public void setKeyStr(String keyStr) {DBAesUtil.keyStr = keyStr;try {//生成DES算法对象KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);//运用SHA1安全策略SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");//设置上密钥种子secureRandom.setSeed(DBAesUtil.keyStr.getBytes());//初始化基于SHA1的算法对象generator.init(secureRandom);//生成密钥对象key = generator.generateKey();} catch (Exception e) {throw new RuntimeException(e);}}/**** 获取加密的信息* @param str* @return*/public static String getEncryptString(String str) {//基于BASE64编码,接收byte[]并转换成StringBASE64Encoder encoder = new BASE64Encoder();try {//按utf8编码byte[] bytes = str.getBytes(CHARSETNAME);//获取加密对象Cipher cipher = Cipher.getInstance(ALGORITHM);//初始化密码信息cipher.init(Cipher.ENCRYPT_MODE, key);//加密byte[] doFinal = cipher.doFinal(bytes);//byte[]to encode好的String 并返回return encoder.encode(doFinal);} catch (Exception e) {throw new RuntimeException(e);}}/**** 获取解密之后的信息* @param str* @return*/public static String getDecryptString(String str) {BASE64Decoder decoder = new BASE64Decoder();try {//将字符串decode成byte[]byte[] bytes = decoder.decodeBuffer(str);//获取解密对象Cipher cipher = Cipher.getInstance(ALGORITHM);//初始化解密信息cipher.init(Cipher.DECRYPT_MODE, key);//解密byte[] doFial = cipher.doFinal(bytes);return new String(doFial, CHARSETNAME);} catch (Exception e) {throw new RuntimeException(e);}}
}

3.DES示例
DES算法的入口参数有三个:Key、Data、Mode。 Key 是 DES 算法的工作密钥。 Data 是要被加密或被解密的数据。 Mode 为 DES 的工作方式,有两种:加密或解密。

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Base64;public class DESExample {public static void main(String[] args) throws Exception {// 生成DES密钥Key secretKey = generateDESKey();// 原始数据String originalData = "Hello, DES!";System.out.println("原始数据: " + originalData);// 加密String encryptedData = encrypt(originalData, secretKey);System.out.println("加密后数据: " + encryptedData);// 解密String decryptedData = decrypt(encryptedData, secretKey);System.out.println("解密后数据: " + decryptedData);}/*** 生成DES密钥*/public static Key generateDESKey() throws Exception {KeyGenerator keyGenerator = KeyGenerator.getInstance("DES");keyGenerator.init(new SecureRandom());SecretKey secretKey = keyGenerator.generateKey();return secretKey;}/*** 加密方法*/public static String encrypt(String data, Key key) throws Exception {Cipher cipher = Cipher.getInstance("DES");cipher.init(Cipher.ENCRYPT_MODE, key);byte[] encryptedBytes = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));return Base64.getEncoder().encodeToString(encryptedBytes);}/*** 解密方法*/public static String decrypt(String data, Key key) throws Exception {byte[] decodedBytes = Base64.getDecoder().decode(data);Cipher cipher = Cipher.getInstance("DES");cipher.init(Cipher.DECRYPT_MODE, key);byte[] decryptedBytes = cipher.doFinal(decodedBytes);return new String(decryptedBytes, StandardCharsets.UTF_8);}
}

首先使用KeyGenerator生成了一个DES密钥。然后,我们定义了两个方法:encrypt用于加密明文数据,decrypt用于解密密文数据。这两个方法都使用了Cipher类,并通过指定加密模式(Cipher.ENCRYPT_MODE或Cipher.DECRYPT_MODE)和密钥来初始化它。加密后的数据被转换为Base64编码的字符串,以便以文本形式显示和存储。解密时,我们首先对Base64编码的数据进行解码,然后再使用Cipher进行解密操作。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com