Java 加解密技术系列之 DES

前几篇文章讲的都是单向加密算法。当中涉及到了 BASE64、MD5、SHA、HMAC 等几个比較常见的加解密算法。

这篇文章,以及后面几篇。打算介绍几个对称加密算法。比方:DES、3DES(TripleDES)、AES 等。那么,这篇文章主要是对 DES 大概讲一下。

背景

在讨论 DES 之前。首先了解一下什么是对称加密算法吧。对于对称加密算法,他应用的时间比較早。技术相对来说比較成熟,在对称加密算法中。数据发信方将明文(原始数据)和加密密钥一起经过特殊加密算法处理后,使其变成复杂的加密密文发送出去。收信方收到密文后,若想解读原文。则须要使用加密用过的密钥及同样算法的逆算法对密文进行解密,才干使其恢复成可读明文。

在对称加密算法中,使用的密钥仅仅有一个。发收信两方都使用这个密钥对数据进行加密和解密。这就要求解密方事先必须知道加密密钥。

对称加密算法的特点是算法公开、计算量小。不足之处是,交易两方都使用相同钥匙,安全性得不到保证。

概念

那么,什么是 DES?他是怎么来的?相信非常多人都非常感兴趣。由于曾经在开发的时候,对进度的要求比較严,非常多时候根本就没有时间来了解这些东西。

因此,今天专门来研究研究这个东西。

DES,全称为“Data Encryption Standard”,中文名为“数据加密标准”。是一种使用密钥加密的块算法。DES 算法为password体制中的对称password体制。又被称为美国数据加密标准。是 1972 年美国 IBM 公司研制的对称password体制加密算法。

明文按 64 位进行分组,密钥长 64 位,密钥其实是 56 位參与 DES 运算(第8、16、24、32、40、48、56、64
位是校验位, 使得每一个密钥都有奇数个 1)分组后的明文组和 56 位的密钥按位替代或交换的方法形成密文组的加密方法。

基本原理

入口參数有三个:key、data、mode。key 为加密解密使用的密钥,data 为加密 解密的数据。mode 为其工作模式。当模式为加密模式时,明文依照 64 位进行分组。形成明文组。key 用于对数据加密,当模式为解密模式时。key 用于对数据解密。

实际运用中,密钥仅仅用到了
64 位中的 56 位,这样才具有高的安全性。

主要流程

DES 算法把 64 位的明文输入块变为 64 位的密文输出块。它所使用的密钥也是 64 位。其算法主要分为两步:

  • 初始置换

其功能是把输入的 64 位数据块按位又一次组合,并把输出分为 L0、R0 两部分。每部分各长 32 位,其置换规则为将输入的第 58 位换到第一位,第 50 位换到第 2 位 …… 依此类推,最后一位是原来的第 7 位。L0、R0 则是换位输出后的两部分。L0 是输出的左 32 位,R0 是右  32 位,例:设置换前的输入值为 D1 D2 D3 …… D64,则经过初始置换后的结果为:L0 = D58 D50 …… D8;R0 = D57
D49 …… D7。

  • 逆置换

经过 16 次迭代运算后。得到 L16、R16。将此作为输入,进行逆置换,逆置换正好是初始置换的逆运算。由此即得到密文输出。

整个算法 的主流程图例如以下:

分组模式

  • ECB模式

ECB。中文名“电子password本模式”。是最古老、最简单的模式,将加密的数据分成若干组,每组的大小跟加密密钥长度同样。

然后每组都用同样的密钥加密,比方 DES 算法。假设最后一个分组长度不够 64 位,要补齐 64 位。

如图所看到的:

  • CBC模式

CBC。中文名“加密块链模式”,与 ECB 模式最大的不同是增加了初始向量。他的特点是,每次加密的密文长度为 64位 ( 8 个字节),当同样的明文使用同样的密钥和初始向量的时候 CBC 模式总是产生同样的密文。

  • CFB模式

CFB,中文名“加密反馈模式”。加密反馈模式克服了须要等待 8 个字节才干加密的缺点。它採用了分组password作为流password的密钥流生成器。

他的特点是。每次加密的 Pi 和 Ci 不大于 64 位;加密算法和解密算法同样。不能适用于公钥算法。使用同样的密钥和初始向量的时候。同样明文使用 CFB 模式加密输出同样的密文。能够使用不同的初始化变量使同样的明文产生不同的密文。防止字典攻击。加密强度依赖于密钥长度;加密块长度过小时,会添加循环的数量,导致开销添加;加密块长度应时
8 位的整数倍(即字节为单位);一旦某位数据出错,会影响眼下和其后 8 个块的数据。

  • OFB模式

