数据安全设计

4 篇文章 0 订阅

引言:在 web 程序中,数据加密非常重要,对于不用解密的数据,如密码等,一般使用 md5 的加密技术,对于需要解密的数据,我们常用 AES 加密,现在我们来讨论下如何提高数据的安全性。

一、对私钥用公钥加密,然后数据进行多次对称加密
我觉得,数据的加首先双方约定一个
公钥:ABCDEFGHIJKLMNOP
签名:QWERTYHJKDLOFJSK
数据加密次数:n

  • 加密随机密钥

    首先对公钥进行MD5加密,转大写并截取 16 位作为newKey;

    然后随机生成 16 位的随机密钥 randomKey,对randomKey 进行 AES 标准加密(偏移量和私钥一样,加密方式为为:“AES/CBC/PKCS5Padding”)得到加密的秘钥realKey;

  • 双方约定数据封装形式+签名-> data,然后对其 MD5 加密转大写成为newSign;

    再对上面的随机秘钥 randomKey 进行 MD5 加密,截取 16 位作为数据传输的 json 进行 AES 标准进行加密,json 一般都是需要传输的数据+newSign;(这里 AES 根据约定进行轮换 n 次)

    下面给出流程示例
    加密示例

下面贴出代码

package com.dao.xu;


import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.digest.DigestUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.*;
/**
 *  安全设计
 *
 * @author 阿导
 * @CopyRight 万物皆导
 * @Created 2019/5/15 20:26:00
 */
public class WWJD {
    /**
     * 加密公钥
     */
    private final static String COMMON_KEY = "wwjdwwjdwwjdwwjdwwjdwwjdwwjdwwjd";
    /**
     * 签名秘钥
     */
    private final static String SIGN_KEY = "wwjdwwjdwwjdwwjdwwjdwwjdwwjdwwjd";
    /**
     * 约定次数
     */
    private final static Integer N = 10;
    /**
     * SIGN
     */
    private final static String SIGN = "sign";
    /**
     * 随机秘钥集合
     */
    private final static String KEYS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz*$";
    /**
     * 默认字符集
     */
    private final static String DEFAULT_CODE = "UTF-8";
    /**
     * 零
     */
    private final static Integer ZERO = Integer.valueOf(0);
    /**
     * 引号
     */
    public static final String QUOTES = "\"";
    /**
     * 逗号
     */
    public static final String COMMA = ",";
    /**
     * 冒号
     */
    public static final String COLON = ":";
    /**
     * 左大括号
     */
    public static final String BRACES_LEFT = "{";
    /**
     * 右大括号
     */
    public static final String BRACES_RIGHT = "}";

    /**
     * 将字符串MD5加码 生成32位md5码
     *
     * @param inStr
     * @return java.lang.String
     * @author 阿导
     * @time 2019/5/15 20:23:00
     */
    private static String md5(String inStr) {
        try {
            return DigestUtils.md5Hex(inStr.getBytes(DEFAULT_CODE));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("MD5签名过程中出现错误");
        }
    }


