但行好事
莫论前程❤

EncryptUtil加密解密工具类

EncryptUtil工具类:

  1. 使用commons-logging记录异常日志。
  2. 提取常量字段、公共字段。
  3. 提取公共方法:
//创建密钥  
createSecretKey(String key):Key   
//加密解密  
processCipher(byte[] processData, Key key, int opsMode, String algorithm):byte[]  

EncryptUtil类的完整代码:

import java.io.IOException;  
import java.security.Key;  
import java.security.KeyPair;  
import java.security.KeyPairGenerator;  
import java.security.MessageDigest;  
import java.security.NoSuchAlgorithmException;  
import java.security.PrivateKey;  
import java.security.PublicKey;  
import java.security.SecureRandom;  
import java.security.Signature;  

import javax.crypto.Cipher;  
import javax.crypto.SecretKey;  
import javax.crypto.SecretKeyFactory;  
import javax.crypto.spec.DESKeySpec;  

import org.apache.commons.logging.Log;  
import org.apache.commons.logging.LogFactory;  

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

/** 
 * 功能简述: 加密解密工具类,对MD5/BASE64/DES/RSA等算法提供了包装. 
 * @author liupeng 
 * @version 1.0 
 */  
public class EncryptUtil {  
    private static Log logger = LogFactory.getLog(EncryptUtil.class);  

    private static final int KEY_SIZE = 1024;  
    private static final String  MD5_ALGORITHM= "md5";  
    private static final String  DES_ALGORITHM= "des";  
    private static final String  RSA_ALGORITHM= "rsa";  
    private static final String  SIGNATURE_ALGORITHM= "MD5withRSA";  

    private static MessageDigest md5;  
    private static BASE64Encoder encoder;  
    private static BASE64Decoder decoder;  
    private static SecureRandom random;  
    private static KeyPair keyPair;  

    private EncryptUtil() {  
    }  

