Java 加密解密

Java  加密解密基础
密码学是研究编制密码和破译密码的技术科学。研究密码变化的客观规律,应用于编制密码以保守通信秘密的,称为编码学;应用于破译密码以获取通信情报的,称为破译学,总称密码学。
密码学常用术语
明文: 待加密数据。
密文: 明文经过加密后数据。
加密: 将明文转换为密文的过程。
加密算法: 将明文转换为密文的转换算法。
加密密钥: 通过加密算法进行加密操作的密钥。
解密: 将密文转换为铭文的过程。
解密算法: 将密文转换为明文的转换算法。
解密密钥: 通过解密短发进行解密操作的密钥。
密码学分类
1.按时间分
a.古典密码:以字符为基本加密单元。
b.现代密码:以信息块为基本加密单元。
2按保密内容的算法划分
a.受限制算法:算法的保密性基于保持算法的秘密。
b.基于密钥算法:算法的保密性基于对密钥的保密。
3.按密钥体制划分
a.对称密码体制:也叫单钥或私钥密码体制,加密过程与解密过程使用同一套密钥。对应的算法就是对称加密算法,例如DES,AES。
b.非对称密码体制:也叫双钥或公钥密码体制,加密过程与解密过程使用不同的密钥。对应的算法就是非对称加密算法,例如RSA。
4.按明文处理方式划分
a.流密码:也称为序列密码,加密时每次加密一位或者一个字节的明文。例如RC4算法。
b.分组密码:加密时将明文分成固定长度的组,用同一个密钥和算法对每一组进行加密输出也是固定长度的明文。当最后一组大小不满足指定的分组大小时,
有两种处理模式:
无填充模式,直接对剩余数据进行加密,此组加密后大小与剩余数据有关;
有填充模式,对于不满足指定长度分组的进行数据填充;如果恰巧最后一组数据与指定分组大小相同,那么直接添加一个指定大小的分组;填充的最后一个字节记录了填充的字节数。
分组密码工作模式简介
1.电子密码本模--ECB
将明文的各个分组独立的使用相同的密钥进行加密,这种方式加密时各分组的加密独立进行互不干涉,因而可并行进行。同样因为各分组独立加密的缘故,相同的明文分组加密之后具有相同的密文。该模式容易暴露明文分组的统计规律和结构特征。不能防范替换攻击。
其实照实现来看,ECB的过程只是把明文进行分组,然后分别加密,最后串在一起的过程。当消息长度超过一个分组时,不建议使用该模式。在每个分组中增加随机位(如128位分组中96位为有效明文,32位的随机数)则可稍微提高其安全性,但这样无疑造成了加密过程中数据的扩张。
优点:
1.简单;
2.有利于并行计算;
3.误差不会被传送;
缺点:
1.不能隐藏明文的模式;
2.可能对明文进行主动攻击;
2.密码分组链接模--CBC
需要一个初始化向量IV,第一组明文与初始化向量进行异或运算后再加密,以后的每组明文都与前一组的密文进行异或运算后再加密。IV 不需要保密,它可以明文形式与密文一起传送。
优点:
1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
缺点:
1.不利于并行计算;
2.误差传递;
3.需要初始化向量IV
3.密文反馈模式--CFB
需要一个初始化向量IV ,加密后与第一个分组明文进行异或运算产生第一组密文,然后对第一组密文加密后再与第二组明文进行异或运算缠身第二组密文,一次类推,直到加密完毕。
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.误差传送:一个明文单元损坏影响多个单元;
3.唯一的IV;
4. 输出反馈模式--OFB
需要一个初始化向量IV ,加密后得到第一次加密数据,此加密数据与第一个分组明文进行异或运算产生第一组密文,然后对第一次加密数据进行第二次加密,得到第二次加密数据,第二次加密数据再与第二组明文进行异或运算产生第二组密文,一次类推,直到加密完毕。
优点:
1.隐藏了明文模式;
2.分组密码转化为流模式;
3.可以及时加密传送小于分组的数据;
缺点:
1.不利于并行计算;
2.对明文的主动攻击是可能的;
3.误差传送:一个明文单元损坏影响多个单元;
5.计数器模式--CTR
使用计数器,计数器初始值加密后与第一组明文进行异或运算产生第一组密文,
计数器增加,然后,加密后与下一组明文进行异或运算产生下一组密文,以此类推,直到加密完毕
优点:
1.可并行计算;
2.安全性至少与CBC 模式一样好;
3.加密与解仅涉及密码算法的加密;
缺点:
1.没有错误传播,不易确保数据完整性;
分组密码填充方式简介
PKCS5 :填充字符串由一个值为5的字节序列组成,每个字节填充该字节序列的长度。明确定义Block的大小是8位
PKCS7 :填充字符串由一个值为7的字节序列组成,每个字节填充该字节序列的长度。对于块的大小是不确定的,可以在1-255之间
ISO10126:填充字符串由一个字节序列组成,此字节序列的最后一个字节填充字节序列的长度,其余字节填充随机数据。

