麻花痒 发表于 2024-11-6 19:44:22

【利用 Commons Codec 实现 MD5、RSA、AES 加密】

一、MD5 加密算法

1. 什么是 MD5?

MD5(Message Digest Algorithm 5)是一种广泛利用的哈希函数,由 Ronald Rivest 在 1991 年计划。它的主要用途是将恣意长度的输入数据(称为消息)转换为固定长度的散列值(称为消息摘要)。MD5 生成的摘要长度为 128 位,即 16 字节。由于其生成的散列值长度固定,即使输入数据发生微小变化,输出也会明显变化,这使得 MD5 适用于数据完备性校验,如文件校验和、密码加密(虽然不推荐用于密码存储)等。
MD5 的主要特点包括:


[*]固定输出长度:无论输入数据大小怎样,输出的摘要长度都是 128 位。
[*]不可逆性:从散列值不能反推出原始数据。
[*]强抗碰撞性:理论上不应出现差异的输入生成雷同的散列值(然而实际中已被破解)。
2. 利用 Commons Codec 实现 MD5

import org.apache.commons.codec.digest.DigestUtils;

import java.io.UnsupportedEncodingException;

/**
* MD5加密工具类
* MD5,全称为“Message-Digest Algorithm 5”,中文名“消息摘要算法5”,是一种单向加密算法。
* 加密特点:1.不可逆;2.不可还原;3.相同内容加密后的结果相同;4.不同内容加密后的结果不同。
* 应用场景:1.密码加密;2.文件完整性校验;3.数字签名。
* 步骤:1.初始化MD5;2.更新MD5;3.计算MD5;4.输出MD5。
* 优点:1.压缩性;2.容易计算;3.抗修改性;4.强抗碰撞。
* 缺点:1.不可逆;2.碰撞攻击。
* 安全性:1.碰撞攻击;2.彩虹表攻击。
*/
public abstract class MD5Util {
        /**
       * 对content进行MD5加密
       * @param content需要加密的内容
       * @param salt   盐值
       * @param charset字符编码
       * @return加密后的内容
       */
        public static String sign(String content, String salt, String charset) {
                content = content + salt;
                return DigestUtils.md5Hex(getContentBytes(content, charset));// 使用MD5加密算法对content进行加密
        }

        /**
       * 验证签名
       * @param content需要加密的内容
       * @param sign签名
       * @param salt盐值
       * @param charset字符编码
       * @return是否验证通过
       */
        public static boolean verify(String content, String sign, String salt, String charset) {
                content = content + salt;
                String mySign = DigestUtils.md5Hex(getContentBytes(content, charset));// 使用MD5加密算法对content进行加密
                return mySign.equals(sign);// 判断mySign和sign是否相等
        }

        /**
       * 将content转换为字节数组
       * @param content需要转换的内容
       * @param charset字符编码
       * @return字节数组
       */
        private static byte[] getContentBytes(String content, String charset) {
                if (charset == null || "".equals(charset)) {
                        return content.getBytes();
                }
                try {
                        return content.getBytes(charset);
                } catch (UnsupportedEncodingException e) {
                        throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);
                }
        }

        public static void main(String[] args) {
                String content = "123456";// 需要加密的内容
                String salt = "abc";// 盐值
                String charset = "utf-8";// 字符编码
                String sign = sign(content, salt, charset);// 对content进行MD5加密,并返回加密后的内容
                System.out.println("加密后的内容: " + sign);// 输出加密后的内容
                boolean verify = verify(content, sign, salt, charset);// 验证签名
                System.out.println("验证签名: " + verify);// 输出验证签名
        }
}

3. 注意事项

MD5 算法不适用于安全性要求高的场景,由于其存在碰撞漏洞和被暴力破解的风险。
二、RSA 加密算法

1. 什么是 RSA?

RSA 是一种非对称加密算法,由 Ron Rivest、Adi Shamir 和 Leonard Adleman 于 1977 年提出。RSA 算法基于大整数因数分解的数学困难,其安全性依赖于大数分解的困难性。与对称加密差异,RSA 利用一对密钥:公钥和私钥。公钥用于加密数据,私钥用于解密数据。RSA 可以用于加密和数字签名,其广泛应用于 SSL/TLS 协议、电子邮件加密和数字签名等领域。
RSA 的主要特点包括:


