美文网首页
Java 实现 3DES 加密

Java 实现 3DES 加密

作者: 又语 | 来源:发表于2020-04-10 19:58 被阅读0次

    本文介绍 Java 语言实现 3DES 加密的方法。


    目录

    • 3DES 简介
    • 代码实现
      • CBC

    3DES 简介

    3DES,原名 Triple Data Encryption Algorithm,即 三重数据加密算法,缩写也为 TDEA。
    3DES 是对原版 DES 的改进,相当于对每个数据块应用 3 次 DES算法,是 DES 向 AES 过渡的加密算法。
    3DES 的加密过程:C=EK3(DK2(EK1(M)))
    3DES 的解密过程:M=DK1(EK2(DK3(C)))
    C 是密文,M 是明文,K 代表 DES 算法使用的密钥,EK() 代表 DES 算法的加密过程,DK() 代表 DES 算法的解密过程。


    代码实现

    CBC
    1. 添加 Bouncy Castle 依赖
    <dependency>
        <groupId>org.bouncycastle</groupId>
        <artifactId>bcprov-jdk15on</artifactId>
        <version>1.65</version>
    </dependency>
    
    1. 代码
    package tutorial.java.util;
    
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    import javax.crypto.*;
    import javax.crypto.spec.DESedeKeySpec;
    import javax.crypto.spec.IvParameterSpec;
    import java.security.*;
    import java.security.spec.InvalidKeySpecException;
    
    public class TripleDesUtils {
    
        /**
         * 算法名称
         */
        private static final String ALGORITHM_3DES = "DESEDE";
    
        private static final SecureRandom RANDOM = new SecureRandom();
    
        /**
         * 注意:
         * 1.CBC 模式下加解密 Cipher 初始化必须传入同一个 IvParameterSpec 实例参数
         * 2.IvParameterSpec 构造函数中参数字节数组长度必须是 8 位
         */
        private static final IvParameterSpec IV_PARAMETER_SPEC = new IvParameterSpec(RANDOM.generateSeed(8));
    
        public static byte[] encryptCbc(byte[] key, byte[] content, Padding padding) {
            // 添加一个安全供应商
            Security.addProvider(new BouncyCastleProvider());
            // 生成密钥
            try {
                Key desKey = keyGenerator(key);
                // 实例化一个 Cipher 对象用于完成加密操作
                Cipher cipher = Cipher.getInstance(ALGORITHM_3DES + "/CBC/" + padding.value);
                // 初始化 Cipher 对象,设置为加密模式
                cipher.init(Cipher.ENCRYPT_MODE, desKey, IV_PARAMETER_SPEC);
                return cipher.doFinal(content);
            } catch (InvalidKeyException e) {
                e.printStackTrace();
                throw new UnsupportedOperationException("Invalid Key");
            } catch (NoSuchAlgorithmException e) {
                throw new UnsupportedOperationException("No such algorithm");
            } catch (InvalidKeySpecException e) {
                throw new UnsupportedOperationException("Invalid key spec");
            } catch (NoSuchPaddingException e) {
                throw new UnsupportedOperationException("No such padding");
            } catch (BadPaddingException e) {
                throw new UnsupportedOperationException("Bad padding");
            } catch (IllegalBlockSizeException e) {
                throw new UnsupportedOperationException("Illegal block size");
            } catch (InvalidAlgorithmParameterException e) {
                throw new UnsupportedOperationException("Illegal algorithm parameter");
            }
        }
    
        public static byte[] decryptCbc(byte[] key, byte[] content, Padding padding) {
            try {
                // 生成密钥
                Key desKey = keyGenerator(key);
                // 实例化一个 Cipher 对象用于完成解密操作
                Cipher cipher = Cipher.getInstance(ALGORITHM_3DES + "/CBC/" + padding.value);
                // 初始化 Cipher 对象,设置为解密模式
                cipher.init(Cipher.DECRYPT_MODE, desKey, IV_PARAMETER_SPEC);
                return cipher.doFinal(content);
            } catch (NoSuchPaddingException e) {
                throw new UnsupportedOperationException("No such padding");
            } catch (NoSuchAlgorithmException e) {
                throw new UnsupportedOperationException("No such algorithm");
            } catch (InvalidKeyException e) {
                e.printStackTrace();
                throw new UnsupportedOperationException("Invalid Key");
            } catch (InvalidKeySpecException e) {
                throw new UnsupportedOperationException("Invalid key spec");
            } catch (BadPaddingException e) {
                throw new UnsupportedOperationException("Bad padding");
            } catch (IllegalBlockSizeException e) {
                throw new UnsupportedOperationException("Illegal block size");
            } catch (InvalidAlgorithmParameterException e) {
                throw new UnsupportedOperationException("Illegal algorithm parameter");
            }
        }
    
        /**
         * 生成 3DES 密钥对象
         *
         * @param key 密钥字节数组
         * @return 密钥对象
         * @throws InvalidKeyException      Key 无效
         * @throws NoSuchAlgorithmException 无相关算法
         * @throws InvalidKeySpecException  KeySepc 无效
         */
        private static Key keyGenerator(byte[] key)
                throws InvalidKeyException, NoSuchAlgorithmException, InvalidKeySpecException {
            DESedeKeySpec deSedeKeySpec = new DESedeKeySpec(key);
            // 创建一个密钥工厂,用于转换 DESKeySpec
            SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ALGORITHM_3DES);
            // 生成一个密钥并返回
            return secretKeyFactory.generateSecret(deSedeKeySpec);
        }
    
        public static enum Padding {
            NO_PADDING("NoPadding"),
            PKCS5_PADDING("PKCS5Padding");
    
            private String value;
    
            Padding(String value) {
                this.value = value;
            }
        }
    }
    
    1. 单元测试
    package tutorial.java.util;
    
    import org.junit.Assert;
    import org.junit.Test;
    
    import java.nio.charset.StandardCharsets;
    
    public class TripleDesUtilsTest {
    
        private void test(TripleDesUtils.Padding padding, String key, String content) {
            byte[] encryptResult = TripleDesUtils.encryptCbc(key.getBytes(StandardCharsets.UTF_8),
                    content.getBytes(StandardCharsets.UTF_8),
                    padding);
            byte[] decryptResult = TripleDesUtils.decryptCbc(key.getBytes(StandardCharsets.UTF_8),
                    encryptResult,
                    padding);
            Assert.assertEquals(content, new String(decryptResult, StandardCharsets.UTF_8));
        }
    
        @Test
        public void testCbcNoPadding() {
            // 密钥长度必须是 8 的倍数,最少 24 位
            String key = "123456781234567812345678";
            // 待加密原文长度必须是 8 的倍数
            String content = "12345678";
            test(TripleDesUtils.Padding.NO_PADDING, key, content);
        }
    
        @Test
        public void testCbcPkcs5Padding() {
            // 密钥长度必须是 8 的倍数,最少 24 位
            String key = "123456781234567812345678";
            String content = "123456789";
            test(TripleDesUtils.Padding.PKCS5_PADDING, key, content);
        }
    }
    

    相关文章

      网友评论

          本文标题:Java 实现 3DES 加密

          本文链接:https://www.haomeiwen.com/subject/fsldmhtx.html