     static {  
        try {  
            md5 = MessageDigest.getInstance(MD5_ALGORITHM);  

            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);  
            keyPairGenerator.initialize(KEY_SIZE);  
            keyPair = keyPairGenerator.generateKeyPair();  
        }  
        catch (NoSuchAlgorithmException e) {  
            // Exception handler  
            logger.error(e);  
        }  
        encoder = new BASE64Encoder();  
        decoder = new BASE64Decoder();  
        random = new SecureRandom();  
    }  

     /** 
     * 功能简述: 使用md5进行单向加密. 
     */  
    public static String encryptMD5(String plainText) {  
        byte[] cipherData = md5.digest(plainText.getBytes());  
        StringBuilder builder = new StringBuilder();  
        for(byte cipher : cipherData) {  
            String toHexStr = Integer.toHexString(cipher & 0xff);  
            builder.append(toHexStr.length() == 1 ? "0" + toHexStr : toHexStr);  
        }  
        return builder.toString();  
    }  
      /** 
     * 功能简述: 使用BASE64进行加密. 
     * @param plainData 明文数据 
     * @return 加密之后的文本内容 
     */  
    public static String encryptBASE64(byte[] plainData) {  
        return encoder.encode(plainData);  
    }  

    /** 
     * 功能简述: 使用BASE64进行解密. 
     * @param cipherText 密文文本 
     * @return 解密之后的数据 
     */  
    public static byte[] decryptBASE64(String cipherText) {  
        byte[] plainData = null;  
        try {  
            plainData =  decoder.decodeBuffer(cipherText);  
        }  
        catch (IOException e) {  
            // Exception handler  
            logger.error(e);  
        }  
        return plainData;  
    }  
    /** 
     * 功能简述: 使用DES算法进行加密. 
     * @param plainData 明文数据 
     * @param key   加密密钥 
     * @return   
     */  
    public static byte[] encryptDES(byte[] plainData, String key) {  
        return processCipher(plainData, createSecretKey(key), Cipher.ENCRYPT_MODE, DES_ALGORITHM);  
    }  

    /** 
     * 功能简述: 使用DES算法进行解密. 
     * @param cipherData    密文数据 
     * @param key   解密密钥 
     * @return 
     */  
    public static byte[] decryptDES(byte[] cipherData, String key) {  
        return processCipher(cipherData, createSecretKey(key), Cipher.DECRYPT_MODE, DES_ALGORITHM);  
    }  

    /** 
     * 功能简述: 根据key创建密钥SecretKey. 
     * @param key  
     * @return 
     */  
    private static SecretKey createSecretKey(String key) {  
        SecretKey secretKey = null;  
        try {  
            DESKeySpec keySpec = new DESKeySpec(key.getBytes());  
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);  
            secretKey = keyFactory.generateSecret(keySpec);  
        }  
        catch (Exception e) {  
            // Exception handler  
            logger.error(e);  
        }  
        return secretKey;  
    }  

    /** 
     * 功能简述: 加密/解密处理流程. 
     * @param processData   待处理的数据 
     * @param key   提供的密钥 
     * @param opsMode   工作模式 
     * @param algorithm   使用的算法 
     * @return   
     */  
    private static byte[] processCipher(byte[] processData, Key key, int opsMode, String algorithm) {  
        try{   
            Cipher cipher = Cipher.getInstance(algorithm);  
            cipher.init(opsMode, key, random);  
            return cipher.doFinal(processData);  
        }  
        catch (Exception e) {  
            // Exception handler  
            logger.error(e);  
        }  
        return null;  
    }  

    /** 
     * 功能简述: 创建私钥,用于RSA非对称加密. 
     * @return 
     */  
    public static PrivateKey createPrivateKey() {  
        return keyPair.getPrivate();  
    }  

    /** 
     * 功能简述: 创建公钥,用于RSA非对称加密. 
     * @return 
     */  
    public static PublicKey createPublicKey() {  
        return keyPair.getPublic();  
    }  

    /** 
     * 功能简述: 使用RSA算法加密. 
     * @param plainData 明文数据 
     * @param key   密钥 
     * @return 
     */  
    public static byte[] encryptRSA(byte[] plainData, Key key) {  
        return processCipher(plainData, key, Cipher.ENCRYPT_MODE, RSA_ALGORITHM);  
    }  

    /** 
     * 功能简述: 使用RSA算法解密. 
     * @param cipherData    密文数据 
     * @param key   密钥 
     * @return 
     */  
    public static byte[] decryptRSA(byte[] cipherData, Key key) {  
        return processCipher(cipherData, key, Cipher.DECRYPT_MODE, RSA_ALGORITHM);  
    }  

    /** 
     * 功能简述: 使用私钥对加密数据创建数字签名. 
     * @param cipherData     已经加密过的数据 
     * @param privateKey    私钥 
     * @return 
     */  
    public static byte[] createSignature(byte[] cipherData, PrivateKey privateKey) {  
        try {  
            Signature signature  = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initSign(privateKey);  
            signature.update(cipherData);  
            return signature.sign();  
        }  
        catch (Exception e) {  
            // Exception handler  
            logger.error(e);   
        }  
        return null;  
    }  

    /** 
     * 功能简述: 使用公钥对数字签名进行验证. 
     * @param signData  数字签名 
     * @param publicKey 公钥 
     * @return 
     */  
    public static boolean verifySignature(byte[] cipherData, byte[] signData, PublicKey publicKey) {  
        try {  
            Signature signature  = Signature.getInstance(SIGNATURE_ALGORITHM);  
            signature.initVerify(publicKey);  
            signature.update(cipherData);  
            return signature.verify(signData);  
        }  
        catch (Exception e) {  
            // Exception handler  
            logger.error(e);  
        }  
        return false;  
    }  
}  

Commons Codec对BASE64的扩展支持:

​ JDK提供了对BASE64的标准支持,每隔76个字符进行换行\r\n,并且包含+、=、/等特殊字符不适合作为url参数传递。因此通常都会使用Commons Codec来进行BASE64的加密和解密。下载commons-codec-1.8.jar并添加到lib下面,注意选择高版本,低版本有些方法不支持。

  1. 是否换行:
byte[] cipherData = Base64.encodeBase64(plainText.getBytes()); //默认不换行    
byte[] cipherData = Base64.encodeBase64(plainText.getBytes(), false); //取消换行  
byte[] cipherData = Base64.encodeBase64Chunked(plainText.getBytes()); //进行换行  
String cipherText = Base64.encodeBase64String(plainText.getBytes()); //转为字符串  
  1. 安全的url:转换+为-、/为_、将多余的=去掉
byte[] cipherData = Base64.encodeBase64(plainText.getBytes(), false, true);  
byte[] cipherData = Base64.encodeBase64URLSafe(plainText.getBytes());  
String cipherText = Base64.encodeBase64URLSafeString(plainText.getBytes());  

MD5、BASE64、DES、RSA等经典加密解密算法,JDK都有提供专门的API来封装相关操作。

MD5加密算法:

​ 消息摘要算法第五版(Message Digest Algorithm),是一种单向加密算法,只能加密、无法解密。然而MD5加密算法已经被中国山东大学王小云教授成功破译,但是在安全性要求不高的场景下,MD5加密算法仍然具有应用价值。

  1. 创建md5对象:
MessageDigest md5 = MessageDigest.getInstance("md5");  
  1. 进行加密操作:
byte[] cipherData = md5.digest(plainText.getBytes());  
  1. 将其中的每个字节转成十六进制字符串:byte类型的数据最高位是符号位,通过和0xff进行与操作,转换为int类型的正整数。