[*]非对称性:加密和解密利用差异的密钥,公钥公开,私钥保密。
[*]数据加密和签名:可以用于加密数据和生成数字签名。
[*]安全性:基于大数分解题目的困难性,现在没有有用的快速分解大数的方法。
尽管 RSA 安全性较高,但其加密速率较慢,不得当加密大数据量。在实际应用中,通常结合对称加密算法,如 AES,来加密数据内容,而 RSA 用于加密对称密钥。
2. 利用 Commons Codec 实现 RSA

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;


/**
* RSA加密解密工具类
* RSA,全称为“Rivest-Shamir-Adleman”,中文名“RSA算法”,是一种非对称加密算法。
* RSA加密解密的过程中,密钥长度越长,加密强度越大,但是加密解密速度越慢。
* 加密特点:1.公钥加密,私钥解密;2.私钥签名,公钥验签;3.加密解密速度慢;4.适合对少量数据进行加密解密。
* 应用场景:1.数字签名;2.加密解密;3.密钥协商。
* 步骤:1.生成密钥对;2.加密;3.解密;4.签名;5.验签。
* 优点:1.安全性高;2.密钥管理方便。
* 缺点:1.加密解密速度慢;2.适合对少量数据进行加密解密。
* 安全性:1.公钥加密,私钥解密;2.私钥签名,公钥验签。
*/
public class RSAUtil {
    /**
   * RSA最大加密明文大小
   */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
   * RSA最大解密密文大小
   */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /**
   * 获取密钥对
   * @return 密钥对
   */
    public static KeyPair getKeyPair() throws Exception {
      // 获取密钥对生成器,指定算法为RSA
      KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
      // 设置密钥长度为1024位
      generator.initialize(1024);
      return generator.generateKeyPair();// 生成密钥对
    }

    /**
   * 获取私钥
   * @param privateKey 私钥字符串
   * @return 私钥
   */
    public static PrivateKey getPrivateKey(String privateKey) throws Exception {
      // 获取密钥工厂,指定算法为RSA
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      // 使用base64解码私钥字符串
      byte[] decodedKey = Base64.decodeBase64(privateKey.getBytes());
      // 获取私钥对象
      PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decodedKey);
      return keyFactory.generatePrivate(keySpec); // 生成私钥
    }

    /**
   * 获取公钥
   * @param publicKey 公钥字符串
   * @return 公钥
   */
    public static PublicKey getPublicKey(String publicKey) throws Exception {
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      byte[] decodedKey = Base64.decodeBase64(publicKey.getBytes());
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(decodedKey);
      return keyFactory.generatePublic(keySpec);
    }

    /**
   * RSA加密
   * @param data      待加密数据
   * @param publicKey 公钥
   * @return 加密后的数据
   */
    public static String encrypt(String data, PublicKey publicKey) throws Exception {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.ENCRYPT_MODE, publicKey);
      int inputLen = data.getBytes().length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offset = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段加密
      while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_ENCRYPT_BLOCK) {
                cache = cipher.doFinal(data.getBytes(), offset, MAX_ENCRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(data.getBytes(), offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_ENCRYPT_BLOCK;
      }
      byte[] encryptedData = out.toByteArray();
      out.close();
      // 获取加密内容使用base64进行编码,并以UTF-8为标准转化成字符串
      // 加密后的字符串
      return new String(Base64.encodeBase64String(encryptedData));
    }

    /**
   * RSA解密
   * @param data       待解密数据
   * @param privateKey 私钥
   * @return 解密后的数据
   */
    public static String decrypt(String data, PrivateKey privateKey) throws Exception {
      Cipher cipher = Cipher.getInstance("RSA");
      cipher.init(Cipher.DECRYPT_MODE, privateKey);
      byte[] dataBytes = Base64.decodeBase64(data);
      int inputLen = dataBytes.length;
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int offset = 0;
      byte[] cache;
      int i = 0;
      // 对数据分段解密
      while (inputLen - offset > 0) {
            if (inputLen - offset > MAX_DECRYPT_BLOCK) {
                cache = cipher.doFinal(dataBytes, offset, MAX_DECRYPT_BLOCK);
            } else {
                cache = cipher.doFinal(dataBytes, offset, inputLen - offset);
            }
            out.write(cache, 0, cache.length);
            i++;
            offset = i * MAX_DECRYPT_BLOCK;
      }
      byte[] decryptedData = out.toByteArray();
      out.close();
      // 解密后的内容
      return new String(decryptedData, "UTF-8");
    }

    /**
   * 签名
   * @param data       待签名数据
   * @param privateKey 私钥
   * @return 签名
   */
    public static String sign(String data, PrivateKey privateKey) throws Exception {
      byte[] keyBytes = privateKey.getEncoded();
      PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      PrivateKey key = keyFactory.generatePrivate(keySpec);
      Signature signature = Signature.getInstance("MD5withRSA");
      signature.initSign(key);
      signature.update(data.getBytes());
      return new String(Base64.encodeBase64(signature.sign()));
    }

    /**
   * 验签
   * @param srcData   原始字符串
   * @param publicKey 公钥
   * @param sign      签名
   * @return 是否验签通过
   */
    public static boolean verify(String srcData, PublicKey publicKey, String sign) throws Exception {
      byte[] keyBytes = publicKey.getEncoded();
      X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
      KeyFactory keyFactory = KeyFactory.getInstance("RSA");
      PublicKey key = keyFactory.generatePublic(keySpec);
      Signature signature = Signature.getInstance("MD5withRSA");
      signature.initVerify(key);
      signature.update(srcData.getBytes());
      return signature.verify(Base64.decodeBase64(sign.getBytes()));
    }

    public static void main(String[] args) {
      try {
            // 生成密钥对,其中的公钥私钥是唯一对应的
            KeyPair keyPair = getKeyPair();
            String privateKey = new String(Base64.encodeBase64(keyPair.getPrivate().getEncoded()));
            String publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));
            System.out.println("私钥:" + privateKey);
            System.out.println("公钥:" + publicKey);
            // RSA加密
            String data = "test";
            String encryptData = encrypt(data, getPublicKey(publicKey));
            System.out.println("加密后内容:" + encryptData);
            // RSA解密
            String decryptData = decrypt(encryptData, getPrivateKey(privateKey));
            System.out.println("解密后内容:" + decryptData);
            // RSA签名
            String sign = sign(data, getPrivateKey(privateKey));
            // RSA验签
            boolean result = verify(data, getPublicKey(publicKey), sign);
            System.out.print("验签结果:" + result);
      } catch (Exception e) {
            e.printStackTrace();
            System.out.print("加解密异常");
      }
    }
}

