盘点Java常见的五种加密算法
  19qMgiCiiRfc 2023年11月02日 68 0

我们在日常开发中需要对一些数据进行加密存储,比如密码不能明文存储需要加密进行存储。还有前后端之间的数据传输我们也需要对后端返回的数据进行加密传输给前端,前端进行解密获取数据。

一、加密算法分类

加密算法整体上可以分为不可逆加密和可逆加密。可逆加密又可以分为对称加密和非对称加密。

不可逆加密算法

可逆加密算法

MD5,HMAC,SHA1,SHA-224,SHA-256

DES(对称加密),AES(对称加密),RSA(非对称加密)

不可逆加密算法说不可逆的,密文无法被还原成原文,散列算法就是一种不可逆算法,散列算法中,明文通过散列算法生成散列值,散列值是长度固定的数据和明文长度无关。散列算法常用于数字签名、消息认证、密码存储等场景。

可逆加密算法,使用同一个密钥进行加密和解密。可逆算法也可以分为对称加密算法和非对称算法。非对称加密算法需要两个密钥,这两个密钥互不相同,但是相互匹配,一个称为公钥,另一个称为私钥。对称加密算法使用同一个密钥进行加密和解密。

二、MD5

MD5,全称为“Message-Digest Algorithm 5”,翻译过来叫“信息摘要算法”。它可以将任意长度的数据通过散列算法,生成一个固定长度的散列值。MD5算法的输出长度为128位,通常用32个16进制数表示。

代码示例如下所示:

package day02;

import java.security.MessageDigest;
import java.util.Formatter;

/**
 * @author qx
 * @date 2023/9/19
 * @des MD5加密算法
 */
public class MD5Test {
    // 加密算法
    private static final String MD5_ALGORITHM = "MD5";

    /**
     * MD5加密算法
     *
     * @param data 要加密的明文
     * @return 加密后的密文
     * @throws Exception
     */
    public static String encrypt(String data) throws Exception {
        // 获取MD5算法实例
        MessageDigest messageDigest = MessageDigest.getInstance(MD5_ALGORITHM);
        // 计算散列值
        byte[] digest = messageDigest.digest(data.getBytes());
        Formatter formatter = new Formatter();
        for (byte b : digest) {
            formatter.format("%02x", b);
        }
        return formatter.toString();
    }

    public static void main(String[] args) throws Exception {
        String data = "hello";
        String encryptData = encrypt(data);
        System.out.println("加密后的数据为:" + encryptData);

    }
}

输出:

加密后的数据为:5d41402abc4b2a76b9719d911017c592

MD5有一些优点,比如计算速度快、输出长度固定、应用广泛等等。

但是MD5作为一个加密算法有个缺点就是不太安全,现在的MD5算法已经被攻破,输出的长度有限,攻击者可以通过暴力破解或彩虹攻击等方式,找到与原始数据相同的散列值,从而破解数据。

三、SHA-256

SHA(Secure Hash Algorithm)系列算法是一组密码散列函数,用于将任意长度的数据映射为固定长度的散列值。SHA系列算法由美国国家安全局(NSA)于1993年设计,目前共有SHA-1、SHA-2、SHA-3三种版本。

其中SHA-1系列存在缺陷,已经不再被推荐使用。

SHA-2算法包括SHA-224、SHA-256、SHA-384和SHA-512四种散列函数,分别将任意长度的数据映射为224位、256位、384位和512位的散列值。

我们来看一下最常用的SHA-256的Java代码实现:

package day02;

import java.security.MessageDigest;

/**
 * @author qx
 * @date 2023/9/19
 * @des SHA256加密算法
 */
public class SHA256Test {
    private static final String SHA_256_ALGORITHM = "SHA-256";

    /**
     * SHA-256加密算法
     *
     * @param data 要加密的明文
     * @return 加密后的密文
     * @throws Exception
     */
    public static String encrypt(String data) throws Exception {
        //获取SHA-256算法实例
        MessageDigest messageDigest = MessageDigest.getInstance(SHA_256_ALGORITHM);
        //计算散列值
        byte[] digest = messageDigest.digest(data.getBytes());
        StringBuilder stringBuilder = new StringBuilder();
        for (byte b : digest) {
            stringBuilder.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
        }
        return stringBuilder.toString();
    }