ava byte数组与十六进制字符串互转
Java中byte用二进制表示占用8位,而我们知道16进制的每个字符需要用4位二进制位来表示。
所以我们就可以把每个byte转换成两个相应的16进制字符,即把byte的高4位和低4位分别转换成相应的16进制字符H和L,并组合起来得到byte转换到16进制字符串的结果new String(H) + new String(L)。
同理,相反的转换也是将两个16进制字符转换成一个byte,原理同上。
根据以上原理,我们就可以将byte[] 数组转换为16进制字符串了,当然也可以将16进制字符串转换为byte[]数组了。 
Hex类代码如下:

    package base.codec; 

    /**

     * reference apache commons <a

     * href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a>

     * 

     * @author Aub

     * 

     */

    publicclass Hex { 

    /**

         * 用于建立十六进制字符的输出的小写字符数组

         */

    privatestaticfinalchar[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5', 

    '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 

    /**

         * 用于建立十六进制字符的输出的大写字符数组

         */

    privatestaticfinalchar[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', 

    '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 

    /**

         * 将字节数组转换为十六进制字符数组

         * 

         * @param data

         *            byte[]

         * @return 十六进制char[]

         */

    publicstaticchar[] encodeHex(byte[] data) { 

    return encodeHex(data, true); 

        } 

    /**

         * 将字节数组转换为十六进制字符数组

         * 

         * @param data

         *            byte[]

         * @param toLowerCase

         *            <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式

         * @return 十六进制char[]

         */

    publicstaticchar[] encodeHex(byte[] data, boolean toLowerCase) { 

    return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); 

        } 

    /**

         * 将字节数组转换为十六进制字符数组

         * 

         * @param data

         *            byte[]

         * @param toDigits

         *            用于控制输出的char[]

         * @return 十六进制char[]

         */

    protectedstaticchar[] encodeHex(byte[] data, char[] toDigits) { 

    int l = data.length; 

    char[] out = newchar[l << 1]; 

    // two characters form the hex value.

    for (int i = 0, j = 0; i < l; i++) { 

                out[j++] = toDigits[(0xF0 & data[i]) >>> 4]; 

                out[j++] = toDigits[0x0F & data[i]]; 

            } 

    return out; 

        } 

    /**

         * 将字节数组转换为十六进制字符串

         * 

         * @param data

         *            byte[]

         * @return 十六进制String

         */

    publicstatic String encodeHexStr(byte[] data) { 

    return encodeHexStr(data, true); 

        } 

    /**

         * 将字节数组转换为十六进制字符串

         * 

         * @param data

         *            byte[]

         * @param toLowerCase

         *            <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式

         * @return 十六进制String

         */

    publicstatic String encodeHexStr(byte[] data, boolean toLowerCase) { 

    return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER); 

        } 

    /**

         * 将字节数组转换为十六进制字符串

         * 

         * @param data

         *            byte[]

         * @param toDigits

         *            用于控制输出的char[]

         * @return 十六进制String

         */

    protectedstatic String encodeHexStr(byte[] data, char[] toDigits) { 

    returnnew String(encodeHex(data, toDigits)); 

        } 

    /**

         * 将十六进制字符数组转换为字节数组

         * 

         * @param data

         *            十六进制char[]

         * @return byte[]

         * @throws RuntimeException

         *             如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常

         */

    publicstaticbyte[] decodeHex(char[] data) { 

    int len = data.length; 

    if ((len & 0x01) != 0) { 

    thrownew RuntimeException("Odd number of characters."); 

            } 

    byte[] out = newbyte[len >> 1]; 

    // two characters form the hex value.

    for (int i = 0, j = 0; j < len; i++) { 

    int f = toDigit(data[j], j) << 4; 

                j++; 

                f = f | toDigit(data[j], j); 

                j++; 

                out[i] = (byte) (f & 0xFF); 

            } 

    return out; 

        } 

    /**

         * 将十六进制字符转换成一个整数

         * 

         * @param ch

         *            十六进制char

         * @param index

         *            十六进制字符在字符数组中的位置

         * @return 一个整数

         * @throws RuntimeException

         *             当ch不是一个合法的十六进制字符时,抛出运行时异常

         */

    protectedstaticint toDigit(char ch, int index) { 

    int digit = Character.digit(ch, 16); 

    if (digit == -1) { 

    thrownew RuntimeException("Illegal hexadecimal character " + ch 

                        + " at index " + index); 

            } 

    return digit; 

        } 

    publicstaticvoid main(String[] args) { 

            String srcStr = "待转换字符串"; 

            String encodeStr = encodeHexStr(srcStr.getBytes()); 

            String decodeStr = new String(decodeHex(encodeStr.toCharArray())); 

            System.out.println("转换前:" + srcStr); 

            System.out.println("转换后:" + encodeStr); 

            System.out.println("还原后:" + decodeStr); 

        } 

    }

参考org.apache.commons.codec.binary.Hex
下载地址:http://commons.apache.org/codec/download_codec.cgi

Java BASE64加密解密

Base64是网络 上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。Base64编码可用于在 HTTP环境下传递较长的标识信息。例如,在Java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

RFC2045还规定每行位76个字符,每行末尾需添加一个回车换行符,即便是最后一行不够76个字符,也要加换行符。

实现原理

Base64实际上是对二进制码做分组转换操作

1.每3个8位二进制码位一组,转换为4个6位二进制码为一组(不足6位时地位补0)。3个8位二进制码和4个6位二进制码长度都是24位。

2.对获得的4个6位二进制码补位,每个6位二进制码添加两位高位0,组成4个8位二进制码。

3.将获得的4个8位二进制码转换为4个十进制码。

4.将获得的十进制码转换为Base64字符表中对应的字符。


字符串“A”,进行Base64编码,如下所示:

字符                A

ASCII码           65

二进制码          01000001

4个6位二进制码 010000          010000

4个8位二进制码 00010000       00010000

十进制码          16                 16

字符表映射码     Q                  Q                   =                 =

字符串“A”经过Base64编码后得到字符串“QQ==”。

结果出现了两个等号。很显然,当原文的二进制码长度不足24位,最终转换为十进制时也不足4项,这时就需要用等号补位。

将Base64编码后的字符串最多会有2个等号,这时因为:

余数 = 原文字节数 MOD 3。

字符串“密”,对其使用UTF-8编码等到Byte数组{-27,-81,-122},

字符                密

UTF-8编码        -27                -81               -122

二进制码          11100101       10101111       10000110

4个6位二进制码 111001          011010           111110          000110

4个8位二进制码 00111001       00011010       00111110       00000110

十进制码          57                 26                  62                6

字符表映射码     5                   a                   +                 G

字符串“密”经过Base64编码后得到字符串“5a+G”。


对照表:

java实现

1.JDK实现:

import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; /** *  BASE64加密解密 */ public class BASE64 { /** * 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); } public static void main(String[]  args) throws Exception { String data =  BASE64.encryptBASE64("http://aub.iteye.com/".getBytes());  System.out.println("加密前:"+data); byte[] byteArray =  BASE64.decryptBASE64(data); System.out.println("解密后:"+new  String(byteArray)); } } 

注意,sun.misc包是Sun公司提供给内部使用的专用API,在java API文档中我们看不到任何有关BASE64影子,不建议使用。


2.Apache的实现:(建议使用这种方式,当然,自己实现也可以)

参考:org.apache.commons.codec.binary.Base64
下载地址:http://commons.apache.org/codec/download_codec.cgi

Apache还提供了,非标准的实现方式:

1.不再添加回车符。

2.Url Base64,也就是将“+”和“\”换成了“-”和“_”符号,且不适用补位。


Java 加密解密之消息摘要算法(MD5 SHA MAC)

消息摘要

消 息摘要(Message Digest)又称为数字摘要(Digital  Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通 过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。消息摘要采用单向Hash 函数将需加密的明文"摘要"成一串128bit的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。

HASH函数的抗冲突性使得如果一段明文稍有变化,哪怕只更改该段落的一个字母,通过哈希算法作用后都将产生不同的值。而HASH算法的单向性使得要找到到哈希值相同的两个不同的输入消息,在计算上是不可能的。所以数据的哈希值,即消息摘要,可以检验数据的完整性。哈希函数的这种对不同的输入能够生成不同的值的特性使得无法找到两个具有相同哈希值的输入。因此,如果两个文档经哈希转换后成为相同的值,就可以肯定它们是同一文档。所以,当希望有效地比较两个数据块时,就可以比较它们的哈希值。例如,可以通过比较邮件发送前和发送后的哈希值来验证该邮件在传递时是否修改。

消息摘要算法

消息摘要算法的主要特征是加密过程不需要密钥,并且经过加密的数据无法被解密,只有输入相同的明文数据经过相同的消息摘要算法才能得到相同的密文。消息摘要算法不存在密钥的管理与分发问题,适合于分布式网络相同上使用。由于其加密计算的工作量相当可观,所以以前的这种算法通常只用于数据量有限的情况下的加密,例如计算机的口令就是用不可逆加密算法加密的。近年来,随着计算机相同性能的飞速改善,加密速度不再成为限制这种加密技术发展的桎梏,因而消息摘要算法应用的领域不断增加。

消息摘要算法的特点:

① 无论输入的消息有多长,计算出来的消息摘要的长度总是固定的。
② 消息摘要看起来是“随机的”。这些比特看上去是胡乱的杂凑在一起的。
③ 一般地,只要输入的消息不同,对其进行摘要以后产生的摘要消息也必不相同;但相同的输入必会产生相同的输出。
④ 消息摘要函数是无陷门的单向函数,即只能进行正向的信息摘要,而无法从摘要中恢复出任何的消息,甚至根本就找不到任何与原信息相关的信息。
⑤ 好的摘要算法,无法找到两条消息,是它们的摘要相同。

现有的消息摘要算法

消息摘要算法包含MD、SHA和MAC三大系列,常用于验证数据的完整性,是数据签名算法的核心算法。
MAC与MD和SHA不同,MAC是含有密钥的散列函数算法,我们也常把MAC称为HMAC。

JDK对消息摘要算法的支持

JDK6支持MD2/MD5/SHA/SHA256/SHA384/SHA512/HmacMD5/HmacSHA1/ HmacSHA256/HmacSHA384/HmacSHA512

使用到十六进制工具类Hex.java  见:java byte数组与十六进制字符串互转

MD和SHA系列的java实现:

DigestUtils.java

Java代码:

    import java.security.MessageDigest;  

    import java.security.NoSuchAlgorithmException;  

    /**

     * reference apache commons <a

     * href="http://commons.apache.org/codec/">http://commons.apache.org/codec/</a>

     * 

     * support MD2/MD5/SHA/SHA256/SHA384/SHA512

     * @author Aub

     * 

     */

    publicclass DigestUtils {  

    /**

         * 根据给定摘要算法创建一个消息摘要实例

         * 

         * @param algorithm

         *            摘要算法名

         * @return 消息摘要实例

         * @see MessageDigest#getInstance(String)

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    static MessageDigest getDigest(String algorithm) {  

    try {  

    return MessageDigest.getInstance(algorithm);  

            } catch (NoSuchAlgorithmException e) {  

    thrownew RuntimeException(e.getMessage());  

            }  

        }  

    /**

         * 获取 MD5 消息摘要实例

         * 

         * @return MD5 消息摘要实例

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    privatestatic MessageDigest getMd5Digest() {  

    return getDigest("MD5");  

        }  

    /**

         * 获取 SHA-1 消息摘要实例

         * 

         * @return SHA-1 消息摘要实例

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    privatestatic MessageDigest getShaDigest() {  

    return getDigest("SHA");  

        }  

    /**

         * 获取 SHA-256 消息摘要实例

         * 

         * @return SHA-256 消息摘要实例

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    privatestatic MessageDigest getSha256Digest() {  

    return getDigest("SHA-256");  

        }  

    /**

         * 获取 SHA-384 消息摘要实例

         * 

         * @return SHA-384 消息摘要实例

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    privatestatic MessageDigest getSha384Digest() {  

    return getDigest("SHA-384");  

        }  

    /**

         * 获取 SHA-512 消息摘要实例

         * 

         * @return SHA-512 消息摘要实例

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    privatestatic MessageDigest getSha512Digest() {  

    return getDigest("SHA-512");  

        }  

    /**

         * 使用MD5消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeMD5(byte[] data) {  

    return getMd5Digest().digest(data);  

        }  

    /**

         * 使用MD5消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return 消息摘要(长度为32的十六进制字符串)

         */

    publicstatic String encodeMD5Hex(byte[] data) {  

    return Hex.encodeHexStr(encodeMD5(data));  

        }  

    /**

         * 使用SHA-1消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-1消息摘要(长度为20的字节数组)

         */

    publicstaticbyte[] encodeSHA(byte[] data) {  

    return getShaDigest().digest(data);  

        }  

    /**

         * 使用SHA-1消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-1消息摘要(长度为40的十六进制字符串)

         */

    publicstatic String encodeSHAHex(byte[] data) {  

    return Hex.encodeHexStr(getShaDigest().digest(data));  

        }  

    /**

         * 使用SHA-256消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-256消息摘要(长度为32的字节数组)

         */

    publicstaticbyte[] encodeSHA256(byte[] data) {  

    return getSha256Digest().digest(data);  

        }  

    /**

         * 使用SHA-256消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-256消息摘要(长度为64的十六进制字符串)

         */

    publicstatic String encodeSHA256Hex(byte[] data) {  

    return Hex.encodeHexStr(encodeSHA256(data));  

        }  

    /**

         * 使用SHA-384消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-384消息摘要(长度为43的字节数组)

         */

    publicstaticbyte[] encodeSHA384(byte[] data) {  

    return getSha384Digest().digest(data);  

        }  

    /**

         * 使用SHA-384消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-384消息摘要(长度为86的十六进制字符串)

         */

    publicstatic String encodeSHA384Hex(byte[] data) {  

    return Hex.encodeHexStr(encodeSHA384(data));  

        }  

    /**

         * 使用SHA-512消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-512消息摘要(长度为64的字节数组)

         */

    publicstaticbyte[] encodeSHA512(byte[] data) {  

    return getSha512Digest().digest(data);  

        }  

    /**

         * 使用SHA-512消息摘要算法计算消息摘要

         * 

         * @param data

         *            做消息摘要的数据

         * @return SHA-512消息摘要(长度为128的十六进制字符串)

         */

    publicstatic String encodeSHA512Hex(byte[] data) {  

    return Hex.encodeHexStr(encodeSHA512(data));  

        }  

    }  


参考 org.apache.commons.codec.digest.DigestUtils
下载地址:http://commons.apache.org/codec/download_codec.cgi


MAC系列的java实现

Hmac.java

Java代码:

    import java.security.InvalidKeyException;  

    import java.security.Key;  

    import java.security.NoSuchAlgorithmException;  

    import javax.crypto.KeyGenerator;  

    import javax.crypto.Mac;  

    import javax.crypto.SecretKey;  

    import javax.crypto.spec.SecretKeySpec;  

    /**

     * Hmac<br/>

     * algorithm HmacMD5/HmacSHA/HmacSHA256/HmacSHA384/HmacSHA512

     * @author Aub

     */

    publicclass Hmac {  

    /**

         * 根据给定密钥生成算法创建密钥

         * 

         * @param algorithm

         *            密钥算法

         * @return 密钥

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    privatestaticbyte[] getHmacKey(String algorithm){  

    //初始化KeyGenerator 

            KeyGenerator keyGenerator = null;  

    try {  

                keyGenerator = KeyGenerator.getInstance(algorithm);  

            } catch (NoSuchAlgorithmException e) {  

    thrownew RuntimeException(e.getMessage());  

            }  

    //产生密钥 

            SecretKey secretKey = keyGenerator.generateKey();  

    //获得密钥 

    return secretKey.getEncoded();  

        }  

    /**

         * 获取 HmaMD5的密钥

         * 

         * @return  HmaMD5的密钥

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    publicstaticbyte[] getHmaMD5key(){  

    return getHmacKey("HmacMD5");  

        }  

    /**

         * 获取 HmaSHA的密钥

         * 

         * @return  HmaSHA的密钥

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    publicstaticbyte[] getHmaSHAkey(){  

    return getHmacKey("HmacSHA1");  

        }  

    /**

         * 获取 HmaSHA256的密钥

         * 

         * @return  HmaSHA256的密钥

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    publicstaticbyte[] getHmaSHA256key(){  

    return getHmacKey("HmacSHA256");  

        }  

    /**

         * 获取 HmaSHA384的密钥

         * 

         * @return  HmaSHA384的密钥

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    publicstaticbyte[] getHmaSHA384key(){  

    return getHmacKey("HmacSHA384");  

        }  

    /**

         * 获取 HmaSHA512的密钥

         * 

         * @return  HmaSHA384的密钥

         * @throws RuntimeException

         *             当 {@link java.security.NoSuchAlgorithmException} 发生时

         */

    publicstaticbyte[] getHmaSHA512key(){  

    return getHmacKey("HmacSHA512");  

        }  

    /**

         * 转换密钥

         * 

         * @param key   二进制密钥

         * @param algorithm 密钥算法

         * @return 密钥

         */

    privatestatic Key toKey(byte[] key,String algorithm){  

    //生成密钥 

    returnnew SecretKeySpec(key, algorithm);  

        }  

    /**

         * 使用HmacMD5消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacMD5(byte[] data, Key key){  

            Mac mac = null;  

    try {  

                mac = Mac.getInstance("HmacMD5");  

                mac.init(key);  

            } catch (NoSuchAlgorithmException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }catch (InvalidKeyException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }  

    return mac.doFinal(data);  

        }  

    /**

         * 使用HmacMD5消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacMD5(byte[] data, byte[] key){  

            Key k = toKey(key, "HmacMD5");  

    return encodeHmacMD5(data, k);  

        }  

    /**

         * 使用HmacSHA消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA(byte[] data, Key key){  

            Mac mac = null;  

    try {  

                mac = Mac.getInstance("HmacSHA1");  

                mac.init(key);  

            } catch (NoSuchAlgorithmException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }catch (InvalidKeyException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }  

    return mac.doFinal(data);  

        }  

    /**

         * 使用HmacSHA消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA(byte[] data, byte[] key){  

            Key k = toKey(key, "HmacSHA1");  

    return encodeHmacSHA(data, k);  

        }  

    /**

         * 使用HmacSHA256消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA256(byte[] data, Key key){  

            Mac mac = null;  

    try {  

                mac = Mac.getInstance("HmacSHA256");  

                mac.init(key);  

            } catch (NoSuchAlgorithmException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }catch (InvalidKeyException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }  

    return mac.doFinal(data);  

        }  

    /**

         * 使用HmacSHA256消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA256(byte[] data, byte[] key){  

            Key k = toKey(key, "HmacSHA256");  

    return encodeHmacSHA256(data, k);  

        }  

    /**

         * 使用HmacSHA384消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA384(byte[] data, Key key){  

            Mac mac = null;  

    try {  

                mac = Mac.getInstance("HmacSHA384");  

                mac.init(key);  

            } catch (NoSuchAlgorithmException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }catch (InvalidKeyException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }  

    return mac.doFinal(data);  

        }  

    /**

         * 使用HmacSHA384消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA384(byte[] data, byte[] key){  

            Key k = toKey(key, "HmacSHA384");  

    return encodeHmacSHA384(data, k);  

        }  

    /**

         * 使用HmacSHA512消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA512(byte[] data, Key key){  

            Mac mac = null;  

    try {  

                mac = Mac.getInstance("HmacSHA512");  

                mac.init(key);  

            } catch (NoSuchAlgorithmException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }catch (InvalidKeyException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }  

    return mac.doFinal(data);  

        }  

    /**

         * 使用HmacSHA512消息摘要算法计算消息摘要

         * 

         * @param data 做消息摘要的数据

         * @param key 密钥

         * @return 消息摘要(长度为16的字节数组)

         */

    publicstaticbyte[] encodeHmacSHA512(byte[] data, byte[] key){  

            Key k = toKey(key, "HmacSHA512");  

    return encodeHmacSHA512(data, k);  

        }  

    privatestatic String  showByteArray(byte[] data){  

    if(null == data){  

    returnnull;  

            }  

            StringBuilder sb = new StringBuilder("{");  

    for(byte b:data){  

                sb.append(b).append(",");  

            }  

            sb.deleteCharAt(sb.length()-1);  

            sb.append("}");  

    return sb.toString();  

        }  

    publicstaticvoid main(String[] args) {  

    //      byte[] key = getHmaMD5key(); 

    //      byte[] key = getHmaSHAkey(); 

    //      byte[] key = getHmaSHA256key(); 

    //      byte[] key = getHmaSHA384key(); 

    byte[] key = getHmaSHA512key();  

            System.out.println("加密密钥: byte[]:"+showByteArray(key).length());  

            String data = "Mac数据";  

            System.out.println("加密前数据: string:"+data);  

            System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes()));  

            System.out.println();  

    //      byte[] encodeData = encodeHmacMD5(data.getBytes(), key); 

    //      byte[] encodeData = encodeHmacSHA(data.getBytes(), key); 

    //      byte[] encodeData = encodeHmacSHA256(data.getBytes(), key); 

    //      byte[] encodeData = encodeHmacSHA384(data.getBytes(), key); 

    byte[] encodeData = encodeHmacSHA512(data.getBytes(), key);  

            System.out.println("加密后数据: byte[]:"+showByteArray(encodeData).length());  

            System.out.println("加密后数据: byte[]:"+encodeData.length);  

            System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encodeData));  

            System.out.println();  

        }  

    }  

