3Des加密

       使用3Des加密算法前,我们需要了解一下当前主流的加密模式:单向加密和双向加密,两者最大的区别在于加密的密文是否具有可逆性。

       单向加密:将需要加密的数据进行加密,并且密文不可进行解密,像我们常用的加密算法MD5就属于这种。

       双向加密:和单向加密不同的是可以通过某些方式进行加解密的操作,其中分为对称加密和非对称加密。

               对称加密:指数据使用者必须拥有相同的密钥才可以进行加密解密,就像彼此约定的一串暗号,本文介绍的3Des加密就属于这种。

               非对称加密:通过一组包含公钥和私钥的密码来加密解密,用公钥加密,私钥解密,首推的就是RSA加密

---------------------------------------------------------------------------------------------------------------------------------------

         3Des加密算法,由于可以逆推原文,所以主要通过本地的唯一密钥来保证数据的安全性,我这边通过生成随机的256位加密字符串存储在本地,代码读取时将其通过md5加密成32位的字符串(由于本地有原始密钥,不必担心md5加密不可逆),最后以这32位加密字符串作为密钥进行加解密的操作。

  

package com.youfuli.util;


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

import Decoder.BASE64Decoder;
import Decoder.BASE64Encoder;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.util.UUID;

/**
 * Created by lixiaotian on 2018/12/25.
 */
public class Des3Util {

	private static final String IV = "1234567-";

	/**
	 * DESCBC加密
	 *
	 * @param src 数据源
	 * @param key 密钥,长度必须是8的倍数
	 * @return 返回加密后的数据
	 * @throws Exception
	 */
	public String encryptDESCBC(final String src, final String key) throws Exception {

		// --生成key,同时制定是des还是DESede,两者的key长度要求不同
		final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
		final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

		// --加密向量
		final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

		// --通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.ENCRYPT_MODE,
		// secretKey)就可以了.
		final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
		final byte[] b = cipher.doFinal(src.getBytes("UTF-8"));

		// --通过base64,将加密数组转换成字符串
		final BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(b);
	}

	/**
	 * DESCBC解密
	 *
	 * @param src 数据源
	 * @param key 密钥,长度必须是8的倍数
	 * @return 返回解密后的原始数据
	 * @throws Exception
	 */
	public String decryptDESCBC(final String src, final String key) throws Exception {
		// --通过base64,将字符串转成byte数组
		final BASE64Decoder decoder = new BASE64Decoder();
		final byte[] bytesrc = decoder.decodeBuffer(src);

		// --解密的key
		final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
		final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
		final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

		// --向量
		final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));

		// --Chipher对象解密Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.DECRYPT_MODE,
		// secretKey)就可以了.
		final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
		cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
		final byte[] retByte = cipher.doFinal(bytesrc);

		return new String(retByte);

	}

	// 3DESECB加密,key必须是长度大于等于 3*8 = 24 位哈
	public static String encryptThreeDESECB(final String src, final String key) throws Exception {
		final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
		final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		final SecretKey securekey = keyFactory.generateSecret(dks);

		final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
		cipher.init(Cipher.ENCRYPT_MODE, securekey);
		final byte[] b = cipher.doFinal(src.getBytes());

		final BASE64Encoder encoder = new BASE64Encoder();
		return encoder.encode(b).replaceAll("\r", "").replaceAll("\n", "");

	}

	// 3DESECB解密,key必须是长度大于等于 3*8 = 24 位哈
	public static String decryptThreeDESECB(final String src, final String key) throws Exception {
		// --通过base64,将字符串转成byte数组
		final BASE64Decoder decoder = new BASE64Decoder();
		final byte[] bytesrc = decoder.decodeBuffer(src);
		// --解密的key
		final DESedeKeySpec dks = new DESedeKeySpec(key.getBytes("UTF-8"));
		final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DESede");
		final SecretKey securekey = keyFactory.generateSecret(dks);

		// --Chipher对象解密
		final Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
		cipher.init(Cipher.DECRYPT_MODE, securekey);
		final byte[] retByte = cipher.doFinal(bytesrc);

		return new String(retByte);
	}
}

       此处提供的代码中,展现了des加解密和3des加解密的相应的方法。des和3Des加密算法的区别在于des加密算法的实际密文长度为56位,导致加密长度不足,才会出现3Des加密算法来进行弥补的,通过执行3次DES来达到增加密钥长度和安全的目的。

        这边我提供一个测试类,用于测试生成本地唯一密钥文件和md5加密本地密钥文件,然后采用3Des对需要加解密的数据进行加解密的操作。

        