    public static void main(String[] args) throws Exception {
        String data = "hello";
        String encryptData = encrypt(data);
        System.out.println("加密后的数据为:" + encryptData);
    }
}

输出:

加密后的数据为:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

SHA-2算法之所以比MD5强,主要有两个原因:

散列值长度更长:例如SHA-256算法的散列值长度是256位,而MD5算法的散列值长度是128位,这就提高了攻击者暴力破解或彩虹表攻击的难度。

更强的碰撞抗性:SHA算法采用了更复杂的运算过程和更多的轮次,使得攻击者更难以通过预计算或巧合找到碰撞。

当然,SHA-2也不是绝对安全的,散列算法都有被暴力破解或者彩虹表攻击的风险,所以,在实际的应用中,加盐还是必不可少的。

四、DES

DES算法是一种对称加密算法,使用56位密钥对数据进行加密,加密过程中使用了置换、替换、异或等运算,具有较高的安全性。

代码示例如下所示:

package day02;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.spec.KeySpec;
import java.util.Base64;

/**
 * @author qx
 * @date 2023/9/19
 * @des DES加密算法
 */
public class DESTest {
    private static final String DES_ALGORITHM = "DES";

    /**
     * DES加密
     *
     * @param data 要加密的明文数据
     * @param key  密钥,长度必须为8位
     * @return 加密后的密文数据
     * @throws Exception
     */
    public static String encrypt(String data, String key) throws Exception {
        // 根据密钥生成密钥规范
        KeySpec keySpec = new DESKeySpec(key.getBytes());
        // 根据密钥规范生成密钥工厂
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
        // 根据密钥工厂和密钥规范生成密钥
        SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);

        // 根据加密算法获取加密器
        Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
        // 初始化加密器,设置加密模式和密钥
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        // 加密数据
        byte[] encryptedData = cipher.doFinal(data.getBytes());
        // 对加密后的数据进行Base64编码
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * DES解密
     *
     * @param encryptedData 加密后的密文数据
     * @param key           密钥,长度必须为8位
     * @return 解密后的数据
     * @throws Exception
     */
    public static String decrypt(String encryptedData, String key) throws Exception {
        // 根据密钥生成密钥规范
        KeySpec keySpec = new DESKeySpec(key.getBytes());
        // 根据密钥规范生成密钥工厂
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
        // 根据密钥工厂和密钥规范生成密钥
        SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);

        // 对加密后的数据进行Base64解码
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);
        // 根据加密算法获取解密器
        Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
        // 初始化解密器,设置解密模式和密钥
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        // 解密数据
        byte[] decryptedData = cipher.doFinal(decodedData);
        // 将解密后的数据转换为字符串
        return new String(decryptedData);
    }

    public static void main(String[] args) throws Exception {
        // 8位长度密钥
        String key = "abcdefgh";
        // 待加密的数据
        String data = "hello";

        String encryptData = encrypt(data, key);
        System.out.println("加密后的数据为:" + encryptData);

        String decryptData = decrypt(encryptData, key);
        System.out.println("解密后的数据为:" + decryptData);
    }
}

输出:

加密后的数据为:SPjdrAgKBpg=
解密后的数据为:hello

DES的算法速度较快,但是在安全性上面并不是最优选择,因为DES算法的密钥长度比较短,被暴力破解和差分攻击的风险比较高,一般推荐用一些更安全的对称加密算法,比如3DES、AES。

五、AES

AES(Advanced Encryption Standard)即高级加密标准,是一种对称加密算法,被广泛应用于数据加密和保护领域。AES算法使用的密钥长度为128位、192位或256位,比DES算法的密钥长度更长,安全性更高。

代码示例如下所示:

package day02;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author qx
 * @date 2023/9/19
 * @des AES加密算法
 */
public class AESTest {
    private static final String AES_ALGORITHM = "AES";
    // AES加密模式为CBC,填充方式为PKCS5Padding
    private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
    // AES密钥为16位
    private static final String AES_KEY = "1234567890123456";
    // AES初始化向量为16位
    private static final String AES_IV = "abcdefghijklmnop";

