java安全架构____DES加密原理

来源:互联网 发布:茶叶网络连锁 编辑:程序博客网 时间:2024/05/19 18:42
转自李祥:http://blog.csdn.net/happylee6688/article/details/44455407

Java 加解密技术系列之 DES

标签: 加密解密技术des
5093人阅读 评论(1)收藏举报
本文章已收录于:
分类:
作者同类文章X

    目录(?)[-]

    1. 背景
    2. 概念
    3. 基本原理
    4. 主要流程
    5. 分组模式
    6. 代码实现
    7. 结束语



    前几篇文章讲的都是单向加密算法,其中涉及到了 BASE64、MD5、SHA、HMAC 等几个比较常见的加解密算法。这篇文章,以及后面几篇,打算介绍几个对称加密算法,比如:DES、3DES(TripleDES)、AES 等。那么,这篇文章主要是对 DES 大概讲一下。


    背景


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



    在对称加密算法中,使用的密钥只有一个,发收信双方都使用这个密钥对数据进行加密和解密,这就要求解密方事先必须知道加密密钥。对称加密算法的特点是算法公开、计算量小。不足之处是,交易双方都使用同样钥匙,安全性得不到保证。


    概念


    那么,什么是 DES?他是怎么来的?相信很多人都很感兴趣,因为以前在开发的时候,对进度的要求比较严,很多时候根本就没有时间来了解这些东西。因此,今天专门来研究研究这个东西。

    DES,全称为“Data Encryption Standard”,中文名为“数据加密标准”,是一种使用密钥加密的块算法。DES 算法为密码体制中的对称密码体制,又被称为美国数据加密标准,是 1972 年美国 IBM 公司研制的对称密码体制加密算法。 明文按 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,中文名“电子密码本模式”,是最古老、最简单的模式,将加密的数据分成若干组,每组的大小跟加密密钥长度相同。然后每组都用相同的密钥加密,比如 DES 算法,如果最后一个分组长度不够 64 位,要补齐 64 位。如图所示:



    • CBC模式

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



    • CFB模式

    CFB,中文名“加密反馈模式”,加密反馈模式克服了需要等待 8 个字节才能加密的缺点,它采用了分组密码作为流密码的密钥流生成器。他的特点是,每次加密的 Pi 和 Ci 不大于 64 位;加密算法和解密算法相同,不能适用于公钥算法;使用相同的密钥和初始向量的时候,相同明文使用 CFB 模式加密输出相同的密文;可以使用不同的初始化变量使相同的明文产生不同的密文,防止字典攻击;加密强度依赖于密钥长度;加密块长度过小时,会增加循环的数量,导致开销增加;加密块长度应时 8 位的整数倍(即字节为单位);一旦某位数据出错,会影响目前和其后 8 个块的数据。



    • OFB模式

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



    • CTR模式

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




    代码实现

    [java] view plain copy
    print?在CODE上查看代码片派生到我的代码片
    1. <span style="font-family:Comic Sans MS;"><span style="font-size:12px;">package com.sica.des;  
    2.   
    3. import com.google.common.base.Strings;  
    4. import sun.misc.BASE64Decoder;  
    5. import sun.misc.BASE64Encoder;  
    6.   
    7. import javax.crypto.Cipher;  
    8. import javax.crypto.KeyGenerator;  
    9. import javax.crypto.SecretKey;  
    10. import javax.crypto.SecretKeyFactory;  
    11. import javax.crypto.spec.DESKeySpec;  
    12. import java.security.InvalidKeyException;  
    13. import java.security.Key;  
    14. import java.security.NoSuchAlgorithmException;  
    15. import java.security.SecureRandom;  
    16. import java.security.spec.InvalidKeySpecException;  
    17.   
    18. /** 
    19.  * Created by xiang.li on 2015/2/28. 
    20.  * DES 加解密工具类 
    21.  * 
    22.  * <pre> 
    23.  * 支持 DES、DESede(TripleDES,就是3DES)、AES、Blowfish、RC2、RC4(ARCFOUR) 
    24.  * DES                  key size must be equal to 56 
    25.  * DESede(TripleDES)    key size must be equal to 112 or 168 
    26.  * AES                  key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available 
    27.  * Blowfish             key size must be multiple of 8, and can only range from 32 to 448 (inclusive) 
    28.  * RC2                  key size must be between 40 and 1024 bits 
    29.  * RC4(ARCFOUR)         key size must be between 40 and 1024 bits 
    30.  * 具体内容 需要关注 JDK Document http://.../docs/technotes/guides/security/SunProviders.html 
    31.  * </pre> 
    32.  */  
    33. public class DES {  
    34.     /** 
    35.      * 定义加密方式 
    36.      */  
    37.     private final static String KEY_DES = "DES";  
    38.     private final static String KEY_AES = "AES";    // 测试  
    39.   
    40.     /** 
    41.      * 全局数组 
    42.      */  
    43.     private final static String[] hexDigits = { "0""1""2""3""4""5",  
    44.             "6""7""8""9""a""b""c""d""e""f" };  
    45.   
    46.     /** 
    47.      * 初始化密钥 
    48.      * @return 
    49.      */  
    50.     public static String init() {  
    51.         return init(null);  
    52.     }  
    53.   
    54.     /** 
    55.      * 初始化密钥 
    56.      * @param seed 初始化参数 
    57.      * @return 
    58.      */  
    59.     public static String init(String seed) {  
    60.         SecureRandom secure = null;  
    61.         String str = "";  
    62.         try {  
    63.             if (null != secure) {  
    64.                 // 带参数的初始化  
    65.                 secure = new SecureRandom(decryptBase64(seed));  
    66.             } else {  
    67.                 // 不带参数的初始化  
    68.                 secure = new SecureRandom();  
    69.             }  
    70.   
    71.             KeyGenerator generator = KeyGenerator.getInstance(KEY_DES);  
    72.             generator.init(secure);  
    73.   
    74.             SecretKey key = generator.generateKey();  
    75.             str = encryptBase64(key.getEncoded());  
    76.         } catch (Exception e) {  
    77.             e.printStackTrace();  
    78.         }  
    79.         return str;  
    80.     }  
    81.   
    82.     /** 
    83.      * 转换密钥 
    84.      * @param key 密钥的字节数组 
    85.      * @return 
    86.      */  
    87.     private static Key byteToKey(byte[] key) {  
    88.         SecretKey secretKey = null;  
    89.         try {  
    90.             DESKeySpec dks = new DESKeySpec(key);  
    91.             SecretKeyFactory factory = SecretKeyFactory.getInstance(KEY_DES);  
    92.             secretKey = factory.generateSecret(dks);  
    93.   
    94.             // 当使用其他对称加密算法时,如AES、Blowfish等算法时,用下述代码替换上述三行代码  
    95. //            secretKey = new SecretKeySpec(key, KEY_DES);  
    96.         } catch (InvalidKeyException e) {  
    97.             e.printStackTrace();  
    98.         } catch (NoSuchAlgorithmException e) {  
    99.             e.printStackTrace();  
    100.         } catch (InvalidKeySpecException e) {  
    101.             e.printStackTrace();  
    102.         }  
    103.         return secretKey;  
    104.     }  
    105.   
    106.     /** 
    107.      * DES 解密 
    108.      * @param data 需要解密的字符串 
    109.      * @param key 密钥 
    110.      * @return 
    111.      */  
    112.     public static String decryptDES(String data, String key) {  
    113.         // 验证传入的字符串  
    114.         if (Strings.isNullOrEmpty(data)) {  
    115.             return "";  
    116.         }  
    117.         // 调用解密方法完成解密  
    118.         byte[] bytes = decryptDES(hexString2Bytes(data), key);  
    119.         // 将得到的字节数组变成字符串返回  
    120.         return new String(bytes);  
    121.     }  
    122.   
    123.     /** 
    124.      * DES 解密 
    125.      * @param data 需要解密的字节数组 
    126.      * @param key 密钥 
    127.      * @return 
    128.      */  
    129.     public static byte[] decryptDES(byte[] data, String key) {  
    130.         byte[] bytes = null;  
    131.         try {  
    132.             Key k = byteToKey(decryptBase64(key));  
    133.             Cipher cipher = Cipher.getInstance(KEY_DES);  
    134.             cipher.init(Cipher.DECRYPT_MODE, k);  
    135.             bytes = cipher.doFinal(data);  
    136.         } catch (Exception e) {  
    137.             e.printStackTrace();  
    138.         }  
    139.         return bytes;  
    140.     }  
    141.   
    142.     /** 
    143.      * DES 加密 
    144.      * @param data 需要加密的字符串 
    145.      * @param key 密钥 
    146.      * @return 
    147.      */  
    148.     public static String encryptDES(String data, String key) {  
    149.         // 验证传入的字符串  
    150.         if (Strings.isNullOrEmpty(data)) {  
    151.             return "";  
    152.         }  
    153.         // 调用加密方法完成加密  
    154.         byte[] bytes = encryptDES(data.getBytes(), key);  
    155.         // 将得到的字节数组变成字符串返回  
    156.         return byteArrayToHexString(bytes);  
    157.     }  
    158.   
    159.     /** 
    160.      * DES 加密 
    161.      * @param data 需要加密的字节数组 
    162.      * @param key 密钥 
    163.      * @return 
    164.      */  
    165.     public static byte[] encryptDES(byte[] data, String key) {  
    166.         byte[] bytes = null;  
    167.         try {  
    168.             Key k = byteToKey(decryptBase64(key));  
    169.             Cipher cipher = Cipher.getInstance(KEY_DES);  
    170.             cipher.init(Cipher.ENCRYPT_MODE, k);  
    171.             bytes = cipher.doFinal(data);  
    172.         } catch (Exception e) {  
    173.             e.printStackTrace();  
    174.         }  
    175.         return bytes;  
    176.     }  
    177.   
    178.   
    179.     /** 
    180.      * BASE64 解密 
    181.      * @param key 需要解密的字符串 
    182.      * @return 字节数组 
    183.      * @throws Exception 
    184.      */  
    185.     public static byte[] decryptBase64(String key) throws Exception {  
    186.         return (new BASE64Decoder()).decodeBuffer(key);  
    187.     }  
    188.   
    189.     /** 
    190.      * BASE64 加密 
    191.      * @param key 需要加密的字节数组 
    192.      * @return 字符串 
    193.      * @throws Exception 
    194.      */  
    195.     public static String encryptBase64(byte[] key) throws Exception {  
    196.         return (new BASE64Encoder()).encodeBuffer(key);  
    197.     }  
    198.   
    199.     /** 
    200.      * 将一个字节转化成十六进制形式的字符串 
    201.      * @param b 字节数组 
    202.      * @return 字符串 
    203.      */  
    204.     private static String byteToHexString(byte b) {  
    205.         int ret = b;  
    206.         //System.out.println("ret = " + ret);  
    207.         if (ret < 0) {  
    208.             ret += 256;  
    209.         }  
    210.         int m = ret / 16;  
    211.         int n = ret % 16;  
    212.         return hexDigits[m] + hexDigits[n];  
    213.     }  
    214.   
    215.     /** 
    216.      * 转换字节数组为十六进制字符串 
    217.      * @param bytes 字节数组 
    218.      * @return 十六进制字符串 
    219.      */  
    220.     private static String byteArrayToHexString(byte[] bytes) {  
    221.         StringBuffer sb = new StringBuffer();  
    222.         for (int i = 0; i < bytes.length; i++) {  
    223.             sb.append(byteToHexString(bytes[i]));  
    224.         }  
    225.         return sb.toString();  
    226.     }  
    227.   
    228.   
    229.     /** 
    230.      * 转换十六进制字符串为字节数组 
    231.      * @param hexstr 十六进制字符串 
    232.      * @return 
    233.      */  
    234.     public static byte[] hexString2Bytes(String hexstr) {  
    235.         byte[] b = new byte[hexstr.length() / 2];  
    236.         int j = 0;  
    237.         for (int i = 0; i < b.length; i++) {  
    238.             char c0 = hexstr.charAt(j++);  
    239.             char c1 = hexstr.charAt(j++);  
    240.             b[i] = (byte) ((parse(c0) << 4) | parse(c1));  
    241.         }  
    242.         return b;  
    243.     }  
    244.   
    245.     /** 
    246.      * 转换字符类型数据为整型数据 
    247.      * @param c 字符 
    248.      * @return 
    249.      */  
    250.     private static int parse(char c) {  
    251.         if (c >= 'a')  
    252.             return (c - 'a' + 10) & 0x0f;  
    253.         if (c >= 'A')  
    254.             return (c - 'A' + 10) & 0x0f;  
    255.         return (c - '0') & 0x0f;  
    256.     }  
    257.   
    258.     /** 
    259.      * 测试方法 
    260.      * @param args 
    261.      */  
    262.     public static void main(String[] args) {  
    263.         String key = DES.init();  
    264.         System.out.println("DES密钥:\n" + key);  
    265.   
    266.         String word = "123";  
    267.           
    268.   
    269.         String encWord = encryptDES(word, key);  
    270.   
    271.         System.out.println(word + "\n加密后:\n" + encWord);  
    272.         System.out.println(word + "\n解密后:\n" + decryptDES(encWord, key));  
    273.     }  
    274. }</span><span style="font-size: 14px;">  
    275. </span></span>  


    结束语


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


    4
    0
     
     

    我的同类文章

    http://blog.csdn.net
    • Java 加解密技术系列之 总结2015-04-27
    • Java 加解密技术系列之 RSA2015-04-23
    • Java 加解密技术系列之 AES2015-03-20
    • Java 加解密技术系列之 HMAC2015-02-27
    • Java 加解密技术系列之 MD52015-02-26
    • Java 加解密技术系列之 DH2015-04-24
    • Java 加解密技术系列之 PBE2015-03-26
    • Java 加解密技术系列之 3DES2015-03-19
    • Java 加解密技术系列之 SHA2015-02-27
    • Java 加解密技术系列之 BASE642015-02-26
    0 0