OFB,中文名“输出反馈模式”,与 CFB 模式不同之处在于, 加密位移寄存器与密文无关了,仅与加密 key 和加密算法有关,做法是不再把密文输入到加密移位寄存器,而是把输出的分组密文(Oi)输入到一位寄存器。由于密文没有參与链操作。所以使得 OFB 模式更easy受到攻击;不会进行错误传播,某位密文错误发生,仅仅会影响该位相应的明文,而不会影响别的位;不是自同步的。假设加密和解密两个操作失去同步,那么系统须要又一次初始化;每次又一次同步时,应使用不同的初始向量。能够避免产生同样的比特流。避免“已知明文”攻击。

  • CTR模式

CTR。中文名“计数模式”,是对一系列输入数据块(称为计数)进行加密,产生一系列的输出块,输出块与明文异或得到密文。对于最后的数据块。可能是长 u 位的局部数据块,这 u 位就将用于异或操作,而剩下的 b-u 位将被丢弃(b表示块的长度)。

代码实现

<span style="font-family:Comic Sans MS;"><span style="font-size:12px;">package com.sica.des;

import com.google.common.base.Strings;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

/**
 * Created by xiang.li on 2015/2/28.
 * DES 加解密工具类
 *
 * <pre>
 * 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR)
 * DES                  key size must be equal to 56
 * DESede(TripleDES)    key size must be equal to 112 or 168
 * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
 * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
 * RC2                  key size must be between 40 and 1024 bits
 * RC4(ARCFOUR)         key size must be between 40 and 1024 bits
 * 详细内容 须要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html
 * </pre>
 */
public class DES {
    /**
     * 定义加密方式
     */
    private final static String KEY_DES = "DES";
    private final static String KEY_AES = "AES";    // 測试

