加密算法

为了安全性的考虑,我时常需要使用到加密算法对关键数据进行加密,常用的加密算法有很多,本人接触到的有DES加密、MD5加密以及SHA-1加密,每种算法都有自己的优劣势,本文的目的就是简单的介绍一下各种加密算法的实现,方便以后回顾。

GitHub项目地址

DES加密

历史背景

DES的原始思想可以参照二战德国的恩尼格玛机,其基本思想大致相同。传统的密码加密都是由古代的循环移位思想而来,恩尼格玛机在这个基础之上进行了扩散模糊。但是本质原理都是一样的。现代DES在二进制级别做着同样的事:替代模糊,增加分析的难度。

加密原理

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

破解方法

攻击 DES 的主要形式被称为蛮力的或穷举,即重复尝试各种密钥直到有一个符合为止。如果 DES 使用 56 位的密钥,则可能的密钥数量是 2 的 56 次方个。随着计算机系统能力的不断发展,DES 的安全性比它刚出现时会弱得多,然而从非关键性质的实际出发,仍可以认为它是足够的。

安全性

一.安全性比较高的一种算法,目前只有一种方法可以破解该算法,那就是穷举法.
二.采用64位密钥技术,实际只有56位有效,8位用来校验的.譬如,有这样的一台PC机器,它能每秒计算一百万次,那么256位空间它要穷举的时间为2285年.所以这种算法还是比较安全的一种算法.

变种

DES 的常见变体是三重 DES(3DES),使用 168 (56*3)位的密钥对资料进行三次加密(3次使用DES)的一种机制;它通常(但非始终)提供极其强大的安全性。如果三个 56 位的子元素都相同,则三重 DES 向后兼容 DES。

TripleDES。该算法被用来解决使用 DES 技术的 56 位时密钥日益减弱的强度,其方法是:使用两个独立密钥对明文运行 DES 算法三次,从而得到 112 位有效密钥强度。TripleDES 有时称为 DESede(表示加密、解密和加密这三个阶段)。

以上内容均来自百度百科,大概对DES进行了一个大体介绍,然后我们看一下最关键的部分,就是DES加密算法的实现。

算法实现

由于这个算法有很多不同的实现方式,所以这里我就只贴出我使用的加密方式了。
DesUtil.java

import javax.crypto.Cipher;
import java.security.Key;
import java.security.Security;

/**
 * Created by Administrator on 2017/08/19.
 */
public class DesUtil {
    private static final String ENCRYPT_TYPE = "DES";
    //字符串默认值
    private static String defaultKey = "";
    //加密工具
    private Cipher encryptCipher = null;
    //解密工具
    private Cipher decryptCipher = null;

    public DesUtil() throws Exception{
        this(defaultKey);
    }

    /**
     * 指定密钥构造方法
     *
     * @param strKey
     *            指定的密钥
     * @throws Exception
     */
    public DesUtil(String strKey) throws Exception{
        Security.addProvider(new com.sun.crypto.provider.SunJCE());
        Key key = getKey(strKey.getBytes());
        encryptCipher = Cipher.getInstance(ENCRYPT_TYPE);
        encryptCipher.init(Cipher.ENCRYPT_MODE, key);
        decryptCipher = Cipher.getInstance(ENCRYPT_TYPE);
        decryptCipher.init(Cipher.DECRYPT_MODE, key);
    }

    /**
     * 加密字节数组
     *
     * @param arr
     *            需加密的字节数组
     * @return 加密后的字节数组
     * @throws Exception
     */
    private byte[] encryptStr(byte[] arr) throws Exception {
        return encryptCipher.doFinal(arr);
    }

    /**
     * 加密字符串
     *
     * @param strIn
     *            需加密的字符串
     * @return 加密后的字符串
     * @throws Exception
     */
    public String encrypt(String strIn) throws Exception {
        return StrConvertUtil.byteArrToHexStr(encryptStr(strIn.getBytes()));
    }

    /**
     * 解密字节数组
     *
     * @param arr
     *            需解密的字节数组
     * @return 解密后的字节数组
     * @throws Exception
     */
    private byte[] decryptStr(byte[] arr) throws Exception {
        return decryptCipher.doFinal(arr);
    }

    /**
     * 解密字符串
     *
     * @param strIn
     *            需解密的字符串
     * @return 解密后的字符串
     * @throws Exception
     */
    public String decrypt(String strIn) throws Exception {
        return new String(decryptStr(StrConvertUtil.hexStrToByteArr(strIn)));
    }

