JAVA实现经典的对称加密算法--DES加解密

一、什么是对称加密算法?

  顾名思义,对称加密算法就是加密和解密使用相同密钥的一种算法。

  优点:使用简单快捷,密钥较短,加密速度快,且破译困难,适用于一对一的加密信息传输;

  缺点:不能验证通信双方的身份,密钥管理和分发困难,不适宜一对多的加密信息传输。 

 

二、DES加解密 

  des是非常经典的对称加密算法。

 

1.密钥生成

      指定算法名称(或者既指定算法名称又指定包提供程序),获取到唯一的随机数

      SecureRandom secureRandom = SecureRandom.getInstance( "SHA1PRNG" );

     或

      SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");

  密钥为 64位(二进制)长的密码key, ,密钥事实上是56位参与DES运算(第8、16、24、32、40、48、56、64位是奇偶校验位)。奇偶校验位是一个表示给定位数的二进制数中 1 的个数是奇数还是偶数的二进制数。奇偶校验位是最简单的错误检测码。 奇偶校验位有两种类型:偶校验位与奇校验位。如果一组给定数据位中 1 的个数是奇数,那么偶校验位就置为 1;如果给定一组数据位中 1 的个数是偶数,那么奇校验位就置为 1,总之,奇偶校验位保证这组数据位中1 的个数是奇数。

 

2、了解des加密的四种模式

 ECB模式

优点:

  1.简单;

  2.有利于并行计算;

  3.误差不会被传送;

缺点:

  1.不能隐藏明文的模式;

  2.可能对明文进行主动攻击;

 

 

CBC模式:

 

优点:

  1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。

缺点:

  1.不利于并行计算;

  2.误差传递;

  3.需要初始化向量IV

 

CFB模式:

 优点:

  1.隐藏了明文模式;

  2.分组密码转化为流模式;

  3.可以及时加密传送小于分组的数据;

缺点:

  1.不利于并行计算;

  2.误差传送:一个明文单元损坏影响多个单元;

  3.唯一的IV;

 

 OFB模式:

 优点:

  1.隐藏了明文模式;

  2.分组密码转化为流模式;

  3.可以及时加密传送小于分组的数据;

缺点:

  1.不利于并行计算;

  2.对明文的主动攻击是可能的;

  3.误差传送:一个明文单元损坏影响多个单元;

 

3、简单了解填充方式

  PKCS5Padding与PKCS7Padding基本上是可以通用的。

PKCS5Padding:

  If numberOfBytes(clearText) mod 8 == 7, PM = M + 0x01 

  If numberOfBytes(clearText) mod 8 == 6, PM = M + 0x0202

  ... 

  If numberOfBytes(clearText) mod 8 == 0, PM = M + 0x0808080808080808 

PKCS7Padding:

  PKCS #7 填充字符串由一个字节序列组成,每个字节填充该字节序列的长度。

下面的示例演示这些模式的工作原理。假定块长度为 8,数据长度为 9,则填充用八位字节数等于 7,数据等于 FF FF FF FF FF FF FF FF FF:

  数据: FF FF FF FF FF FF FF FF FF

  PKCS7 填充: FF FF FF FF FF FF FF FF FF 07 07 07 07 07 07 07 

在PKCS5Padding中,明确定义Block的大小是8位,而在PKCS7Padding定义中,对于块的大小是不确定的,可以在1-255之间(块长度超出255的尚待研究),填充值的算法都是一样的:value=k - (l mod k)  ,K=块大小,l=数据长度,如果l=8, 则需要填充额外的8个byte的08。

 

4、算法

想了解具体算法的可以在网上找下,这里就不写了。

三、DES加密在java中的实现 

在 pom.xml文件中加入:

  <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.10</version>
</dependency>
package com.su.mybatis.mysql.util.encryption;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.IvParameterSpec;

import org.apache.commons.codec.binary.Base64;

public class DESUtil {

    /**
     * CFB
     */
    public static final String CFB = "CFB";

    /**
     * OFB
     */
    public static final String OFB = "OFB";

    /**
     * CBC
     */
    public static final String CBC = "CBC";

    /**
     * iv向量
     */
    private static final byte[] DESIV = { (byte) 0xCE, (byte) 0x35, (byte) 0x5,
        (byte) 0xD, (byte) 0x98, (byte) 0x91, (byte) 0x8, (byte) 0xA };

    /**
     * AlgorithmParameterSpec
     */
    private static AlgorithmParameterSpec IV = null;

    /**
     * SHA1PRNG
     */
    private static final String SHA1PRNG = "SHA1PRNG";

    /**
     * DES默认模式
     */
    private static final String DES = "DES";

    /**
     * CBC加密模式
     */
    private static final String DES_CBC_PKCS5PADDING = "DES/CBC/PKCS5Padding";

    /**
    * OFB加密模式
    */
    private static final String DES_OFB_PKCS5PADDING = "DES/OFB/PKCS5Padding";

   /**
    * CFB加密模式
    */
    private static final String DES_CFB_PKCS5_PADDING = "DES/CFB/PKCS5Padding";

    /**
     * 加密模式
     */
    private static final int ENCRYPT_MODE = 1;

    /**
     * 解密模式
     */
    private static final int DECRYPT_MODE = 2;

    /**
     * 密钥
     */
    private Key key;

    public DESUtil(String str) {
        getKey(str);
    }

    public Key getKey() {
        return key;
    }

    public void setKey(Key key) {
        this.key = key;
    }