Java 加密解密之对称加密算法DES

数据加密算法 (Data Encryption  Algorithm,DEA)是一种对称加密算法,很可能是使用最广泛的密钥系统,特别是在保护金融数据的安全中,最初开发的DEA是嵌入硬件中的。通 常,自动取款机(Automated Teller  Machine,ATM)都使用DEA。它出自IBM的研究工作,IBM也曾对它拥有几年的专利权,但是在1983年已到期后,处于公有范围中,允许在特 定条件下可以免除专利使用费而使用。1977年被美国政府正式采纳。

1998年后实用化DES破译机的出现彻底宣告DES算法已不具备安全性,1999年NIST颁布新标准,规定DES算法只能用于遗留加密系统,但不限制使用DESede算法。当今DES算法正是推出历史舞台,AES算法称为他的替代者。(详见:Java 加密解密之对称加密算法AES)


加密原理

DES 使用一个  56 位的密钥以及附加的 8 位奇偶校验位,产生最大 64 位的分组大小。这是一个迭代的分组密码,使用称为 Feistel  的技术,其中将加密的文本块分成两半。使用子密钥对其中一半应用循环功能,然后将输出与另一半进行“异或”运算;接着交换这两半,这一过程会继续下去,但 最后一个循环不交换。DES 使用 16 个循环,使用异或,置换,代换,移位操作四种基本运算。


