对字符串进行3DES加密

86 阅读3分钟

介绍

密码学中,三重数据加密算法(英语:Triple Data Encryption Algorithm,缩写为TDEA,Triple DEA),或称3DES(Triple DES),是一种对称密钥加密块密码,相当于是对每个数据块应用三次数据加密标准(DES)算法。由于计算机运算能力的增强,原版DES密码的密钥长度变得容易被暴力破解;3DES即是设计用来提供一种相对简单的方法,即通过增加DES的密钥长度来避免类似的攻击,而不是设计一种全新的块密码算法。

要求

q字符串__o_s=ec4867af19b00ba67f3b2c83058cc41a%23LATEST&__o_v=0.1.0&arg1=4&arg2=123456789&__o_r=1453355520149.751 对字符串进行加密

  • 首先对原始密钥(上文准备参数中的key)做MD5算hash值得到16位字节数组,再用前8位数据对应补全后8位 ,计算出24位长的密码byte值。
  • 使用上一步24位字节数组,构造一个算法为DESede的密钥。
  • 获取模式为“DESede/CBC/PKCS5Padding”的Cipher 对象
  • 以加密模式,上面生成的密钥,初始向量IV( 8字节空数组)作为算法参数,初始化Cipher 对象
  • q的字节数组作为缓存区, Cipher 按单部分操作进行加密(doFinal)
  • 对加密后的byte[]数组转换为0-9a-f 16进制ASCII字符q

加密与解密

public class TripleDESUtil {
    private static final Pattern pattern = Pattern.compile("[0-9a-fA-F]+");

    public TripleDESUtil() {
    }

    /**
     * 签名
     * @param dataStr
     * @param keyStr
     * @param saltStr
     * @return
     */
    public static String hmac(String dataStr, String keyStr, String saltStr) {
        try {
            byte[] data = (dataStr + saltStr).getBytes("UTF-8");
            byte[] key = keyStr.getBytes("UTF-8");
            SecretKeySpec keySpec = new SecretKeySpec(key, "HmacSHA1");
            Mac e = Mac.getInstance("HmacSHA1");
            e.init(keySpec);
            return toHexString(e.doFinal(data));
        } catch (Exception var7) {
            throw new RuntimeException("Signature calculation error");
        }
    }

    /**
     * 加密
     * @param message
     * @param key
     * @return
     */
    public static String encrypt(String message, String key) {
        try {
            SecretKeySpec var10 = new SecretKeySpec(toKeyBytes(key), "DESede");
            IvParameterSpec var11 = new IvParameterSpec(new byte[8]);
            Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
            cipher.init(1, var10, var11);
            byte[] plainTextBytes = message.getBytes("utf-8");
            return toHexString(cipher.doFinal(plainTextBytes));
        } catch (Exception var6) {
            throw new RuntimeException("Fail");
        }
    }

    /**
     * 解密
     * @param cypher
     * @param key
     * @return
     */
    public static String decrypt(String cypher, String key) {
        try {
            Map<String, String> map = toMap(cypher, false);
            String salt = (String)map.get("s");
            String expSig = (String)map.get("h");
            String dataStr = (String)map.get("d");
            String actSig = hmac(dataStr, key, salt);
            if (!actSig.equals(expSig)) {
                throw new RuntimeException("Fail to validate signatures, potentialdatacorruption");
            } else {
                Matcher match = pattern.matcher(dataStr);
                if (!match.matches()) {
                    throw new IllegalArgumentException("Invalid hex string: " + dataStr);
                } else if (dataStr.length() % 2 != 0) {
                    throw new IllegalArgumentException("Invalid hex string length:" + dataStr);
                } else {
                    int len = dataStr.length();
                    byte[] data = new byte[len / 2];

                    for(int i = 0; i < len; i += 2) {
                        data[i / 2] = (byte)((Character.digit(dataStr.charAt(i), 16) << 4) + Character.digit(dataStr.charAt(i + 1), 16));
                    }

                    SecretKeySpec keySpec = new SecretKeySpec(toKeyBytes(key), "DESede");
                    IvParameterSpec iv = new IvParameterSpec(new byte[8]);
                    Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
                    decipher.init(2, keySpec, iv);
                    byte[] plainText = decipher.doFinal(data);
                    String token = (String)toMap(new String(plainText, "UTF-8"), true).get("__o_o");
                    if (token != null && token.length() >= 3) {
                        return token;
                    } else {
                        throw new RuntimeException("Get invalid ticket: " + (token == null ? "null" : token));
                    }
                }
            }
        } catch (Exception var15) {
            throw new RuntimeException("Fail  to decrypt");
        }
    }

    public static Map<String, String> toMap(String data, boolean doUrlDecode) {
        try {
            Map<String, String> paramMap = new HashMap();
            if (data != null && data.trim().length() != 0) {
                data = data.trim();
                String[] cipher = data.split("&");
                String[] var4 = cipher;
                int var5 = cipher.length;

                for(int var6 = 0; var6 < var5; ++var6) {
                    String aCipher = var4[var6];
                    String[] pairs = aCipher.split("=");
                    if (doUrlDecode) {
                        paramMap.put(pairs[0], URLDecoder.decode(pairs[1], "UTF-8"));
                    } else {
                        paramMap.put(pairs[0], pairs[1]);
                    }
                }
            }

            return paramMap;
        } catch (UnsupportedEncodingException var9) {
            throw new RuntimeException("Fail to url decode");
        }
    }

    public static String toHexString(byte[] data) {
        StringBuilder buffer = new StringBuilder();
        byte[] var2 = data;
        int var3 = data.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            byte aData = var2[var4];
            buffer.append(String.format("%02x", 255 & aData));
        }

        return buffer.toString();
    }

    public static byte[] toKeyBytes(String key) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest md = MessageDigest.getInstance("md5");
        byte[] digestOfPassword = md.digest(key.getBytes("utf-8"));
        byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
        System.arraycopy(keyBytes, 0, keyBytes, 16, 8);
        return keyBytes;
    }
}