文章目录

  • 单向散列哈希算法
  • md5
  • DigestUtils(spring)实现md5
  • 对称加密算法
  • base64
  • BASE64
  • jdk自带base64工具
  • base64有什么好处
  • aes加密算法
  • 代码
  • AES加密时报错 Cannot find any provider supporting AES/CBC/PKCS7Padding
  • aes加密时报错 Illegal key size or default parameters
  • 非对称加密算法(又称:公开密钥加密算法)
  • 对称加密和非对称加密的结合


单向散列哈希算法

摘要算法的特点:
1、无论输入的长度是多少,输出总是固定的长度。
2、如果输入有变化,摘要一定不同。

基于这个原理可以对数据的完整性和一致性进行校验。
由于是提取的不是全部内容,所以无法还原为原始值。

MD5、SHA(128、256)系列

描述

单向不可逆

场景

用户密码的加密

md5

摘要算法

DigestUtils(spring)实现md5
//md5 单向加密
String password="芝麻开门";
String digest = DigestUtils.md5DigestAsHex(password.getBytes()); // digest是摘要算法,这里只生成的字符串
System.out.println(digest);

对称加密算法

DES、3DES、AES、Blowfish、IDEA、RC5、RC6

base64

首先强调一点,base64属于编码算法,不属于加密算法,概念一定要搞清楚

描述

双向可逆加密

场景

邮件中的信息

BASE64

base64工具类有很多。

jdk自带base64工具

jdk自带的base64工具就不错。 类路径为: java.util.Base64

// jdk自带的BASE64 加解密工具
String password="芝麻开门";
BASE64Encoder base64Encoder = new BASE64Encoder();
String encode = base64Encoder.encode(password.getBytes());  // 加密
System.out.println("加密为字符串:  " + encode);
BASE64Decoder decoder = new BASE64Decoder();
try {
    String decode = new String ( decoder.decodeBuffer(encode)); // 解密
    System.out.println("解密为:  " + decode);
} catch (IOException e) {
    e.printStackTrace();
}

再来一个例子:

// 文件流到base64字符串
File refereeFile = new File("D://我的.jpg");
byte[] refereeFileOriginalBytes = FileUtils.readFileToByteArray(refereeFile);
String base64String = Base64.getEncoder().encodeToString(refereeFileOriginalBytes);
logger.info("base64字符串:{}",base64String);

//base64字符串到文件
byte[] bytes = Base64.getDecoder().decode(base64String);
File file = new File("D://base64转换为我的.jpg");
FileUtils.writeByteArrayToFile(file,bytes);  // 执行完之后去文件系统查看是否有这个文件

字符串直接复制到java,因为太大可能报错,所以最好把字符串写在文件里面再读取,如下例子:

// 文件流到base64字符串
File refereeFile = new File("D://base64String.txt");
try {
    String base64String = FileUtils.readFileToString(refereeFile);
    //base64字符串到文件
    byte[] bytes = Base64.getDecoder().decode(base64String);
    File file = new File("D://base64转换为我的.jpg");
    FileUtils.writeByteArrayToFile(file,bytes);  // 执行完之后去文件系统查看是否有这个文件
} catch (IOException e) {
    e.printStackTrace();
}

base64有什么好处

1是不直接显示文件流,稍微安全些。
另外,如果不考虑性能,数据之间的转移也比较方便,就当做是个大点的字符串。

对于需要反复读写的不是特别大的文件,可以把base64放在内存中。省去了io和网络rest的时间。

aes加密算法

五种加密算法:
ECB
CBC
CTR
OFB
CFB
不用纠结具体区别了,就是起个匹配的作用,和前后端匹配时一致即可。

主要参数:
key
偏移量(懒一点的话,可以设置为和key一样)
算法 例如:AES/CBC/PKCS7Padding

代码

aes属于通用工具,网上代码很多,随便来一段吧。

@Slf4j
@Component
public class AESUtils {

    // AES密钥算法
    private static final String KEY_ALGORITHM = "AES";

    // 加密/解密算法/工作模式/填充方式
    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";


    @Value("${aesKey:kkkkkkkkkkkkkkkk==}")
    private String tempAesKey; 

    public static String AES_KEY;

    @PostConstruct
    public void init(){
        log.info("AES工具类初始化开始", tempAesKey);
        AES_KEY=tempAesKey;
        log.info("AES工具类初始化完成,aesKey={}",AES_KEY );
    }

    // 生成密钥
    public static String generateAESKey() throws Exception {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
        keyGenerator.init(128, new SecureRandom()); // 192 and 256 bits may not be available
        SecretKey secretKey = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(secretKey.getEncoded());
    }

    // 加密
    public static String encrypt(String data, String key) throws Exception {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(key), KEY_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
        byte[] encrypted = cipher.doFinal(data.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);
    }

    // 解密
    public static String decrypt(String data, String key) throws Exception {
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        SecretKeySpec secretKeySpec = new SecretKeySpec(Base64.getDecoder().decode(key), KEY_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
        byte[] original = cipher.doFinal(Base64.getDecoder().decode(data));
        return new String(original);
    }

    public static void main(String[] args) throws Exception {
        // 这个方法只有第一次用,生成后以后固定用一个值即可 自己编写的key不一定符合位数等要求,所以第一次要自己生成
//        String key = generateAESKey();
        String key="kkkkkkkkkkkkkkkk==";

        
        String originalText = "hello world";
        String encryptedText = encrypt(originalText, key);
        String decryptedText = decrypt(encryptedText, key);

        log.info("key={}", key);
        log.info("originalText={}", originalText);
        log.info("encryptedText={}", encryptedText);
        log.info("decryptedText={}", decryptedText);

    }
}

注:一直以为aes很简单,眼高手低,实际使用的时候还是有些要注意。
例如用默认的方法,每次key都是重新生成,导致解密失败
实际生成key后应该固定用这个key,就可以解密成功了

AES加密时报错 Cannot find any provider supporting AES/CBC/PKCS7Padding

是因为jdk1.8不支持这个算法,需要下载补丁包,放到jdk jar包目录下。(不推荐,因为成本太多,从开发到服务器都要操作)

aes加密时报错 Illegal key size or default parameters

报错解释:

这个错误通常发生在使用Java加密时,尤其是AES加密算法。在JDK 8 Update 161及以后的版本中,引入了新的加密策略限制(称为JEP 261: JDK Cryptography Extension Policy),这意味着默认情况下,Java加密库中的一些加密算法可能被限制使用。Illegal key size or default parameters错误表明你正在使用的加密密钥大小超出了Java加密库的默认限制。

注:这堆内容啰哩吧嗦,知道是版本不对就行了。

解决方法:
1、更新JDK到8u161或更高版本,这样可以使用未受限制的加密策略
2、下载补丁包。
jdk7的略。

# 这个是jdk8的,官网太慢,直接从这里下吧

下载完成后,解压缩下载的文件。你将会得到两个JAR文件:local_policy.jar和US_export_policy.jar。

下载包的readme.txt 有安装说明,即替换
${jdk_home}/jre/lib/security${jre_home}/lib/security 目录下的 local_policy.jarUS_export_policy.jar 文件。

自己下载的步骤
步骤 1:下载Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files打开Oracle官方网站,搜索"Java Cryptography Extension Unlimited Strength Jurisdiction Policy Files"。

进入下载页面,找到适用于你的Java版本的文件,并下载。

非对称加密算法(又称:公开密钥加密算法)

RSA,见rsa博客。

对称加密和非对称加密的结合