JDK对DES算法的支持

密钥长度:56位
工作模式:ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128
填充方式:Nopadding/PKCS5Padding/ISO10126Padding/

工作模式和填充方式请参考:     JAVA加密解密基础

十六进制工具类Hex.java,见:java byte数组与十六进制字符串互转

DES加密解密的java实现:
DESCoder.java

Java代码:

    import java.security.Key;  

    import javax.crypto.Cipher;  

    import javax.crypto.KeyGenerator;  

    import javax.crypto.SecretKey;  

    import javax.crypto.SecretKeyFactory;  

    import javax.crypto.spec.DESKeySpec;  

    /**

     * DES Coder<br/>

     * secret key length:   56 bit, default:    56 bit<br/>

     * mode:    ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128<br/>

     * padding: Nopadding/PKCS5Padding/ISO10126Padding/

     * @author Aub

     * 

     */

    publicclass DESCoder {  

    /**

         * 密钥算法

        */

    privatestaticfinal String KEY_ALGORITHM = "DES";  

    privatestaticfinal String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";  

    //  private static final String DEFAULT_CIPHER_ALGORITHM = "DES/ECB/ISO10126Padding"; 

    /**

         * 初始化密钥

         * 

         * @return byte[] 密钥 

         * @throws Exception

         */

    publicstaticbyte[] initSecretKey() throws Exception{  

    //返回生成指定算法的秘密密钥的 KeyGenerator 对象 

            KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);  

    //初始化此密钥生成器,使其具有确定的密钥大小 

            kg.init(56);  

    //生成一个密钥 

            SecretKey  secretKey = kg.generateKey();  

    return secretKey.getEncoded();  

        }  

    /**

         * 转换密钥

         * 

         * @param key   二进制密钥

         * @return Key  密钥

         * @throws Exception

         */

    privatestatic Key toKey(byte[] key) throws Exception{  

    //实例化DES密钥规则 

            DESKeySpec dks = new DESKeySpec(key);  

    //实例化密钥工厂 

            SecretKeyFactory skf = SecretKeyFactory.getInstance(KEY_ALGORITHM);  

    //生成密钥 

            SecretKey  secretKey = skf.generateSecret(dks);  

    return secretKey;  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   密钥

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,Key key) throws Exception{  

    return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   二进制密钥

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,byte[] key) throws Exception{  

    return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   二进制密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{  

    //还原密钥 

            Key k = toKey(key);  

    return encrypt(data, k, cipherAlgorithm);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{  

    //实例化 

            Cipher cipher = Cipher.getInstance(cipherAlgorithm);  

    //使用密钥初始化,设置为加密模式 

            cipher.init(Cipher.ENCRYPT_MODE, key);  

    //执行操作 

    return cipher.doFinal(data);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   二进制密钥

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,byte[] key) throws Exception{  

    return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   密钥

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,Key key) throws Exception{  

    return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   二进制密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{  

    //还原密钥 

            Key k = toKey(key);  

    return decrypt(data, k, cipherAlgorithm);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{  

    //实例化 

            Cipher cipher = Cipher.getInstance(cipherAlgorithm);  

    //使用密钥初始化,设置为解密模式 

            cipher.init(Cipher.DECRYPT_MODE, key);  

    //执行操作 

    return cipher.doFinal(data);  

        }  

    privatestatic String  showByteArray(byte[] data){  

    if(null == data){  

    returnnull;  

            }  

            StringBuilder sb = new StringBuilder("{");  

    for(byte b:data){  

                sb.append(b).append(",");  

            }  

            sb.deleteCharAt(sb.length()-1);  

            sb.append("}");  

    return sb.toString();  

        }  

    publicstaticvoid main(String[] args) throws Exception {  

    byte[] key = initSecretKey();  

    //      byte[] key = "12345678".getBytes(); 

            System.out.println("key:"+ showByteArray(key));  

            Key k = toKey(key);  

            String data ="DES数据";  

            System.out.println("加密前数据: string:"+data);  

            System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes()));  

            System.out.println();  

    byte[] encryptData = encrypt(data.getBytes(), k);  

            System.out.println("加密后数据: byte[]:"+showByteArray(encryptData));  

            System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encryptData));  

            System.out.println();  

    byte[] decryptData = decrypt(encryptData, k);  

            System.out.println("解密后数据: byte[]:"+showByteArray(decryptData));  

            System.out.println("解密后数据: string:"+new String(decryptData));  

        }  

    }