String toHexStr = Integer.toHexString(cipher & 0xff);
  1. 如果该正数小于16(长度为1个字符),前面拼接0占位:确保最后生成的是32位字符串。
builder.append(toHexStr.length() == 1 ? "0" + toHexStr : toHexStr);
  1. 加密转换之后的字符串为:c0bb4f54f1d8b14caf6fe1069e5f93ad

  2. 完整的MD5算法应用如下所示:

/** 
 * 功能简述: 测试MD5单向加密. 
 * @throws Exception 
 */  
@Test  
public void test01() throws Exception {  
    String plainText = "Hello , world !";  
    MessageDigest md5 = MessageDigest.getInstance("md5");  
    byte[] cipherData = md5.digest(plainText.getBytes());  
    StringBuilder builder = new StringBuilder();  
    for(byte cipher : cipherData) {  
        String toHexStr = Integer.toHexString(cipher & 0xff);  
        builder.append(toHexStr.length() == 1 ? "0" + toHexStr : toHexStr);  
    }  
     System.out.println(builder.toString());  
    //c0bb4f54f1d8b14caf6fe1069e5f93ad  
}  

使用BASE64进行加密/解密:

​ 使用BASE64算法通常用作对二进制数据进行加密,加密之后的数据不易被肉眼识别。严格来说,经过BASE64加密的数据其实没有安全性可言!,因为它的加密解密算法都是公开的,典型的防菜鸟不防程序猿的呀。 经过标准的BASE64算法加密后的数据, 通常包含/、+、=等特殊符号,不适合作为url参数传递,幸运的是Apache的Commons Codec模块提供了对BASE64的进一步封装。 (参见最后一部分的说明)

  1. 使用BASE64加密:
BASE64Encoder encoder = new BASE64Encoder();  
String cipherText = encoder.encode(plainText.getBytes());  
  1. 使用BASE64解密:
BASE64Decoder decoder = new BASE64Decoder();  
plainText = new String(decoder.decodeBuffer(cipherText));  
  1. 完整代码示例:
/** 
 * 功能简述: 使用BASE64进行双向加密/解密. 
 * @throws Exception 
 */  
@Test  
public void test02() throws Exception {  
    BASE64Encoder encoder = new BASE64Encoder();  
    BASE64Decoder decoder = new BASE64Decoder();  
    String plainText = "Hello , world !";  
    String cipherText = encoder.encode(plainText.getBytes());  
    System.out.println("cipherText : " + cipherText);  
    //cipherText : SGVsbG8gLCB3b3JsZCAh  
    System.out.println("plainText : " +   
        new String(decoder.decodeBuffer(cipherText)));  
    //plainText : Hello , world !  

使用DES对称加密/解密:

​ 数据加密标准算法(Data Encryption Standard),和BASE64最明显的区别就是有一个工作密钥,该密钥既用于加密、也用于解密,并且要求密钥是一个长度至少大于8位的字符串。使用DES加密、解密的核心是确保工作密钥的安全性.

  1. 根据key生成密钥:
DESKeySpec keySpec = new DESKeySpec(key.getBytes());  
SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("des");  
SecretKey secretKey = keyFactory.generateSecret(keySpec);  
  1. 加密操作:
Cipher cipher = Cipher.getInstance("des");  
cipher.init(Cipher.ENCRYPT_MODE, secretKey, new SecureRandom());  
byte[] cipherData = cipher.doFinal(plainText.getBytes());  
  1. 为了便于观察生成的加密数据,使用BASE64再次加密:
String cipherText = new BASE64Encoder().encode(cipherData);  
  1. 解密操作:
cipher.init(Cipher.DECRYPT_MODE, secretKey, new SecureRandom());  
byte[] plainData = cipher.doFinal(cipherData);  
String plainText = new String(plainData);  
  1. 完整的代码demo:
/** 
 * 功能简述: 使用DES对称加密/解密. 
 * @throws Exception 
 */  
@Test  
public void test03() throws Exception {  
    String plainText = "Hello , world !";  
    String key = "12345678";    //要求key至少长度为8个字符  

    SecureRandom random = new SecureRandom();  
    DESKeySpec keySpec = new DESKeySpec(key.getBytes());  
    SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("des");  
    SecretKey secretKey = keyFactory.generateSecret(keySpec);  

    Cipher cipher = Cipher.getInstance("des");  
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, random);  
    byte[] cipherData = cipher.doFinal(plainText.getBytes());  
    System.out.println("cipherText : " + new BASE64Encoder().encode(cipherData));  
    //PtRYi3sp7TOR69UrKEIicA==  

    cipher.init(Cipher.DECRYPT_MODE, secretKey, random);  
    byte[] plainData = cipher.doFinal(cipherData);  
    System.out.println("plainText : " + new String(plainData));  
    //Hello , world !  
}  

