展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

加解密:对称加密算法、口令加密算法

  • 对称加密算法
对称加密算法就是传统的用一个密码进行加密和解密

根据算法名称/工作模式/填充模式获取Cipher实例;
根据算法名称初始化一个SecretKey实例,密钥必须是指定长度;
使用SerectKey初始化Cipher实例,并设置加密或解密模式;
传入明文或密文,获得密文或明文。
算法 密钥长度 工作模式 填充模式
DES 56/64 ECB/CBC/PCBC/CTR/... NoPadding/PKCS5Padding/...
AES 128/192/256 ECB/CBC/PCBC/CTR/... NoPadding/PKCS5Padding/PKCS7Padding/...
IDEA 128 ECB PKCS5Padding/PKCS7Padding/...
  • AES算法ECB模式
import java.security.*;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message: " + message);
        // 128位密钥 = 16 bytes Key:
        byte[] key = "1234567890abcdef".getBytes("UTF-8");
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
    }

    // 加密:
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        return cipher.doFinal(input);
    }

    // 解密:
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKey keySpec = new SecretKeySpec(key, "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);
        return cipher.doFinal(input);
    }
}
# 控制台
Message: Hello, world!
Encrypted: 2xiGROlFBhC57b7EGu5c3g==
Decrypted: Hello, world!
  • AES算法CBC模式
# ECB模式是最简单的AES加密模式,它只需要一个固定长度的密钥,固定的明文会生成固定的密文,这种一对一的加密方式会导致安全性降低
# 更好的方式是通过CBC模式,它需要一个随机数作为IV参数,这样对于同一份明文,每次生成的密文都不同

import java.security.*;
import java.util.Base64;
import javax.crypto.*;
import javax.crypto.spec.*;

public class Main {
    public static void main(String[] args) throws Exception {
        // 原文:
        String message = "Hello, world!";
        System.out.println("Message: " + message);
        // 256位密钥 = 32 bytes Key:
        byte[] key = "1234567890abcdef1234567890abcdef".getBytes("UTF-8");
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(key, data);
        System.out.println("Encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(key, encrypted);
        System.out.println("Decrypted: " + new String(decrypted, "UTF-8"));
    }

    // 加密:
    public static byte[] encrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        // CBC模式需要生成一个16 bytes的initialization vector:
        SecureRandom sr = SecureRandom.getInstanceStrong();
        byte[] iv = sr.generateSeed(16);
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivps);
        byte[] data = cipher.doFinal(input);
        // IV不需要保密,把IV和密文一起返回:
        return join(iv, data);
    }

    // 解密:
    public static byte[] decrypt(byte[] key, byte[] input) throws GeneralSecurityException {
        // 把input分割成IV和密文:
        byte[] iv = new byte[16];
        byte[] data = new byte[input.length - 16];
        System.arraycopy(input, 0, iv, 0, 16);
        System.arraycopy(input, 16, data, 0, data.length);
        // 解密:
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
        IvParameterSpec ivps = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, keySpec, ivps);
        return cipher.doFinal(data);
    }

    public static byte[] join(byte[] bs1, byte[] bs2) {
        byte[] r = new byte[bs1.length + bs2.length];
        System.arraycopy(bs1, 0, r, 0, bs1.length);
        System.arraycopy(bs2, 0, r, bs1.length, bs2.length);
        return r;
    }
}
# 控制台
Message: Hello, world!
Encrypted: YPMN+yr8fMTmutXZC0HkMPiT3+p1SiAWUwmnUBPaOhg=
Decrypted: Hello, world!
  • 口令加密算法
# PBE的作用就是把用户输入的口令和一个安全随机的口令采用杂凑后计算出真正的密钥
# 以AES密钥为例,我们让用户输入一个口令,然后生成一个随机数,通过PBE算法计算出真正的AES口令,再进行加密

public class Main {
    public static void main(String[] args) throws Exception {
        // 把BouncyCastle作为Provider添加到java.security:
        Security.addProvider(new BouncyCastleProvider());
        // 原文:
        String message = "Hello, world!";
        // 加密口令:
        String password = "hello12345";
        // 16 bytes随机Salt:
        byte[] salt = SecureRandom.getInstanceStrong().generateSeed(16);
        System.out.printf("salt: %032x\n", new BigInteger(1, salt));
        // 加密:
        byte[] data = message.getBytes("UTF-8");
        byte[] encrypted = encrypt(password, salt, data);
        System.out.println("encrypted: " + Base64.getEncoder().encodeToString(encrypted));
        // 解密:
        byte[] decrypted = decrypt(password, salt, encrypted);
        System.out.println("decrypted: " + new String(decrypted, "UTF-8"));
    }

    // 加密:
    public static byte[] encrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey skey = skeyFactory.generateSecret(keySpec);
        PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.ENCRYPT_MODE, skey, pbeps);
        return cipher.doFinal(input);
    }

    // 解密:
    public static byte[] decrypt(String password, byte[] salt, byte[] input) throws GeneralSecurityException {
        PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory skeyFactory = SecretKeyFactory.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        SecretKey skey = skeyFactory.generateSecret(keySpec);
        PBEParameterSpec pbeps = new PBEParameterSpec(salt, 1000);
        Cipher cipher = Cipher.getInstance("PBEwithSHA1and128bitAES-CBC-BC");
        cipher.init(Cipher.DECRYPT_MODE, skey, pbeps);
        return cipher.doFinal(input);
    }
}
# 控制台
salt: 5b30333ac3430c154d3599d65b21ba88
encrypted: 72w120W+7GdCGRWJByZ5Xw==
decrypted: Hello, world!
  • 案例一
public class EncodingUtil {

    //AES加密
    private static final String KEY = "yflyyflyyflyyfly";

    /**
     * 接收一个字符串,用md5加密
     */
    public static byte[] md5Encoding(String str) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(str.getBytes());
            return digest;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 接收手机号和密码,用md5加密
     */
    public static String psdEncoding(String password, String phone) {
        byte[] md5Encoding = md5Encoding(password+phone);
        return new BigInteger(md5Encoding).toString(16);
    }

    /**
     * 接收字符串,AES加密
     */
    public static String aesEncoding(String msg) {
        if(msg == null) {
            throw new RuntimeException("加密字符串不能为空");
        }
        try {
            Cipher cipher = Cipher.getInstance("AES");//根据算法名称/工作模式/填充模式获取Cipher实例
            Key key = new SecretKeySpec(KEY.getBytes(), "AES");//根据算法名称初始化一个SecretKey实例,密钥必须是指定长度;
            cipher.init(Cipher.ENCRYPT_MODE, key);//使用SerectKey初始化Cipher实例,并设置加密或解密模式;
            byte[] endata = cipher.doFinal(msg.getBytes());//传入明文或密文,获得密文或明文
            return Base64.getEncoder().encodeToString(endata);//最后使用base64加密,返回字符串
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("加密失败");
        }
    }

    /**
     * AES解密
     * 接收base64加密后的字符串
     * 先base64解密
     * 再AES解密
     */
    public static String aesDeCoding(String bs64Str) {
        if(bs64Str == null) {
            throw new RuntimeException("解密字符串不能为空");
        }
        try {
            Cipher cipher = Cipher.getInstance("AES");
            Key key = new SecretKeySpec(KEY.getBytes(), "AES");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] code = Base64.getDecoder().decode(bs64Str);
            byte[] dedata = cipher.doFinal(code);
            return new String(dedata);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("加密失败");
        }
    }

}
posted @ 2022-05-07 19:39  DogLeftover  阅读(130)  评论(0编辑  收藏  举报