    /**
     * 全局数组
     */
    private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };

    /**
     * 初始化密钥
     * @return
     */
    public static String init() {
        return init(null);
    }

    /**
     * 初始化密钥
     * @param seed 初始化參数
     * @return
     */
    public static String init(String seed) {
        SecureRandom secure = null;
        String str = "";
        try {
            if (null != secure) {
                // 带參数的初始化
                secure = new SecureRandom(decryptBase64(seed));
            } else {
                // 不带參数的初始化
                secure = new SecureRandom();
            }

            KeyGenerator generator = KeyGenerator.getInstance(KEY_DES);
            generator.init(secure);

            SecretKey key = generator.generateKey();
            str = encryptBase64(key.getEncoded());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }

    /**
     * 转换密钥
     * @param key 密钥的字节数组
     * @return
     */
    private static Key byteToKey(byte[] key) {
        SecretKey secretKey = null;
        try {
            DESKeySpec dks = new DESKeySpec(key);
            SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DES);
            secretKey = factory.generateSecret(dks);

            // 当使用其它对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码
//            secretKey = new SecretKeySpec(key, KEY_DES);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return secretKey;
    }

    /**
     * DES 解密
     * @param data 须要解密的字符串
     * @param key 密钥
     * @return
     */
    public static String decryptDES(String data, String key) {
        // 验证传入的字符串
        if (Strings.isNullOrEmpty(data)) {
            return "";
        }
        // 调用解密方法完毕解密
        byte[] bytes = decryptDES(hexString2Bytes(data), key);
        // 将得到的字节数组变成字符串返回
        return new String(bytes);
    }

    /**
     * DES 解密
     * @param data 须要解密的字节数组
     * @param key 密钥
     * @return
     */
    public static byte[] decryptDES(byte[] data, String key) {
        byte[] bytes = null;
        try {
            Key k = byteToKey(decryptBase64(key));
            Cipher cipher = Cipher.getInstance(KEY_DES);
            cipher.init(Cipher.DECRYPT_MODE, k);
            bytes = cipher.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * DES 加密
     * @param data 须要加密的字符串
     * @param key 密钥
     * @return
     */
    public static String encryptDES(String data, String key) {
        // 验证传入的字符串
        if (Strings.isNullOrEmpty(data)) {
            return "";
        }
        // 调用加密方法完毕加密
        byte[] bytes = encryptDES(data.getBytes(), key);
        // 将得到的字节数组变成字符串返回
        return byteArrayToHexString(bytes);
    }

    /**
     * DES 加密
     * @param data 须要加密的字节数组
     * @param key 密钥
     * @return
     */
    public static byte[] encryptDES(byte[] data, String key) {
        byte[] bytes = null;
        try {
            Key k = byteToKey(decryptBase64(key));
            Cipher cipher = Cipher.getInstance(KEY_DES);
            cipher.init(Cipher.ENCRYPT_MODE, k);
            bytes = cipher.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytes;
    }

    /**
     * BASE64 解密
     * @param key 须要解密的字符串
     * @return 字节数组
     * @throws Exception
     */
    public static byte[] decryptBase64(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key);
    }

    /**
     * BASE64 加密
     * @param key 须要加密的字节数组
     * @return 字符串
     * @throws Exception
     */
    public static String encryptBase64(byte[] key) throws Exception {
        return (new BASE64Encoder()).encodeBuffer(key);
    }

    /**
     * 将一个字节转化成十六进制形式的字符串
     * @param b 字节数组
     * @return 字符串
     */
    private static String byteToHexString(byte b) {
        int ret = b;
        //System.out.println("ret = " + ret);
        if (ret < 0) {
            ret += 256;
        }
        int m = ret / 16;
        int n = ret % 16;
        return hexDigits[m] + hexDigits[n];
    }

    /**
     * 转换字节数组为十六进制字符串
     * @param bytes 字节数组
     * @return 十六进制字符串
     */
    private static String byteArrayToHexString(byte[] bytes) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < bytes.length; i++) {
            sb.append(byteToHexString(bytes[i]));
        }
        return sb.toString();
    }

    /**
     * 转换十六进制字符串为字节数组
     * @param hexstr 十六进制字符串
     * @return
     */
    public static byte[] hexString2Bytes(String hexstr) {
        byte[] b = new byte[hexstr.length() / 2];
        int j = 0;
        for (int i = 0; i < b.length; i++) {
            char c0 = hexstr.charAt(j++);
            char c1 = hexstr.charAt(j++);
            b[i] = (byte) ((parse(c0) << 4) | parse(c1));
        }
        return b;
    }

    /**
     * 转换字符类型数据为整型数据
     * @param c 字符
     * @return
     */
    private static int parse(char c) {
        if (c >= ‘a‘)
            return (c - ‘a‘ + 10) & 0x0f;
        if (c >= ‘A‘)
            return (c - ‘A‘ + 10) & 0x0f;
        return (c - ‘0‘) & 0x0f;
    }

    /**
     * 測试方法
     * @param args
     */
    public static void main(String[] args) {
        String key = DES.init();
        System.out.println("DES密钥:\n" + key);

        String word = "123";

        String encWord = encryptDES(word, key);

        System.out.println(word + "\n加密后:\n" + encWord);
        System.out.println(word + "\n解密后:\n" + decryptDES(encWord, key));
    }
}</span><span style="font-size: 14px;">
</span></span>

结束语

到这里。这篇文章也就差点儿相同要结束了,希望以上的内容对各位看官有稍许的帮助,哪怕一点也好。事实上,在日常的开发中,假设不是进度控制的特别严格。对于这些原理性的东西,我们还是需要知道的,对于那些细节的东西,能够不用死记硬背。有网的话,随用随查就能够了。但这个前提是,原理性的东西必需要懂,知道了原理。就会有解决思路,有了思路,解决这个问题是迟早的事,细节嘛,不用那么纠结,做的时候考虑到即可了,毕竟时间是有限的。

时间: 2024-10-10 21:37:16

Java 加解密技术系列之 DES的相关文章

5.Java 加解密技术系列之 DES

Java 加解密技术系列之 DES 序 背景 概念 基本原理 主要流程 分组模式 代码实现 结束语 序 前 几篇文章讲的都是单向加密算法,其中涉及到了 BASE64.MD5.SHA.HMAC 等几个比较常见的加解密算法.这篇文章,以及后面几篇,打算介绍几个对称加密算法,比如:DES.3DES(TripleDES).AES 等.那么,这篇文章主要是对 DES 大概讲一下. 背景 在 讨论 DES 之前,首先了解一下什么是对称加密算法吧.对于对称加密算法,他应用的时间比较早,技术相对来说比较成熟,在

Java 加解密技术系列文章

Java 加解密技术系列之 总结 Java 加解密技术系列之 DH Java 加解密技术系列之 RSA Java 加解密技术系列之 PBE Java 加解密技术系列之 AES Java 加解密技术系列之 3DES Java 加解密技术系列之 DES Java 加解密技术系列之 HMAC Java 加解密技术系列之 SHA Java 加解密技术系列之 MD5 Java 加解密技术系列之 BASE64

10.Java 加解密技术系列之 DH