3. 注意事项

RSA 加密算法适用于安全性要求高的场景,但运算速率较慢,得当加密较小数据量。
三、AES 加密算法

1. 什么是 AES?

AES(Advanced Encryption Standard)是美国国家尺度与技术研究院(NIST)于 2001 年发布的对称加密算法尺度,由比利时密码学家 Joan Daemen 和 Vincent Rijmen 计划。AES 是替换原有 DES(Data Encryption Standard)的新尺度,旨在提供更强的安全性和更高的效率。AES 支持多种密钥长度,包括 128 位、192 位和 256 位,密钥长度越长,安全性越高。
AES 的主要特点包括:


[*]对称加密:利用雷同的密钥举行加密和解密。
[*]块加密算法:AES 处理固定大小(128 位)的数据块。
[*]高安全性和效率:AES 被广泛认为是现在最安全和高效的对称加密算法之一,得当用于保护大数据量的传输。
AES 在很多领域得到广泛应用,包括 SSL/TLS 协议、无线安全(如 WPA2)、文件加密、虚拟专用网络(VPN)等。其高效的加密和解密性能使其成为现代数据安全的首选方案。
2. 利用 Commons Codec 实现 AES

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
* AES加密解密工具类
* AES,全称为“Advanced Encryption Standard”,中文名“高级加密标准”,是一种对称加密算法。
* AES加密解密的过程中,密钥长度越长,加密强度越大,但是加密解密速度越慢。
* 加密特点:1.密钥长度可变;2.加密解密速度快;3.适合对大量数据进行加密解密。
* 应用场景:1.文件加密;2.数据传输加密;3.数据库加密。
* 步骤:1.生成密钥;2.加密;3.解密。
* 优点:1.加密解密速度快;2.适合对大量数据进行加密解密。
* 缺点:1.密钥管理不方便;2.适合对大量数据进行加密解密。
* 安全性:1.密钥长度可变;2.加密解密速度快。
*/
public class AESUtil {