public static void main(String[] args) throws Exception {
		String str2 = "";
		StringBuilder result = new StringBuilder();
		File newfile = new File("D:/decrypt");
		if (!newfile.exists()) {
			newfile.mkdirs();
			File file = new File("D:/decrypt"+"/decrypt.txt");
			if(!file.exists()) {
				file.createNewFile();
			}
			for (int i=0;i<8;i++) {
				UUID uuid = UUID.randomUUID();
	            String str = uuid.toString();
	            String str1 = str.substring(0, 8) + str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) + str.substring(24);
	            str2 = str2+str1;
			}
			FileOutputStream fileOutputStream = null;
			fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(str2.getBytes("UTF-8"));
            fileOutputStream.close();
		}
		BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream("D:/decrypt/decrypt.txt"), "UTF-8"));

		String lineTxt = null;
		while ((lineTxt = bfr.readLine()) != null) {
			result.append(lineTxt).append("\n");
		}
		bfr.close();
		str2 = result.toString();
		System.out.println(str2);
		String md5Key = md5.getMD5Str(str2);
		System.out.println("密钥:"+md5Key);
		String keys = "654321";
		Des3Util des3 = new Des3Util();
		String txt = des3.encryptThreeDESECB(keys, md5Key);
		System.out.println("加密数据:"+txt);
		String decy = des3.decryptThreeDESECB(txt,md5Key);
		System.out.println("解密数据:"+decy);
	}

     可以看出,我本地通过uuid循环八次随机生成密钥文件,然后对其进行md5,最后调用相应的方法进行加解密的操作,最后对需要加密的数据“654321”的加解密的操作结果如下:

  

第一行:打印出本地长度为256位的原始密钥

第二行:打印出使用md5加密后的密钥

第三行:对654321进行加密后的加密数据

第四行:对加密数据preJaIoIzLw=进行解密,最后还原为明文654321

---------------------------------------------------------------------------------------------------------------------------------------

      此次采用3Des加密算法,在于把本地配置文件中的密码配置进行加密化操作,将配置文件中的密码加密保存在数据库中,然后再读取时配置在缓存中。

package com.youfuli.util;

import com.youfuli.dao.FlxThirdAccountInfoMapper;
import com.youfuli.entity.FlxThirdAccountInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.util.*;

/**
 * Created by lixiaotian on 2018/12/25.
 */
public class ThirdAccountMap {

    private static Logger logger = LoggerFactory.getLogger(ThirdAccountMap.class);

    //账户map
    private static Map<String, String> accMap;

    static FlxThirdAccountInfoMapper thirdAccountInfoMapper = SpringUtil.getBean(FlxThirdAccountInfoMapper.class);

    static {
        try {
            List<FlxThirdAccountInfo> thirdAccountInfos = thirdAccountInfoMapper.findAccount();
            if (CollectionUtils.isEmpty(thirdAccountInfos)) {
                logger.info("数据库还未导入加密密码");
            }
            Properties prop = PropertiesUtil.getInstance();
            String decryptUrl = prop.getProperty("decrypt.url");
            StringBuilder result = new StringBuilder();
            File newfile = new File(decryptUrl);
            String txtFile = decryptUrl + "/decrypt.txt";
            File file = new File(txtFile);
            //文件不存在的情况
            if (!file.exists()) {
                if (!newfile.exists()) {
                    newfile.mkdirs();
                }
                file.createNewFile();
                String str2 = "";
                for (int i = 0; i < 8; i++) {
                    UUID uuid = UUID.randomUUID();
                    String str = uuid.toString();
                    String str1 = str.substring(0, 8) + str.substring(9, 13) + str.substring(14, 18) + str.substring(19, 23) + str.substring(24);
                    str2 = str2 + str1;
                }
                FileOutputStream fileOutputStream = null;
                fileOutputStream = new FileOutputStream(file);
                fileOutputStream.write(str2.getBytes("UTF-8"));
                fileOutputStream.close();
            }
            BufferedReader bfr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(txtFile)), "UTF-8"));
            String lineTxt = null;
            while ((lineTxt = bfr.readLine()) != null) {
                result.append(lineTxt).append("\n");
            }
            bfr.close();
            String str = md5.getMD5Str(result.toString());
            accMap = new HashMap<>();
            for (int i = 0; i < thirdAccountInfos.size(); i++) {
                String keys = thirdAccountInfos.get(i).getAccountKey();
                String values = thirdAccountInfos.get(i).getAccountValue();
                if ("1".equals(thirdAccountInfos.get(i).getIsEncrypt())) {
                    accMap.put(keys, Des3Util.decryptThreeDESECB(values, str));
                } else {
                    accMap.put(keys, values);
                }


            }
            logger.info("数据库解密密码完成");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 根据账户key进行查询
     *
     * @param accountKey
     * @return
     */
    public static String queryThirdKey(String accountKey) {
        if (accMap == null) {
            logger.error("数据库加密信息未加载");
            return null;
        }
        return accMap.get(accountKey);
    }
}

通过数据库中的key匹配key即可。

appKey = ThirdAccountMap.queryThirdKey("appKey");

其中还对文件路径下的文件做了处理,如果不存在即进行新建处理,个人觉得还有优化的空间。一起加油哦。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值