java常用加密算法

参考文章

CRC、MD5、SHA1 有何区别?

Java实现AES加密

常用算法

java常用加密算法

AES

高级加密标准(AES,Advanced Encryption Standard)为最常见的对称加密算法(微信小程序加密传输就是用这个加密算法的)。对称加密算法也就是加密和解密用相同的密钥,具体的加密流程如下图:
java常用加密算法
代码

package com.qzn.demo.utils;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

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.SecureRandom;
import java.util.Scanner;

/**
 * AES对称加密和解密
 */
public class SecurityAESUtil {
    private SecurityAESUtil() {
    }

    /**
     * 加密
     * 1.构造密钥生成器
     * 2.根据ecnodeRules规则初始化密钥生成器
     * 3.产生密钥
     * 4.创建和初始化密码器
     * 5.内容加密
     * 6.返回字符串
     *
     * @param encodeRules 密钥
     * @param content     明文
     */
    public static String encode(String encodeRules, String content) {
        try {
            Cipher cipher = generateCipher(encodeRules, Cipher.ENCRYPT_MODE);
            //8.获取加密内容的字节数组(这里要设置为utf-8)不然内容中如果有中文和英文混合中文就会解密为乱码
            byte[] byteEncode = content.getBytes(StandardCharsets.UTF_8);
            //9.根据密码器的初始化方式--加密:将数据加密
            byte[] byteAES = cipher.doFinal(byteEncode);
            //10.将加密后的数据转换为字符串
            return new BASE64Encoder().encode(byteAES);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 创建密码器
     *
     * @param encodeRules 密钥
     * @param mode        加密/解密模式: 加密 Cipher.ENCRYPT_MODE,解密 Cipher.DECRYPT_MODE
     */
    private static Cipher generateCipher(String encodeRules, Integer mode) {
        try {
            //1.构造密钥生成器,指定为AES算法,不区分大小写
            KeyGenerator keygen = KeyGenerator.getInstance("AES");
            //2.根据ecnodeRules规则初始化密钥生成器生成一个128位的随机源,根据传入的字节数组
            keygen.init(128, new SecureRandom(encodeRules.getBytes()));
            //3.产生原始对称密钥
            SecretKey originalKey = keygen.generateKey();
            //4.获得原始对称密钥的字节数组
            byte[] raw = originalKey.getEncoded();
            //5.根据字节数组生成AES密钥
            SecretKey key = new SecretKeySpec(raw, "AES");
            //6.根据指定算法AES自成密码器
            Cipher cipher = Cipher.getInstance("AES");
            //7.初始化密码器,第一个参数为加密(Encrypt_mode)或者解密解密(Decrypt_mode)操作,第二个参数为使用的KEY
            cipher.init(mode, key);
            return cipher;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 解密
     * 1.同加密1-4步
     * 2.将加密后的字符串反纺成byte[]数组
     * 3.将加密内容解密
     *
     * @param encodeRules 密钥
     * @param content     密文
     */
    public static String decode(String encodeRules, String content) {
        try {

            Cipher cipher = generateCipher(encodeRules, Cipher.DECRYPT_MODE);
            //8.将加密并编码后的内容解码成字节数组
            byte[] byteContent = new BASE64Decoder().decodeBuffer(content);
            //9.解密
            byte[] byteDecode = cipher.doFinal(byteContent);
            return new String(byteDecode, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        /*
         * 加密
         */
        System.out.println("使用AES对称加密,请输入加密的规则");
        String encodeRules = scanner.next();
        System.out.println("请输入要加密的内容:");
        String content = scanner.next();
        String encodeContent = SecurityAESUtil.encode(encodeRules, content);
        System.out.println("根据输入的规则" + encodeRules + "加密后的密文是:" + encodeContent);

        /*
         * 解密
         */
        System.out.println("使用AES对称解密,请输入加密的规则:(须与加密相同)");
        encodeRules = scanner.next();
        System.out.println("根据输入的规则" + encodeRules + "解密后的明文是:" + SecurityAESUtil.decode(encodeRules, encodeContent));
    }
}

运行结果:

加密解密的密钥相等,如下:
java常用加密算法
加密解密的密钥不相等,如下:
java常用加密算法

RSA

RSA 加密算法是一种典型的非对称加密算法,它基于大数的因式分解数学难题,它也是应用最广泛的非对称加密算法。非对称加密是通过两个密钥(公钥-私钥)来实现对数据的加密和解密的。公钥用于加密,私钥用于解密

java常用加密算法

java常用加密算法
代码

package com.qzn.demo.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;

import javax.crypto.Cipher;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA 非对称加密
 */
@Slf4j
public class SecurityRsaUtil {
    /**
     * 公钥文件路径
     */
    private static final String publicKeyFile = "D:/datas/temp/a/public_key.pem";
    /**
     * 私钥文件路径
     */
    private static final String privateKeyFile = "D:/datas/temp/a/private_key.pem";


    /**
     * 随机生成密钥对。公钥发给别人,私钥秘密保留。
     */
    public static void genKeyPair() {
        try {
            // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            // 初始化密钥对生成器,密钥大小为96-1024位
            keyPairGen.initialize(1024, new SecureRandom());
            // 生成一个密钥对,保存在keyPair中
            KeyPair keyPair = keyPairGen.generateKeyPair();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();   // 得到私钥
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();  // 得到公钥

            String publicKeyString = new String(Base64.encodeBase64(publicKey.getEncoded()));
            String privateKeyString = new String(Base64.encodeBase64((privateKey.getEncoded())));

            IOUtils.write(publicKeyString, new FileOutputStream(publicKeyFile), StandardCharsets.UTF_8);
            IOUtils.write(privateKeyString, new FileOutputStream(privateKeyFile), StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 加密
     *
     * @param text 明文
     * @return 密文
     */
    public static String encrypt(String text) {
        try {
            String publicKeyContent = IOUtils.toString(new FileInputStream(publicKeyFile), StandardCharsets.UTF_8);
            byte[] publicKeyByte = Base64.decodeBase64(publicKeyContent);

            X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyByte);
            KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
            PublicKey publicKey = rsaKeyFactory.generatePublic(x509KeySpec);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] clear = text.getBytes(StandardCharsets.UTF_8);
            byte[] encrypted = cipher.doFinal(clear);
            return Base64.encodeBase64String(encrypted);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * 解密
     *
     * @param text 密文
     * @return 明文
     */
    public static String decrypt(String text) {
        try {
            String privateKeyContent = IOUtils.toString(new FileInputStream(privateKeyFile), "UTF-8");

            byte[] privateKeyByte = Base64.decodeBase64(privateKeyContent);

            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyByte);
            KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
            PrivateKey privateKey = rsaKeyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] encrypted = Base64.decodeBase64(text);
            byte[] decrypted = cipher.doFinal(encrypted);
            return new String(decrypted, StandardCharsets.UTF_8);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }

    }

    public static void main(String[] args) {
        //产生公钥私钥
//        genKeyPair();

        String password = "hello@world@123";
        System.out.println("加密前的明文=" + password);

        String encode1 = SecurityRsaUtil.encrypt(password);
        System.out.println("第一次加密后的密文=" + encode1);

        String encode2 = SecurityRsaUtil.encrypt(password);
        System.out.println("第二次加密后的密文=" + encode2);

        String decode1 = SecurityRsaUtil.decrypt(encode1);
        System.out.println("解密第一次的密文=" + decode1);

        String decode2 = SecurityRsaUtil.decrypt(encode2);
        System.out.println("解密第二次的密文=" + decode2);

    }
}

运行:genKeyPair(); 可以得到公钥文件: private_key.pem,私钥文件:public_key.pem 。如下。把公钥给客户,私钥保留。
java常用加密算法
运行上面的代码结果如下:
java常用加密算法
可以看到RSA每次用公钥加密后的密文是不一样的。但每次解密的结果是一样的。

RSA 速度慢,只对少量数据加密。ASE 速度快,可以加密较大的数据。所以对大数据的时候ASE RSA混合使用。思路如下;

1,随机生成一个字符串,如UUID 。作为AES 的秘钥secretKey 。
2,对大数据用ASE加密,秘钥secretKey(因为ASE效率快),得到密文 secretData
3,通过RSA用公钥对秘钥secretKey加密,得到 secretKey2
4,把secretData,secretKey2,都传给服务端(都是密文,很安全)
5,服务端通过RSA用私钥解密secretKey2得到secretKey
6,服务端通过AES用秘钥secretKey对secretData解密,得到真实数据

CRC、MD5、SHA1

相同点

CRC、MD5、SHA1都是通过对数据进行计算,来生成一个校验值,该校验值用来校验数据的完整性。具有不可逆,压缩性

不同点

名称 算法 校验值长度 校验值称呼 安全性 效率
CRC 多项式除法 4位 CRC值 一般 最高
MD5 替换、轮转等方法 32位 哈希值(Hash) 较高 一般
SHA1 替换、轮转等方法 40位 哈希值(Hash) 最高 一般

安全性:这里的安全性是指检错的能力,即数据的错误能通过校验位检测出来。CRC的安全性跟多项式有很大关系,相对于MD5和SHA1要弱很多;MD5的安全性很高,不过大概在04年的时候被山东大学的王小云破解了;SHA1的安全性最高。

用途:CRC的效率最高,不常用,一般用作通信数据的校验。D5和SHA1用于安全(Security)领域,比如文件校验、数字签名等

代码:

package com.qzn.demo.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
//import org.springframework.util.DigestUtils;

/**
 * MD5、SHA1都是通过对数据进行计算,来生成一个校验值,该校验值用来校验数据的完整性。具有不可逆,压缩性
 */
@Slf4j
public class SecurityUtil {
    /**
     * 盐,用于混交
     */
    private static final String slat = "&%5123***&&%%$$#@";

    private SecurityUtil() {
    }

    /**
     * MD5
     *
     * @param data 数据
     */
    public static String getMD5(String data) {
        String base = data + "/" + slat;
        return DigestUtils.md5Hex(base);
    }

    /**
     * CRC
     *
     * @param data 数据
     */
    public static String getSHA1(String data) {
        String base = data + "/" + slat;
        return DigestUtils.sha1Hex(base);
    }

    public static void main(String[] args) {
        String password = "hello@world@123123";
        System.out.println("原数据=" + password);
        String md5 = SecurityUtil.getMD5(password);
        System.out.println("md5加密后=" + md5 + " ,位数=" + md5.length());
        String sha1 = SecurityUtil.getSHA1(password);
        System.out.println("sha1加密后=" + sha1 + " ,位数=" + sha1.length());
    }
}

运行结果:
java常用加密算法

上一篇:安全架构-加密算法-3DES加密java实现


下一篇:古典密码-博福特密码Beaufort