    private static final String KEY_AES = "AES";// 算法

    private static final int KEY_SIZE = 128;// 密钥长度(位)

    /**
   * 生成随机AES密钥
   *
   * @return 随机生成的AES密钥
   * @throws NoSuchAlgorithmException
   */
    public static String generateRandomKey() throws NoSuchAlgorithmException {
      KeyGenerator keyGen = KeyGenerator.getInstance(KEY_AES);
      keyGen.init(KEY_SIZE, new SecureRandom()); // AES密钥长度
      SecretKey secretKey = keyGen.generateKey();
      return byte2hex(secretKey.getEncoded());
    }

    /**
   * 加密
   *
   * @param src    需要加密的内容
   * @param keyHex 十六进制表示的加密密钥
   * @return 加密后的内容
   * @throws Exception
   */
    public static String encrypt(String src, String keyHex) throws Exception {
      if (isValidKey(keyHex)) {
            throw new Exception("key不满足条件");
      }
      byte[] raw = hex2byte(keyHex);
      SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_AES);
      Cipher cipher = Cipher.getInstance(KEY_AES);
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
      byte[] encrypted = cipher.doFinal(src.getBytes());
      return byte2hex(encrypted);
    }

    /**
   * 解密
   *
   * @param src    需要解密的内容
   * @param keyHex 十六进制表示的解密密钥
   * @return 解密后的内容
   * @throws Exception
   */
    public static String decrypt(String src, String keyHex) throws Exception {
      if (isValidKey(keyHex)) {
            throw new Exception("key不满足条件");
      }
      byte[] raw = hex2byte(keyHex);
      SecretKeySpec skeySpec = new SecretKeySpec(raw, KEY_AES);
      Cipher cipher = Cipher.getInstance(KEY_AES);
      cipher.init(Cipher.DECRYPT_MODE, skeySpec);
      byte[] encrypted1 = hex2byte(src);
      byte[] original = cipher.doFinal(encrypted1);
      return new String(original);
    }

    /**
   * 验证密钥是否有效
   *
   * @param keyHex 十六进制表示的密钥
   * @return 是否有效
   */
    private static boolean isValidKey(String keyHex) {
      return keyHex == null || keyHex.length() != (KEY_SIZE / 4);
    }

    /**
   * 将16进制转换为二进制
   *
   * @param strhex 16进制字符串
   * @return 二进制字节数组
   */
    public static byte[] hex2byte(String strhex) {
      if (strhex == null) {
            return null;
      }
      int l = strhex.length();
      if (l % 2 == 1) {
            return null;
      }
      byte[] b = new byte;
      for (int i = 0; i != l / 2; i++) {
            b = (byte) Integer.parseInt(strhex.substring(i * 2, i * 2 + 2), 16);
      }
      return b;
    }

    /**
   * 将二进制转换为16进制
   *
   * @param b 二进制字节数组
   * @return 16进制字符串
   */
    public static String byte2hex(byte[] b) {
      StringBuilder hs = new StringBuilder();
      String stmp;
      for (byte value : b) {
            stmp = Integer.toHexString(value & 0XFF);
            if (stmp.length() == 1) {
                hs.append("0").append(stmp);
            } else {
                hs.append(stmp);
            }
      }
      return hs.toString().toUpperCase();
    }

    public static void main(String[] args) {
      try {
            // 生成随机密钥
            String randomKey = generateRandomKey();
            System.out.println("随机生成的密钥:" + randomKey);

            String[] dataArr = {"hello", "hello world", "12345678901234567890"};

            for (String data : dataArr) {
                System.out.println("加密前:" + data);
                // 加密
                String encrypt = encrypt(data, randomKey);
                System.out.println("加密后:" + encrypt + " 长度:" + encrypt.length());
                // 解密
                String decrypt = decrypt(encrypt, randomKey);
                System.out.println("解密后:" + decrypt);
                System.out.println();
            }
      } catch (Exception e) {
            e.printStackTrace();
      }
    }
}
3. 注意事项

AES 加密算法适用于对称加密场景,速率快,得当加密大数据量。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【利用 Commons Codec 实现 MD5、RSA、AES 加密】