    /**
     * AES加密
     *
     * @param cleartext
     * @param rKey
     * @return java.lang.String
     * @author 阿导
     * @time 2019/5/15 20:24:00
     */
    private static String encrypt(String cleartext, String rKey) {
        //加密方式: AES128(CBC/PKCS5Padding) + Base64, 私钥:rKey
        try {
            IvParameterSpec zeroIv = new IvParameterSpec(rKey.getBytes());
            //两个参数,第一个为私钥字节数组, 第二个为加密方式 AES或者DES

            SecretKeySpec key = new SecretKeySpec(rKey.getBytes(), "AES");

            //实例化加密类,参数为加密方式,要写全
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
            //PKCS5Padding比PKCS7Padding效率高,PKCS7Padding可支持IOS加解密

            //初始化,此方法可以采用三种方式,按加密算法要求来添加。(1)无第三个参数(2)第三个参数为SecureRandom random = new SecureRandom();中random对象,随机数。(AES不可采用这种方法)(3)采用此代码中的IVParameterSpec
            cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);

            //加密操作,返回加密后的字节数组,然后需要编码。主要编解码方式有Base64, HEX, UUE,7bit等等。此处看服务器需要什么编码方式
            byte[] encryptedData = cipher.doFinal(cleartext.getBytes(DEFAULT_CODE));

            return new BASE64Encoder().encode(encryptedData);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    
    /**
     * AES 解密
     * @author 阿导
     * @time 2019/5/15 20:24:00
     * @param encrypted
     * @param rKey
     * @return java.lang.String
     */
    private static String decrypt(String encrypted, String rKey) {
    
        try {
            byte[] byteMi = new BASE64Decoder().decodeBuffer(encrypted);
            IvParameterSpec zeroIv = new IvParameterSpec(rKey.getBytes());
            SecretKeySpec key = new SecretKeySpec(rKey.getBytes(), "AES");
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            //与加密时不同MODE:Cipher.DECRYPT_MODE
            cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
            byte[] decryptedData = cipher.doFinal(byteMi);
            return new String(decryptedData, DEFAULT_CODE);
        } catch (Exception e) {
            e.printStackTrace();
            return "";
        }
    }

    /**
     * 获取随机秘钥
     *
     * @author 阿导
     * @time 2019/5/15 20:25:00
     * @param num
     * @return java.lang.String
     */
    private static String getRKey(Integer num) {
        String rs = new String();
        for (int pox = ZERO; pox < num; pox++) {
            rs += KEYS.toCharArray()[new Random().nextInt(KEYS.length())];
        }
        return rs;
    }

    public static Map<String, String> getEncryptionData(Map<String, String> map) {
        //存储realKey和realData
        Map<String, String> rsMap = new HashMap<>(16);
        String randomKey = getRKey(16);
        rsMap.put("realKey", URLEncoder.encode(encrypt(randomKey, md5(COMMON_KEY).substring(ZERO, 16).toUpperCase())));
        String realData = getJsonString(map);

        for (int i = ZERO; i < N; i++) {
            realData = encrypt(realData, randomKey);
        }
        rsMap.put("realData", URLEncoder.encode(realData));
        return rsMap;
    }


    /**
     * 处理数据
     * 
     * @author 阿导
     * @time 2019/5/15 20:26:00
     * @param params
     * @return java.lang.String
     */
    private static String dealData(Map<String, Object> params) {
        StringBuilder sign = new StringBuilder();
        Map<String, Object> sortParams = new TreeMap<String, Object>(params);
        Set<Map.Entry<String, Object>> entrys = sortParams.entrySet();
        int count = ZERO;
        for (Map.Entry<String, Object> entry : entrys) {
            if (entry.getValue() != null) {
                if (count++ != ZERO) {
                    sign.append(COMMA);
                }
                sign.append(QUOTES)
                        .append(entry.getKey())
                        .append(COLON)
                        .append(entry.getValue())
                        .append(QUOTES);
            }
        }

        sign.append(QUOTES)
                .append(SIGN)
                .append(COLON)
                .append(SIGN_KEY)
                .append(QUOTES);

        return md5(sign.toString()).toUpperCase();
    }

    /**
     * 获取 json 数据
     * 
     * @author 阿导
     * @time 2019/5/15 20:26:00
     * @param params
     * @return java.lang.String
     */
    private static String getJsonString(Map<String, String> params) {
        StringBuilder json = new StringBuilder();
        // 将参数以参数名的字典升序排序
        Map<String, String> sortParams = new TreeMap<String, String>(params);
        Set<Map.Entry<String, String>> entrys = sortParams.entrySet();
        String sign = dealData(new HashMap<>(params));
        json.append(BRACES_LEFT);
        int count = ZERO;
        for (Map.Entry<String, String> entry : entrys) {
            if (entry.getValue() != null) {
                if (count++ != ZERO) {
                    json.append(COMMA);
                }
                json.append(QUOTES)
                        .append(entry.getKey())
                        .append(QUOTES)
                        .append(COLON)
                        .append(QUOTES)
                        .append(entry.getValue())
                        .append(QUOTES);
            }
        }
        json.append(COMMA)
                .append(QUOTES)
                .append(SIGN)
                .append(QUOTES)
                .append(COLON)
                .append(QUOTES)
                .append(sign)
                .append(QUOTES)
                .append(BRACES_RIGHT);

        return json.toString();
    }

    /**
     * 获取解密数据
     * 
     * @author 阿导
     * @time 2019/5/15 20:27:00
     * @param map
     * @return java.lang.Object
     */
    private static Object getDecryptData(Map<String, String> map) {
        try {
            String randomKey = decrypt(URLDecoder.decode(map.get("realKey")), md5(COMMON_KEY).substring(0, 16).toUpperCase());
            String rsData = URLDecoder.decode(map.get("realData").toString());
            for (int i = ZERO; i < N; i++) {
                rsData = decrypt(rsData, randomKey);
            }
            Map<String, Object> rsMap = JSON.parseObject(rsData);
            String sign = (String) rsMap.get("sign");
            if (sign == null || "".equals(sign)) {
                return "SIGN_NULL";
            }
            rsMap.remove("sign");
            if (sign.equals(dealData(rsMap))) {
                return rsMap;
            } else {
                return "SIGN_ERROR";
            }
        } catch (Exception e) {
            return "KEY_ERROR";
        }

    }

    public static void main(String[] args) {
        Map<String, String> map = new HashMap<String, String>();
        map.put("name", "小明");
        map.put("sex", "男");
        Map<String, String> map1 = getEncryptionData(map);
        Object map2 = getDecryptData(map1);
        System.err.println(map2);
    }

}



皎月

哎!最近阿导诸事不利,广告还是打起来:

需要云服务器的不要错过优惠

阿里云低价购买云服务,值得一看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值