使用RSA非对称加密/解密:

​ RSA算法是非对称加密算法的典型代表,既能加密、又能解密。和对称加密算法比如DES的明显区别在于用于加密、解密的密钥是不同的。使用RSA算法,只要密钥足够长(一般要求1024bit),加密的信息是不能被破解的.用户通过https协议访问服务器时,就是使用非对称加密算法进行数据的加密、解密操作的。

​ 服务器发送数据给客户端时使用私钥(private key)进行加密,并且使用加密之后的数据和私钥生成数字签名(digital signature)并发送给客户端。客户端接收到服务器发送的数据会使用公钥(public key)对数据来进行解密,并且根据加密数据和公钥验证数字签名的有效性,防止加密数据在传输过程中被第三方进行了修改。

​ 客户端发送数据给服务器时使用公钥进行加密,服务器接收到加密数据之后使用私钥进行解密。

  1. 创建密钥对KeyPair:
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("rsa");  
keyPairGenerator.initialize(1024);  //密钥长度推荐为1024位.  
KeyPair keyPair = keyPairGenerator.generateKeyPair();  
  1. 获取公钥/私钥:
PublicKey publicKey = keyPair.getPublic();  
PrivateKey privateKey = keyPair.getPrivate();  
  1. 服务器数据使用私钥加密:
Cipher cipher = Cipher.getInstance("rsa");  
cipher.init(Cipher.ENCRYPT_MODE, privateKey, new SecureRandom());  
byte[] cipherData = cipher.doFinal(plainText.getBytes());  
  1. 用户使用公钥解密:
cipher.init(Cipher.DECRYPT_MODE, publicKey, new SecureRandom());  
byte[] plainData = cipher.doFinal(cipherData); 
  1. 服务器根据私钥和加密数据生成数字签名:
Signature signature  = Signature.getInstance("MD5withRSA");  
signature.initSign(privateKey);  
signature.update(cipherData);  
byte[] signData = signature.sign();  
  1. 用户根据公钥、加密数据验证数据是否被修改过:
signature.initVerify(publicKey);  
signature.update(cipherData);  
boolean status = signature.verify(signData);
  1. RSA算法代码demo:
/** 
 * 功能简述: 使用RSA非对称加密/解密. 
 * @throws Exception 
 */  
@Test  
public void test04() throws Exception {  
    String plainText = "Hello , world !";  

    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("rsa");  
    keyPairGenerator.initialize(1024);  
    KeyPair keyPair = keyPairGenerator.generateKeyPair();  

    PublicKey publicKey = keyPair.getPublic();  
    PrivateKey privateKey = keyPair.getPrivate();  

    Cipher cipher = Cipher.getInstance("rsa");  
    SecureRandom random = new SecureRandom();  

    cipher.init(Cipher.ENCRYPT_MODE, privateKey, random);  
    byte[] cipherData = cipher.doFinal(plainText.getBytes());  
    System.out.println("cipherText : " + new BASE64Encoder().encode(cipherData));  
    //gDsJxZM98U2GzHUtUTyZ/Ir/NXqRWKUJkl6olrLYCZHY3RnlF3olkWPZ35Dwz9BMRqaTL3oPuyVq  
    //sehvHExxj9RyrWpIYnYLBSURB1KVUSLMsd/ONFOD0fnJoGtIk+T/+3yybVL8M+RI+HzbE/jdYa/+  
    //yQ+vHwHqXhuzZ/N8iNg=  

    cipher.init(Cipher.DECRYPT_MODE, publicKey, random);  
    byte[] plainData = cipher.doFinal(cipherData);  
    System.out.println("plainText : " + new String(plainData));  
    //Hello , world !  

    Signature signature  = Signature.getInstance("MD5withRSA");  
    signature.initSign(privateKey);  
    signature.update(cipherData);  
    byte[] signData = signature.sign();  
    System.out.println("signature : " + new BASE64Encoder().encode(signData));  
    //ADfoeKQn6eEHgLF8ETMXan3TfFO03R5u+cQEWtAQ2lRblLZw1DpzTlJJt1RXjU451I84v3297LhR  
    //co64p6Sq3kVt84wnRsQw5mucZnY+jRZNdXpcbwh2qsh8287NM2hxWqp4OOCf/+vKKXZ3pbJMNT/4  
    ///t9ewo+KYCWKOgvu5QQ=  

    signature.initVerify(publicKey);  
    signature.update(cipherData);  
    boolean status = signature.verify(signData);  
    System.out.println("status : " + status);  
    //true  
}  
赞(0) 打赏
未经允许不得转载:刘鹏博客 » EncryptUtil加密解密工具类
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