Java 加密解密之对称加密算法DESede

DESede即三重 DES加密算法,也被称为3DES或者Triple  DES。使用三(或两)个不同的密钥对数据块进行三次(或两次)DES加密(加密一次要比进行普通加密的三次要快)。三重DES的强度大约和112- bit的密钥强度相当。通过迭代次数的提高了安全性,但同时也造成了加密效率低的问题。正因DESede算法效率问题,AES算法诞生了。(详见:Java 加密解密之对称加密算法AES)

到目前为止,还没有人给出攻击三重DES的有效方法。对其密钥空间中密钥进行蛮干搜索,那么由于空间太大,这实际上是不可行的。若用差分攻击的方法,相对于单一DES来说复杂性以指数形式增长。


三重DES有四种模型

(a)DES-EEE3,使用三个不同密钥,顺序进行三次加密变换。
(b)DES-EDE3,使用三个不同密钥,依次进行加密-解密-加密变换。
(c)DES-EEE2,其中密钥K1=K3,顺序进行三次加密变换。
(d)DES-EDE2, 其中密钥K1=K3,依次进行加密-解密-加密变换。


JDK对DESede算法的支持

密钥长度:112位/168位
工作模式:ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128
填充方式:Nopadding/PKCS5Padding/ISO10126Padding/

工作模式和填充方式请参考:     JAVA加密解密基础

十六进制工具类Hex.java,见:java byte数组与十六进制字符串互转
DESede加密解密的java实现:
DESede.java

Java代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
   
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
/**
 * DESede Coder<br/>
 * secret key length:   112/168 bit, default:   168 bit<br/>
 * mode:    ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128<br/>
 * padding: Nopadding/PKCS5Padding/ISO10126Padding/
 * @author Aub
 *
 */
public class DESedeCoder {
      
    /**
     * 密钥算法
    */
    private static final String KEY_ALGORITHM = "DESede";
      
//  private static final String DEFAULT_CIPHER_ALGORITHM = "DESede/ECB/PKCS5Padding";
    private static final String DEFAULT_CIPHER_ALGORITHM = "DESede/ECB/ISO10126Padding";
      
    /**
     * 初始化密钥
     *
     * @return byte[] 密钥
     * @throws Exception
     */
    public static byte[] initSecretKey() throws Exception{
        //返回生成指定算法的秘密密钥的 KeyGenerator 对象
        KeyGenerator kg = KeyGenerator.getInstance(KEY_ALGORITHM);
        //初始化此密钥生成器,使其具有确定的密钥大小
        kg.init(168);
        //生成一个密钥
        SecretKey  secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }
      
    /**
     * 转换密钥
     *
     * @param key   二进制密钥
     * @return Key  密钥
     * @throws Exception
     */
    private static Key toKey(byte[] key) throws Exception{
        //实例化DES密钥规则
        DESedeKeySpec dks = new DESedeKeySpec(key);
        //实例化密钥工厂
        SecretKeyFactory skf = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        //生成密钥
        SecretKey  secretKey = skf.generateSecret(dks);
        return secretKey;
    }
      