    /**
     * 从指定字符串生成密钥,密钥所需的字节数组长度为8位。不足8位时后面补0,超出8位只取前8位
     *
     * @param arrBTmp
     *            构成该字符串的字节数组
     * @return 生成的密钥
     */
    private Key getKey(byte[] arrBTmp) {
        byte[] arrB = new byte[8];// 创建一个空的8位字节数组(默认值为0)
        // 将原始字节数组转换为8位
        for (int i = 0; i < arrBTmp.length && i < arrB.length; i++) {
            arrB[i] = arrBTmp[i];
        }
        Key key = new javax.crypto.spec.SecretKeySpec(arrB, ENCRYPT_TYPE);// 生成密钥
        return key;
    }

}

因为这就是个加密工具类,我可以不了解DES的内部实现是什么样的,对于该工具类其实也可以完全没有了解,直接使用就可以了。
不过,基本的注释也有,还是比较好理解的。

这里用了另外一个字符字节处理工具类,如下
StrConvertUtil.java

/**
 * Created by Administrator on 2017/08/19.
 */
public class StrConvertUtil {

    /**
     * 将byte数组转换为表示16进制值的字符串,如:byte[]{8,18}转换为:0813, 和public static byte[]
     * hexStrToByteArr(String strIn) 互为可逆的转换过程
     *
     * @param arrB
     *            需要转换的byte数组
     * @return 转换后的字符串
     */
    public static String byteArrToHexStr(byte[] arrB){
        int iLen = arrB.length;
        // 每个byte(8位)用两个(16进制)字符才能表示,所以字符串的长度是数组长度的两倍
        StringBuilder sb = new StringBuilder(iLen * 2);
        for(int i = 0; i < iLen; i++){
            int intTmp = arrB[i];
            while (intTmp < 0){//把负数转化为正数
                intTmp = intTmp + 256;
            }
            if(intTmp < 16){//小于0F的数需要在前面补0
            sb.append("0");
            }
            sb.append(Integer.toString(intTmp,16));
        }

        return sb.toString();
    }

    /**
     * 将表示16进制值的字符串转换为byte数组,和public static String byteArrToHexStr(byte[] arrB)
     * 互为可逆的转换过程
     *
     * @param strIn
     *            需要转换的字符串
     * @return 转换后的byte数组
     */
    public static byte[] hexStrToByteArr(String strIn){
        byte[] arrB = strIn.getBytes();
        int iLen = arrB.length;
        // 两个(16进制)字符表示一个字节(8位),所以字节数组长度是字符串长度除以2
        byte[] arrOut =new byte[iLen/2];
        for (int i = 0; i < iLen; i = i+2){
            String strTmp = new String(arrB,i,2);
            arrOut[i/2] = (byte) Integer.parseInt(strTmp,16);
        }
        return arrOut;
    }
}

这部分内容可能理解清楚需要花一些时间,如果不是很想知道细节,直接拿来使用即可。

看一下测试类及结果

 @Test
    public void testDES(){
    try{
        DesUtil des = new DesUtil("JAVA");

        String username = "admin";
        Long logTime = System.currentTimeMillis();
        String time  = "" +logTime;
        String last = username + "," + time;

        String fff = des.encrypt(last);
        System.out.println("加密后:" + fff);

        String defff = des.decrypt(fff);
        System.out.println("解密后:" + defff);

        String[] sArr = defff.split(",");

        String user1 = sArr[0];
        String time1 = sArr[1];
        System.out.println(user1);
        System.out.println(time1);

        Long logTime1 = Long.parseLong(time1);
        System.out.println("转换为Long型:" + logTime1);

    }catch (Exception e){
        e.printStackTrace();
    }
    }
}

这里写图片描述

MD5加密

首先MD5是一个不可逆算法。

背景介绍

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。

优点

MD5算法具有以下特点:
1、压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2、容易计算:从原数据计算出MD5值很容易。
3、抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4、强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。

主要应用

1.一致性验证。利用MD5算法来进行文件校验的方案被大量应用到软件下载站、论坛数据库、系统文件安全等方面。
2.数字签名。第三方的认证机构对数字指纹进行监管验证。
3.安全访问认证。MD5还广泛用于操作系统的登陆认证上,如Unix、各类BSD系统登录密码、数字签名等诸多方面。如在Unix系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。这种加密技术被广泛的应用于Unix系统中,这也是为什么Unix系统比一般操作系统更为坚固一个重要原因。