    /**
     * AES加密
     *
     * @param data 待加密的明文数据
     * @return 加密后的密文数据
     * @throws Exception
     */
    public static String encrypt(String data) throws Exception {
        // 将AES密钥转换为SecretKeySpec对象
        SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
        // 将AES初始化向量转换为IvParameterSpec对象
        IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
        // 根据加密算法获取加密器
        Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
        // 初始化加密器,设置加密模式、密钥和初始化向量
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        // 加密数据
        byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        // 对加密后的数据使用Base64编码
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * AES解密
     *
     * @param encryptedData 加密后的密文数据
     * @return 解密后的明文数据
     * @throws Exception
     */
    public static String decrypt(String encryptedData) throws Exception {
        // 将AES密钥转换为SecretKeySpec对象
        SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
        // 将AES初始化向量转换为IvParameterSpec对象
        IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
        // 根据加密算法获取解密器
        Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
        // 初始化解密器,设置解密模式、密钥和初始化向量
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
        // 对加密后的数据使用Base64解码
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);
        // 解密数据
        byte[] decryptedData = cipher.doFinal(decodedData);
        // 返回解密后的数据
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) throws Exception {
        String data = "hello";
        String encryptedData = encrypt(data);
        System.out.println("加密后的数据:" + encryptedData);

        String decryptedData = decrypt(encryptedData);
        System.out.println("解密后的数据:" + decryptedData);
    }
}

输出:

加密后的数据:ZM6V+N4TrIblhrpN+FfkYw==
解密后的数据:hello

AES算法采用的密钥长度更长,密钥空间更大,安全性更高,能够有效地抵抗暴力破解攻击。

当然,因为密钥长度较长,需要的存储也更多。

对于对称加密算法而言,最大的痛点就在于密钥管理困难,相比而言,非对称加密就没有这个担忧。

六、RSA

RSA算法是是目前应用最广泛的非对称加密算法。

代码示例如下所示:

package day02;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

/**
 * @author qx
 * @date 2023/9/19
 * @des RSA加密算法
 */
public class RSATest {
    private static final String RSA_ALGORITHM = "RSA";

    /**
     * 生成RSA密钥(包含公钥和私钥)
     *
     * @return RSA密钥对
     * @throws NoSuchAlgorithmException
     */
    public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        keyPairGenerator.initialize(2048);
        return keyPairGenerator.generateKeyPair();
    }

    /**
     * 使用公钥加密数据
     *
     * @param data      待加密的数据
     * @param publicKey 公钥
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return Base64.getEncoder().encodeToString(encryptedData);
    }

    /**
     * 使用私钥解密数据
     *
     * @param encryptedData 加密后的数据
     * @param privateKey    私钥
     * @return 解密后的数据
     * @throws Exception
     */
    public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
        byte[] decodedData = Base64.getDecoder().decode(encryptedData);
        Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] decryptedData = cipher.doFinal(decodedData);
        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) throws Exception {
        KeyPair keyPair = generateKeyPair();
        // 公钥
        PublicKey publicKey = keyPair.getPublic();
        // 私钥
        PrivateKey privateKey = keyPair.getPrivate();

        String data = "Hello";

        String encryptedData = encrypt(data, publicKey);
        System.out.println("加密后的数据:" + encryptedData);

        String decryptedData = decrypt(encryptedData, privateKey);
        System.out.println("解密后的数据:" + decryptedData);
    }
}

输出:

加密后的数据:U3NbgKOhvcWQHyOYs0TeF22+Lcocxe1Qtp1DifD8h0HgXP/C96pEjKbmQPlBd31eHb/A/Xk56T9xMWOJBrheK3MS1cukTZixCF3GNQGLTZzZ8CxFL4mXwkZhvCSy2mCOB19y1dZxCbCBu65aEDMBayO7pyRPWZgZSeSNTvxofRKC41TkxQgOzXMMwZNbtZdnwf2bEbkiiRiPVi1VbQZWu4kGxfrxrL1ZPTax1oDsavNsuwMXS1aB4hATfrj7j8QXEnfepvrMn+ljFluKyAbMBBZUuwalIVjKEn1Xjk+I0hNFo572tubNjmhrsIt5NoSBe2W4djE4luc3thWdjcRA+g==
解密后的数据:Hello

RSA算法的优点是安全性高,公钥可以公开,私钥必须保密,保证了数据的安全性;可用于数字签名、密钥协商等多种应用场景。

缺点是加密、解密速度较慢,密钥长度越长,加密、解密时间越长;密钥长度过短容易被暴力破解,密钥长度过长则会增加计算量和存储空间的开销。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
19qMgiCiiRfc