    /**
     * 加密
     *
     * @param data  待加密数据
     * @param key   密钥
     * @return byte[]   加密数据
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data,Key key) throws Exception{
        return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
    }
      
    /**
     * 加密
     *
     * @param data  待加密数据
     * @param key   二进制密钥
     * @return byte[]   加密数据
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data,byte[] key) throws Exception{
        return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
    }
      
      
    /**
     * 加密
     *
     * @param data  待加密数据
     * @param key   二进制密钥
     * @param cipherAlgorithm   加密算法/工作模式/填充方式
     * @return byte[]   加密数据
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{
        //还原密钥
        Key k = toKey(key);
        return encrypt(data, k, cipherAlgorithm);
    }
      
    /**
     * 加密
     *
     * @param data  待加密数据
     * @param key   密钥
     * @param cipherAlgorithm   加密算法/工作模式/填充方式
     * @return byte[]   加密数据
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{
        //实例化
        Cipher cipher = Cipher.getInstance(cipherAlgorithm);
        //使用密钥初始化,设置为加密模式
        cipher.init(Cipher.ENCRYPT_MODE, key);
        //执行操作
        return cipher.doFinal(data);
    }
      
      
      
    /**
     * 解密
     *
     * @param data  待解密数据
     * @param key   二进制密钥
     * @return byte[]   解密数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data,byte[] key) throws Exception{
        return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
    }
      
    /**
     * 解密
     *
     * @param data  待解密数据
     * @param key   密钥
     * @return byte[]   解密数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data,Key key) throws Exception{
        return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);
    }
      
    /**
     * 解密
     *
     * @param data  待解密数据
     * @param key   二进制密钥
     * @param cipherAlgorithm   加密算法/工作模式/填充方式
     * @return byte[]   解密数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{
        //还原密钥
        Key k = toKey(key);
        return decrypt(data, k, cipherAlgorithm);
    }
    /**
     * 解密
     *
     * @param data  待解密数据
     * @param key   密钥
     * @param cipherAlgorithm   加密算法/工作模式/填充方式
     * @return byte[]   解密数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{
        //实例化
        Cipher cipher = Cipher.getInstance(cipherAlgorithm);
        //使用密钥初始化,设置为解密模式
        cipher.init(Cipher.DECRYPT_MODE, key);
        //执行操作
        return cipher.doFinal(data);
    }
      
    private static String  showByteArray(byte[] data){
        if(null == data){
            return null;
        }
        StringBuilder sb = new StringBuilder("{");
        for(byte b:data){
            sb.append(b).append(",");
        }
        sb.deleteCharAt(sb.length()-1);
        sb.append("}");
        return sb.toString();
    }
      
    public static void main(String[] args) throws Exception {
        byte[] key = initSecretKey();
//      byte[] key = "123456789012345678901".getBytes();
        System.out.println("key:"+ showByteArray(key));
          
        Key k = toKey(key);
          
//      String data ="DESede数据";
        String data ="123456789";
        System.out.println("加密前数据: string:"+data);
        System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes()));
        System.out.println();
        byte[] encryptData = encrypt(data.getBytes(), k);
        System.out.println("加密后数据: byte[]:"+showByteArray(encryptData));
        System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encryptData));
        System.out.println();
        byte[] decryptData = decrypt(encryptData, k);
        System.out.println("解密后数据: byte[]:"+showByteArray(decryptData));
        System.out.println("解密后数据: string:"+new String(decryptData));
          
    }
      
}

Java 加密解密之对称加密算法AES

密码学中的高级加密 标准(Advanced Encryption  Standard,AES),又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。这个标准用来替代原先的DES,已经被多方分析且广为 全世界所使用。经过五年的甄选流程,高级加密标准由美国国家标准与技术研究院 (NIST)于2001年11月26日发布于FIPS PUB  197,并在2002年5月26日成为有效的标准。2006年,高级加密标准已然成为对称密钥加密中最流行的算法之一。该算法为比利时密码学家Joan  Daemen和Vincent  Rijmen所设计,结合两位作者的名字,以Rijndael之命名之,投稿高级加密标准的甄选流程。(Rijdael的发音近于  "Rhinedoll"。)

AES是美国国家标准技术研究所NIST旨在取代DES的21世纪的加密标准。

AES的基本要求 是,采用对称分组密码体制,密钥长度的最少支持为128、192、256,分组长度128位,算法应易于各种硬件和软件实现。1998年NIST开始 AES第一轮分析、测试和征集,共产生了15个候选算法。1999年3月完成了第二轮AES2的分析、测试。2000年10月2日美国政府正式宣布选中比 利时密码学家Joan Daemen 和 Vincent Rijmen 提出的一种密码算法RIJNDAEL 作为 AES.    在应用方面,尽管DES在安全上是脆弱的,但由于快速DES芯片的大量生产,使得DES仍能暂时继续使用,为提高安全强度,通常使用独立密钥的三级 DES。但是DES迟早要被AES代替。流密码体制较之分组密码在理论上成熟且安全,但未被列入下一代加密标准。   

AES加密数据块和密钥长度可以是128比特、192比特、256比特中的任意一个。

AES加密有很多轮的重复和变换。大致步骤如下:

1、密钥扩展(KeyExpansion),

2、初始轮(Initial Round),

3、重复轮(Rounds),每一轮又包括:SubBytes、ShiftRows、MixColumns、AddRoundKey,

4、最终轮(Final Round),最终轮没有MixColumns。


JDK对DESede算法的支持

密钥长度:128位
工作模式:ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128
填充方式:Nopadding/PKCS5Padding/ISO10126Padding/

工作模式和填充方式请参考:     JAVA加密解密基础

十六进制工具类Hex.java,见:java byte数组与十六进制字符串互转

AES加密解密的java实现:
AESCoder.java

Java代码:

    import java.security.Key;  

    import java.security.NoSuchAlgorithmException;  

    import javax.crypto.Cipher;  

    import javax.crypto.KeyGenerator;  

    import javax.crypto.SecretKey;  

    import javax.crypto.spec.SecretKeySpec;  

    /**

     * AES Coder<br/>

     * secret key length:   128bit, default:    128 bit<br/>

     * mode:    ECB/CBC/PCBC/CTR/CTS/CFB/CFB8 to CFB128/OFB/OBF8 to OFB128<br/>

     * padding: Nopadding/PKCS5Padding/ISO10126Padding/

     * @author Aub

     * 

     */