算法原理

对MD5算法简要的叙述可以为:MD5以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

如下为总体流程图
这里写图片描述

破解

现在被黑客使用最多的一种破译密码的方法就是一种被称为”跑字典”的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。

2004年8月17日的美国加州圣巴巴拉的国际密码学会议(Crypto’2004)上,来自中国山东大学的王小云教授做了破译MD5、HAVAL-128、 MD4和RIPEMD算法的报告,公布了MD系列算法的破解结果。宣告了固若金汤的世界通行密码标准MD5的堡垒轰然倒塌,引发了密码学界的轩然大波。(注意:并非是真正的破解,只是加速了杂凑冲撞)
所谓杂凑冲撞指两个完全不同的讯息经杂凑函数计算得出完全相同的杂凑值。根据鸽巢原理,以有长度限制的杂凑函数计算没有长度限制的讯息是必然会有冲撞情况出现的。

2009年,冯登国、谢涛二人利用差分攻击,将MD5的碰撞算法复杂度从王小云的2^42进一步降低到2^21,极端情况下甚至可以降低至2^10。仅仅2^21的复杂度意味着即便是在2008年的计算机上,也只要几秒便可以找到一对碰撞。

以上内容出自百度百科,接下来介绍MD5算法实现。

MD5算法实现

本文介绍的算法及其简单,借助了java.security相关API,另外也使用了之前提到的字符字节处理工具类StrConvertUtil
Md5Util.java

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by Administrator on 2017/08/19.
 */
public class Md5Util {
    public final static String getMd5(String str){
        MessageDigest messageDigest = null;
        try{
            messageDigest = MessageDigest.getInstance("MD5");
        }catch (NoSuchAlgorithmException e){
            e.printStackTrace();
        }
        //使用指定字节更新摘要
        messageDigest.update(str.getBytes());
        //获得密文
        byte[] md = messageDigest.digest();
        return StrConvertUtil.byteArrToHexStr(md);
    }
}

基本的注释都有,就不介绍了,想要深入了解,请查看详细的源码,封装的也比较深,能力有限,就不献丑了。

 @Test
    public void testMD5(){
    try{
        String src = "1125646498441354";
        String src1 = Md5Util.getMd5(src);
        System.out.println("MD5加密前:" + src);
        System.out.println("MD5加完了:" + src1);
    }catch (Exception e){
        e.printStackTrace();
    }
    }

运行结果如下:
这里写图片描述
然后我对加密字符串做一点点的修改,将最后一位的4改为5,结果
这里写图片描述

可以看到一点小改动,最后的加密结果完全不同,一般MD5会用在帐密加密上。

SHA-1算法

简介

这里我们不再引用百度百科上的内容,因为没什么价值。
参考本篇blog整理如下

MD5和SHA-1都被称作哈希(Hash)函数。正式的哈希函数的定义是“把任意长度的数据计算成固定长度的数据”。也就是说函数的输入是任意长的,输出总是固定长度的。MD5和SHA-1是两种加密用哈希函数,MD5的返回值总是128bit的,SHA-1的返回值是160bit,都是固定长度。MD5如果按十六进制表示的话是32位十六进制的数,SHA-1是40位十六进制的数。

如上可知,SHA-1算法也是不可逆的,因为不存在一个算法能够由哈希值倒算出原始信息。

安全性

SHA-1算法的攻破难度较MD5难度更大。

2005年8月,王小云、姚期智,以及姚期智妻子姚储枫(即为Knuth起名高德纳的人)联手于国际密码讨论年会尾声部份提出SHA-1杂凑函数杂凑冲撞演算法的改良版。此改良版使破解SHA-1时间缩短。

应用

目前SHA-1算法应用还是非常广泛的。本人接触到的是在微信公众平台做接入校验的时候使用SHA-1加密算法。

算法实现

同MD5,使用java.securityAPI实现。
SHA1Util.java

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * Created by yubotao on 2017/12/07.
 */
public class SHA1Util {
    public final static String getSHA_1(String str){
        MessageDigest messageDigest = null;
        try{
            messageDigest = MessageDigest.getInstance("SHA-1");
        }catch (NoSuchAlgorithmException e){
            e.printStackTrace();
        }
        //获得密文
        byte[] md = messageDigest.digest();
        return StrConvertUtil.byteArrToHexStr(md);
    }
}

看一下运行结果如下,同MD5比较
这里写图片描述



暂时介绍到这里,如果接触到新的加密算法,再回来更新

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值