Java 加解密技术系列之 DH 序 概念 原理 代码实现 结果 结束语 序 上一篇文章中简单的介绍了一种非对称加密算法 — — RSA,今天这篇文章,继续介绍另一种非对称加密算法 — — DH.当然,可能有很多人对这种加密算法并不是很熟悉,不过没关系,希望今天这篇文章能帮助你熟悉他. 原理 整个通信过程中g.g^a.g^b是公开的,但由于g.a.b都是整数,通过g和g^a得到a还是比较容易的,b也是如此,所以最终的“密钥”g^(a*b)还是可以被计算出来的.所以实际的过程还需要在基本原理上加入

8.Java 加解密技术系列之 PBE

Java 加解密技术系列之 PBE 序 概念 原理 代码实现 结束语 序 前 边的几篇文章,已经讲了几个对称加密的算法了,今天这篇文章再介绍最后一种对称加密算法 — — PBE,这种加密算法,对我的认知来说,并没有 DES.3DES.AES 那么流行,也不尽然,其实是我之前并没有这方面的需求,当然接触他的机会也就很少了,因此,可想而知,没听过显然在正常不过了. 概念 PBE,全称为“Password Base Encryption”,中文名“基于口令加密”,是一种基于密码的加密算法,其特点是使用

6. Java 加解密技术系列之 3DES

Java 加解密技术系列之 3DES 序 背景 概念 原理 代码实现 结束语 序 上一篇文章讲的是对称加密算法 — — DES,这篇文章打算在 DES 的基础上,继续多讲一点,也就是 3 重 DES — — Triple DES. 背景 至于 3DES 为什么会出现呢?其实,这个不难想到.由于 DES 是一种非常简便的加密算法,但是密钥长度比较短,计算量比较小,相对来说,比较容易被破解.因此,在 DES 的基础上,使用三重数据加密算法,对数据进行加密,这样来说,破解的概率就小了很多. 概念 3D

7.java 加解密技术系列之 AES

java 加解密技术系列之 AES 序 概念 原理 应用 代码实现 结束语 序 这篇文章继续介绍对称加密算法,至于今天的主角,不用说,也是个厉害的角色 — — AES.AES 的出现,就是为了来替代原先的 DES 标准.现在来说,AES 的用途还是非常广泛的. 概念 AES, 全称为“Advanced Encryption Standard”,中文名“高级加密标准”,在密码学中又称 Rijndael 加密法,是美国联邦政府采用的一种区块加密标准.AES 加密算法作为新一代的数据加密标准汇聚了强安

11.Java 加解密技术系列之 总结

Java 加解密技术系列之 总结 序 背景 分类 常用算法 原理 关于代码 结束语 序 上一篇文章中简单的介绍了第二种非对称加密算法 — — DH,这种算法也经常被叫做密钥交换协议,它主要是针对密钥的保护.同时,由于水平的限制,打算这个系列就到此为止了,这篇文章就算是一个总结吧,回顾一下这几个月来都写了些什么. 背景 其 实,在开始写这个系列之前,我对于 Java 的加解密也并不是那么了解.之所以要写这些文章,还主要是由于工作的原因.记得几个月以前,当时项目要做一个数字证书,证书的生成.存储.传

9.Java 加解密技术系列之 RSA

Java 加解密技术系列之 RSA 序 概念 工作流程 RSA 代码实现 加解密结果 结束语 序 距 离上一次写博客感觉已经很长时间了,先吐槽一下,这个月以来,公司一直在加班,又是发版.上线,又是新项目太紧,具体的就不多说了,想听我吐槽的小伙伴, 可以私信给我(*^__^*) .上一篇文章,已经把对称加密的算法讲完了.从今天开始,要说说非对称加密了.因为,非对称加密真的是太重要了,我们的日常生活中,都离不开非对称加密. 概念 在说 RSA 之前,首先聊聊什么是非对称加密.在讲对称加密的时候,就曾

1.Java 加解密技术系列之 BASE64

Java 加解密技术系列之 BASE64 序号 背景 正文 总结 序 这段时间,工作中 用到了 Java 的加解密技术,本着学习的态度,打算从这篇文章开始,详细的研究一番 Java 在加解密技术上有什么与众不同,同时,也想为大家或者自己留下点什么,一块分享这其中的“精髓”.需要说明的是,这个系列可能要持续一段时间,因为,加解 密的相关技术太多太多了,要搞明白这些着实不是一件容易的事. 背景 说到这个加解密技 术,之前一直没有机会研究这个东西,这次公司里的项目需要加解密的支持,因此有机会能够好好研