    publicclass AESCoder {  

    /**

         * 密钥算法

        */

    privatestaticfinal String KEY_ALGORITHM = "AES";  

    privatestaticfinal String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";  

    /**

         * 初始化密钥

         * 

         * @return byte[] 密钥 

         * @throws Exception

         */

    publicstaticbyte[] initSecretKey() {  

    //返回生成指定算法的秘密密钥的 KeyGenerator 对象 

            KeyGenerator kg = null;  

    try {  

                kg = KeyGenerator.getInstance(KEY_ALGORITHM);  

            } catch (NoSuchAlgorithmException e) {  

                e.printStackTrace();  

    returnnewbyte[0];  

            }  

    //初始化此密钥生成器,使其具有确定的密钥大小 

    //AES 要求密钥长度为 128 

            kg.init(128);  

    //生成一个密钥 

            SecretKey  secretKey = kg.generateKey();  

    return secretKey.getEncoded();  

        }  

    /**

         * 转换密钥

         * 

         * @param key   二进制密钥

         * @return 密钥

         */

    privatestatic Key toKey(byte[] key){  

    //生成密钥 

    returnnew SecretKeySpec(key, KEY_ALGORITHM);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   密钥

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,Key key) throws Exception{  

    return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   二进制密钥

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,byte[] key) throws Exception{  

    return encrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   二进制密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{  

    //还原密钥 

            Key k = toKey(key);  

    return encrypt(data, k, cipherAlgorithm);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{  

    //实例化 

            Cipher cipher = Cipher.getInstance(cipherAlgorithm);  

    //使用密钥初始化,设置为加密模式 

            cipher.init(Cipher.ENCRYPT_MODE, key);  

    //执行操作 

    return cipher.doFinal(data);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   二进制密钥

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,byte[] key) throws Exception{  

    return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   密钥

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,Key key) throws Exception{  

    return decrypt(data, key,DEFAULT_CIPHER_ALGORITHM);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   二进制密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,byte[] key,String cipherAlgorithm) throws Exception{  

    //还原密钥 

            Key k = toKey(key);  

    return decrypt(data, k, cipherAlgorithm);  

        }  

    /**

         * 解密

         * 

         * @param data  待解密数据

         * @param key   密钥

         * @param cipherAlgorithm   加密算法/工作模式/填充方式

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,Key key,String cipherAlgorithm) throws Exception{  

    //实例化 

            Cipher cipher = Cipher.getInstance(cipherAlgorithm);  

    //使用密钥初始化,设置为解密模式 

            cipher.init(Cipher.DECRYPT_MODE, key);  

    //执行操作 

    return cipher.doFinal(data);  

        }  

    privatestatic String  showByteArray(byte[] data){  

    if(null == data){  

    returnnull;  

            }  

            StringBuilder sb = new StringBuilder("{");  

    for(byte b:data){  

                sb.append(b).append(",");  

            }  

            sb.deleteCharAt(sb.length()-1);  

            sb.append("}");  

    return sb.toString();  

        }  

    publicstaticvoid main(String[] args) throws Exception {  

    byte[] key = initSecretKey();  

            System.out.println("key:"+showByteArray(key));  

            Key k = toKey(key);  

            String data ="AES数据";  

            System.out.println("加密前数据: string:"+data);  

            System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes()));  

            System.out.println();  

    byte[] encryptData = encrypt(data.getBytes(), k);  

            System.out.println("加密后数据: byte[]:"+showByteArray(encryptData));  

            System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encryptData));  

            System.out.println();  

    byte[] decryptData = decrypt(encryptData, k);  

            System.out.println("解密后数据: byte[]:"+showByteArray(decryptData));  

            System.out.println("解密后数据: string:"+new String(decryptData));  

        }  

    }  

扫描二维码关注公众号,回复: 525473 查看本文章

Java 加密解密之对称加密算法PBE

PBE是一种基于口令的加密算法,使用口令代替其他对称加密算法中的密钥,其特点在于口令由用户自己掌管,不借助任何物理媒体;采用随机数(这里我们叫做盐)杂凑多重加密等方法保证数据的安全性。

PBE算法是对称加密算法的综合算法,常见算法PBEWithMD5AndDES,使用MD5和DES算法构建了PBE算法。将盐附加在口令上,通过消息摘要算法经过迭代获得构建密钥的基本材料,构建密钥后使用对称加密算法进行加密解密。


JDK对PBE算法的支持

算法/密钥长度/默认密钥长度:

1.PBEWithMD5AndDES/56/56
2.PBEWithMD5AndTripleDES/112,168/168
3.PBEWithSHA1AndDESede/112,168/168
4.PBEWithSHA1AndRC2_40/40 to 1024/128

工作模式:CBC
填充方式:PKCS5Padding

工作模式和填充方式请参考:      JAVA加密解密基础

十六进制工具类Hex.java,见:java byte数组与十六进制字符串互转

PBE加密解密的java实现:
PBECoder.java

jave代码:

    import java.security.Key;  

    import java.security.SecureRandom;  

    import javax.crypto.Cipher;  

    import javax.crypto.SecretKeyFactory;  

    import javax.crypto.spec.PBEKeySpec;  

    import javax.crypto.spec.PBEParameterSpec;  

    /**

     * PBE Coder<br/>

     * Algorithm/secret key length/default secret key length/<br/>

     * 1.PBEWithMD5AndDES/56/56

     * 2.PBEWithMD5AndTripleDES/112,168/168

     * 3.PBEWithSHA1AndDESede/112,168/168

     * 4.PBEWithSHA1AndRC2_40/40 to 1024/128

     * mode:    CBC <br/>

     * padding: PKCS5Padding

     * @author Aub

     * 

     */

    publicclass PBECoder {  

    publicstaticfinal String ALGORITHM = "PBEWITHMD5andDES";  

    publicstaticfinalint ITERATION_COUNT = 100;  

    /**

         * 初始盐<br/>

         * 盐的长度必须为8位

         * @return byte[] 盐 

         * @throws Exception

         */

    publicstaticbyte[] initSalt() throws Exception{  

    //实例化安全随机数 

            SecureRandom random = new SecureRandom();  

    //产出盐 

    return random.generateSeed(8);  

        }  

    /**

         * 转换密钥

         * 

         * @param password  密码

         * @return Key 密钥

         */

    privatestatic Key toKey(String password) throws Exception{  

    //密钥材料 

            PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());  

    //实例化 

            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);  

    //生成密钥 

    return keyFactory.generateSecret(keySpec);  

        }  

    /**

         * 加密

         * 

         * @param data  待加密数据

         * @param key   密钥

         * @param salt  盐

         * @return byte[]   加密数据

         * @throws Exception

         */

    publicstaticbyte[] encrypt(byte[] data,String password,byte[] salt) throws Exception{  

    //转换密钥 

            Key key = toKey(password);  

    //实例化PBE参数材料 

            PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);  

    //实例化 

            Cipher cipher = Cipher.getInstance(ALGORITHM);  

    //初始化 

            cipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);  

    //执行操作 

    return cipher.doFinal(data);  

        }  

    /**

         * 解密

         * 

         * @param data  待机密数据

         * @param key   密钥

         * @param salt  盐

         * @return byte[]   解密数据

         * @throws Exception

         */

    publicstaticbyte[] decrypt(byte[] data,String password,byte[] salt)throws Exception{  

    //转换密钥 

            Key key = toKey(password);  

    //实例化PBE参数材料 

            PBEParameterSpec paramSpec = new PBEParameterSpec(salt, ITERATION_COUNT);  

    //实例化 

            Cipher cipher = Cipher.getInstance(ALGORITHM);  

    //初始化 

            cipher.init(Cipher.DECRYPT_MODE, key, paramSpec);  

    //执行操作 

    return cipher.doFinal(data);  

        }  

    privatestatic String  showByteArray(byte[] data){  

    if(null == data){  

    returnnull;  

            }  

            StringBuilder sb = new StringBuilder("{");  

    for(byte b:data){  

                sb.append(b).append(",");  

            }  

            sb.deleteCharAt(sb.length()-1);  

            sb.append("}");  

    return sb.toString();  

        }  

    publicstaticvoid main(String[] args) throws Exception {  

    byte[] salt = initSalt();  

            System.out.println("salt:"+showByteArray(salt));  

    //这里的password需要时ASCII码,不然会报异常 

            String password = "1111";  

            System.out.println("口令:"+password);  

            String data ="PBE数据";  

            System.out.println("加密前数据: string:"+data);  

            System.out.println("加密前数据: byte[]:"+showByteArray(data.getBytes()));  

            System.out.println();  

    byte[] encryptData = encrypt(data.getBytes(), password,salt);  

            System.out.println("加密后数据: byte[]:"+showByteArray(encryptData));  

            System.out.println("加密后数据: hexStr:"+Hex.encodeHexStr(encryptData));  

            System.out.println();  

    byte[] decryptData = decrypt(encryptData, password,salt);  

            System.out.println("解密后数据: byte[]:"+showByteArray(decryptData));  

            System.out.println("解密后数据: string:"+new String(decryptData));  

        }  

    }  

猜你喜欢

转载自zhyp29.iteye.com/blog/2353405