Java实现3DES加密算法

加密简介

单向加密:通过对数据进行摘要计算生成密文,密文不可逆推还原。算法代表:MD5,SHA

双向加密:与单向加密相反,可以把密文逆推还原成明文,双向加密又分为对称加密和非对称加密

对称加密:指数据使用者必须拥有相同的密钥才可以进行加密解密。算法代表:DES,3DES,AES,IDEA,RC4,RC5;

非对称加密:非对称加密是一种“信息公开的密钥交换协议”。非对称加密需要公开密钥和私有密钥两组密钥,公开密钥和私有密钥是配对起来的,也就是说使用公开密钥进行数据加密,只有对应的私有密钥才能解密。算法代表:RSA,DSA。

3DES算法:3DES是三重数据加密,且可以逆推的一种算法方案。但由于3DES的算法是公开的,所以算法本身没有密钥可言,主要依靠唯一密钥来确保数据加解密的安全。到目前为止,仍没有人能破解3DES。

3DES加密类

CBC模式(需要指定IV加密向量)

package cn.appblog.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 sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

@SuppressWarnings({ "restriction" })
public class ThreeDES {
    private static final String IV = "1234567-";
    public static final String KEY = "AppBlog.CN";

    /**
     * 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 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 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);
    }
}

ECB模式(无需指定IV加密向量)

/**
 * 3DES的密钥必须是24位的byte数组
 * 随便拿一个String.getBytes()是不行的,会报如下错误
 *   java.security.InvalidKeyException: Invalid key length: 59 bytes
 *   解决方法有很多,①按密钥固定长度重新定义字符串;②先把字符串用Base64或者MD5加密,然后截取固定长度的字符转成byte数组;③字符串转成Byte数组,针对该数组进行修改,若长度过长则只截取一部分,若长度不够则补零
 *  
 * 加密结果的编码方式要一致
 * 从byte数组转成字符串,一般有两种方式,base64处理和十六进制处理。
 */
public class DESedeHelper {
    //定义加密算法,有DES、DESede(即3DES)、Blowfish
    private static final String Algorithm = "DESede";
    private static final String charset = "UTF-8";

    private final String PASSWORD_CRYPT_KEY;
    private DESedeHelper(String key) {
        this.PASSWORD_CRYPT_KEY = key;
    }

    public static DESedeHelper getInstance(String key) {
        return new DESedeHelper(key);
    }

    /**
     * 加密方法
     *
     * @param src 源数据的字节数组
     * @return
     */
    public String encryptMode(String src) {
        try {
            SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);    //生成密钥
            Cipher cipher = Cipher.getInstance(Algorithm);    //实例化负责加密/解密的Cipher工具类
            cipher.init(Cipher.ENCRYPT_MODE, deskey);    //初始化为加密模式
            return Base64.encodeBase64String(cipher.doFinal(src.getBytes(charset)));
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    /**
     * 解密函数
     *
     * @param src 密文的字节数组
     * @return
     */
    public String decryptMode(String src) {
        try {
            SecretKey deskey = new SecretKeySpec(build3DesKey(PASSWORD_CRYPT_KEY), Algorithm);
            Cipher cipher = Cipher.getInstance(Algorithm);
            cipher.init(Cipher.DECRYPT_MODE, deskey);    //初始化为解密模式

            return new String(cipher.doFinal(Base64.decodeBase64(src)), charset);
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    /*
     * 根据字符串生成密钥字节数组
     * @param keyStr 密钥字符串
     * @return
     * @throws UnsupportedEncodingException
     */
    public byte[] build3DesKey(String keyStr) throws UnsupportedEncodingException {
        byte[] key = new byte[24];    //声明一个位的字节数组,默认里面都是0
        byte[] temp = keyStr.getBytes(charset);    //将字符串转成字节数组

        /*
         * 执行数组拷贝
         * System.arraycopy(源数组,从源数组哪里开始拷贝,目标数组,拷贝多少位)
         */
        if (key.length > temp.length) {
            //如果temp不够位,则拷贝temp数组整个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, temp.length);
        } else {
            //如果temp大于位,则拷贝temp数组个长度的内容到key数组中
            System.arraycopy(temp, 0, key, 0, key.length);
        }
        return key;
    }
}

测试类

import java.net.URLEncoder;
import cn.appblog.util.ThreeDES;

public class ThreeDESTest {
    public static void main(String[] args) throws Exception {
        final String key = "AppBlog.CN";
        // 加密流程
        String homepage = "http://www.appblog.cn";
        ThreeDES threeDES = new ThreeDES();
        String telePhone_encrypt = "";
        homepageEncrypt = threeDES.encryptThreeDESECB(URLEncoder.encode(telePhone, "UTF-8"), key);
        System.out.println(homepageEncrypt);

        // 解密流程
        String homepageDecrypt = threeDES.decryptThreeDESECB(telePhone_encrypt, key);
        System.out.println("模拟代码解密: " + homepageDecrypt);
    }
}

注意:(1)3DES密钥的长度必须是8的倍数,可取24位或32位;(2)加密结果的byte数组转换为字符串,一般采用两种方式:Base64处理或十六进制处理。

版权声明:
作者:Joe.Ye
链接:https://www.appblog.cn/index.php/2023/03/19/implementing-3des-encryption-algorithm-in-java/
来源:APP全栈技术分享
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
打赏
海报
Java实现3DES加密算法
加密简介 单向加密:通过对数据进行摘要计算生成密文,密文不可逆推还原。算法代表:MD5,SHA 双向加密:与单向加密相反,可以把密文逆推还原成明文,双向加密……
<<上一篇
下一篇>>
文章目录
关闭
目 录