    /**
     * 通过密钥获得key
     * @param secretKey 密钥
     * @author sucb
     * @date 2017年2月28日下午1:17:58
     */
    public void getKey(String secretKey) {
        try {
            SecureRandom secureRandom = SecureRandom.getInstance(SHA1PRNG);
            secureRandom.setSeed(secretKey.getBytes());
            KeyGenerator generator = null;
            try {
                generator = KeyGenerator.getInstance(DES);
            } catch (NoSuchAlgorithmException e) {
            }
            generator.init(secureRandom);
            IV = new IvParameterSpec(DESIV);
            this.key = generator.generateKey();
            generator = null;

        } catch (Exception e) {
            throw new RuntimeException("Error in getKey(String secretKey), Cause: " + e);
        }
    }

    /**
     * 字符串des加密
     * @param data 需要加密的字符串
     * @param encryptType 加密模式 (ECB/CBC/OFB/CFB)
     * @return 加密结果
     * @throws Exception 异常
     * @author sucb
     * @date 2017年3月2日下午7:47:37
     */
    public String encrypt(String data, String encryptType) throws Exception {
        Cipher cipher = getPattern(encryptType, ENCRYPT_MODE);
        byte[] pasByte = cipher.doFinal(data.getBytes("UTF-8"));
        return Base64.encodeBase64String(pasByte);
    }

    /**
     * 字符串des解密
     * @param data 需要解密的字符串
     * @param decryptType  解密模式 (ECB/CBC/OFB/CFB)
     * @return 解密结果
     * @throws Exception 异常
     * @author sucb
     * @date 2017年3月2日下午7:48:21
     */
    public String decrypt(String data, String decryptType) throws Exception {
        Cipher cipher = getPattern(decryptType, DECRYPT_MODE);
        byte[] pasByte = cipher.doFinal(Base64.decodeBase64(data));
        return new String(pasByte, "UTF-8");
    }

    /**
     * 初始化cipher
     * @param type  加密/解密模式 (ECB/CBC/OFB/CFB)
     * @param cipherMode cipher工作模式 1:加密; 2:解密
     * @return cipher
     * @throws Exception 异常
     * @author sucb
     * @date 2017年3月2日下午7:49:16
     */
    private Cipher getPattern(String type, int cipherMode) throws Exception {
        Cipher cipher;
        switch (type){
            case CBC :
                cipher = Cipher.getInstance(DES_CBC_PKCS5PADDING);
                cipher.init(cipherMode, key, IV);
                break;
            case OFB :
                cipher = Cipher.getInstance(DES_OFB_PKCS5PADDING);
                cipher.init(cipherMode, key, IV);
                break;
            case CFB :
                cipher = Cipher.getInstance(DES_CFB_PKCS5_PADDING);
                cipher.init(cipherMode, key, IV);
                break;
            default :
                cipher = Cipher.getInstance(DES);
                cipher.init(cipherMode, key);
                break;
        }
        return cipher;
    }

    /**
     * 文件 file 进行加密并保存目标文件 destFile 中
     * @param file 要加密的文件 如 c:/test/file.txt
     * @param destFile 加密后存放的文件名 如 c:/ 加密后文件 .txt
     * @param encryptType 加密模式 (ECB/CBC/OFB/CFB)
     * @return 加密结果   0:异常 1:加密成功; 5:未找到需要加密的文件
     * @author sucb
     * @date 2017年3月2日下午7:56:08
     */
    public int encryptFile(String file, String destFile, String encryptType) {
        int result = 0;
        try {
            Cipher cipher = getPattern(encryptType, ENCRYPT_MODE);
            InputStream is = new FileInputStream(file);
            OutputStream out = new FileOutputStream(destFile);
            CipherInputStream cis = new CipherInputStream(is, cipher);
            byte[] buffer = new byte[1024];
            int r;
            while ((r = cis.read(buffer)) > 0) {
                out.write(buffer, 0, r);
            }
            cis.close();
            is.close();
            out.close();
            result = 1;
        } catch (FileNotFoundException e) {
            result = 5;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 文件 file 进行解密并保存目标文件 destFile 中
     * @param file 要解密的文件 如 c:/test/file.txt
     * @param destFile 解密后存放的文件名 如 c:/ 解密后文件 .txt
     * @param decryptType 解密模式 (ECB/CBC/OFB/CFB)
     * @return 解密结果 0:解密异常;1:解密正常;5:未找到需要解密的文件
     * @author sucb
     * @date 2017年3月2日下午7:58:56
     */
    public int decryptFile(String file, String destFile, String decryptType) {
        int result = 0;
        try {
            Cipher cipher = getPattern(decryptType, DECRYPT_MODE);
            InputStream is = new FileInputStream(file);
            OutputStream out = new FileOutputStream(destFile);
            CipherOutputStream cos = new CipherOutputStream(out, cipher);
            byte[] buffer = new byte[1024];
            int r;
            while ((r = is.read(buffer)) >= 0) {
                cos.write(buffer, 0, r);
            }
            cos.close();
            out.close();
            is.close();
            result = 1;
        }catch (FileNotFoundException e) {
            result = 5;
        }  catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    public static void main(String[] args) throws Exception {
        String testString = "82171ba02fc44b52b9f4a4853d0bcc34";
        DESUtil desUtil = new DESUtil("13325710641");
        String stringMi = desUtil.encrypt(testString, "CBC");
        System.out.println("密文" + stringMi);
        String stringMing = desUtil.decrypt(stringMi, "CBC");
        System.out.println("明文:" + stringMing);
    }

}

 

 

如果有写的不对的地方,请大家多多批评指正,非常感谢!

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值