快速学习MD5的方法

MD5加密的Java实现

在各种应用系统中,如果需要设置账户,那么就会涉及到存储用户账户信息的问题,为了保证所存储账户信息的安全,通常会采用MD5加密的方式来,进行存储。首先,简单得介绍一下,什么是MD5加密。
        MD5的全称是Message-Digest Algorithm 5 (信息-摘要算法),在90年代初,由MIT Laboratory for Computer Scientce 和RSA Data Security Inc 的 Ronald L.Rivest开发出来,经MD2、MD3和MD4发展而来。是让大容量信息在用数字签名软件签署私人密匙前被"压缩"成一种保密的格式(就是把一个任意长度的字节串变换成一定长的大整数)。不管是MD2、MD4还是MD5,它们都需要获得一个随机长度的信息并产生一个128位的信息摘要。虽然这些算法的结构或多或少有些相似,但MD2的设计与MD4和MD5完全不同,那是因为MD2是为8位机器做过设计优化的,而MD4和MD5却是面向32位的电脑。这三个算法的描述和C语言源代码在Internet RFCs 1321中有详细的描述,这是一份最权威的文档,由Ronald L.Rivest在1992年8月向IETF提交。

(一)消息摘要简介
            一个消息摘要就是一个数据块的数字指纹。即对一个任意长度的一个数据块进行计算,产生一个唯一指印(对于SHA1是产生一个20字节的二进制数组)。消息摘要是一种与消息认证码结合使用以确保消息完整性的技术。主要使用单向散列函数算法,可用于检验消息的完整性,和通过散列密码直接以文本形式保存等,目前广泛使用的算法由MD4、MD5、SHA-1.

消息摘要有两个基本属性:
            1.两个不同的报文难以生成相同的摘要
            2.难以对指定的摘要生成一个报文,而可以由改报文反推算出该指定的摘要
        代表:美国国家标准技术研究所的SHA1和麻省理工学院Ronald Rivest提出的MD5

(二)对字符串进行加密

package test;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import sun.misc.BASE64Encoder;

/**
 * 对字符串进行加密
 * @param str  待加密的字符串
 * @return  加密后的字符串
 * @throws NoSuchAlgorithmException  没有这种产生消息摘要的算法
 * @throws UnsupportedEncodingException
 */
public class Demo01 {

    public static String EncoderByMd5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException{
        //确定算法
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        BASE64Encoder base64en = new BASE64Encoder();
        //加密后的字符串
        String newstr = base64en.encode(md5.digest(str.getBytes("utf-8")));
        return newstr;
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        String str = "0123456789";
        System.out.println(EncoderByMd5(str));
    }
}

(三)验证密码是否正确

package test;

import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException;

/**
 * 判断用户密码是否正确
 * @param newpasswd  用户输入的密码
 * @param oldpasswd  数据库中存储的密码--用户密码的摘要
 * @return
 * @throws NoSuchAlgorithmException
 * @throws UnsupportedEncodingException
 *
 */
public class Demo02 {

    public static boolean checkpassword(String newpasswd, String oldpasswd) throws NoSuchAlgorithmException, UnsupportedEncodingException{
        if (Demo01.EncoderByMd5(newpasswd).equals(oldpasswd)) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        System.out.println("old:"+Demo01.EncoderByMd5("123"));
        System.out.println("new:"+Demo01.EncoderByMd5("123"));
        System.out.println(checkpassword("123",Demo01.EncoderByMd5("123")));
    }
}

因为MD5是基于消息摘要原理的,消息摘要的基本特征就是很难根据摘要推算出消息报文,因此要验证密码是否正确,就必须对输入密码(消息报文)重新计算其摘要,和数据库中存储的摘要进行对比(即数据库中存储的其实为用户密码的摘要),若两个摘要相同,则说明密码正确,不同,则说明密码错误。

练习1、Java实现MD5加密算法package test;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
 * Java实现MD5加密算法(使用MessageDigest)
 * MD5加密算法,即"Message-Digest Algorithm 5 (信息-摘要算法)",它由MD2、MD3、
 * MD4发展而来的一种单向函数算法(也就是HASH算法),它是国际著名的公钥加密算法标准RSA的第一设计者
 * R.Rivest于上个世纪90年代初开发而来的。MD5的最大作用在于,将不同格式的大容量文件信息在用数字签名
 * 软件来签署私人秘钥前"压缩"成一种保密格式,关键之处在于--这种"压缩"是不可逆的。Java JDK已经自带
 * 了MD5的实现,只要简单调用下就可以。
 *
 * @author Administrator
 *
 */
public class CreateMD5 {

    //静态方法,便于工具类
    public  static String getMd5(String plainText){
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(plainText.getBytes());
            byte b[] = md.digest();

            int i;

            StringBuffer buf = new StringBuffer("");
            for (int offset = 0; offset < b.length; offset++) {
                i = b[offset];
                if (i < 0)
                    i += 256;
                if (i < 16)
                    buf.append("0");
                buf.append(Integer.toHexString(i));
            }
            //32位加密
            return buf.toString();
            // 16位的加密
            // return buf.toString().substring(8,24);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) {
        //测试
        System.out.println(CreateMD5.getMd5("hello"));
    }
}

使用java获取md5值的两种方法
package test;

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

/**
 * 使用java获取md5值的两种方法
 * 1.Message Digest Algorithm MD5 (中文名为消息摘要算法第五版)
 * 为计算机安全领域广泛使用的一种散列函数,是一种比较常用的哈希算法。
 * 2.导入包:commons-codec
 * @author Administrator
 *
 */
public class md5_test {
    //MD5的字符串常量
    private final static String[] hexDigits = {"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"};

    public static void main(String[] args) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            System.out.println(byteArrayToHexString(messageDigest.digest("baidu.com".getBytes())));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }

    private static String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }

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

}MD5加密
package test;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5加密
 * @author Administrator
 *
 */
public class MD5 {
    public static void main(String[] args) {
        System.out.println(MD5.getMD5("123456"));
    }

    /**
     * 用md5 编码后的码值
     *
     * @param sInput
     * 明码
     * @return md5加密后的密码
     */
    private static String getMD5(String sInput) {

        String algorithm ="";
        if (sInput == null) {
            return "null";
        }

        try {
            algorithm = System.getProperty("MD5.algorithm","MD5");
        } catch (SecurityException se) {
        }
        MessageDigest md = null;
        try {
            md = MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte buffer[] = sInput.getBytes();

        for (int count = 0; count < sInput.length(); count++) {
            md.update(buffer,0,count);
        }
        byte bDigest[] = md.digest();
        BigInteger bi = new BigInteger(bDigest);
        return (bi.toString(16));
    }
}java计算过G文件md5 值计算
package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.Security;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.commons.codec.digest.DigestUtils;

import sun.applet.Main;
import sun.awt.image.BytePackedRaster;

/**
 * java计算过G文件md5 值计算
 *
 * @author Administrator
 *
 */
public class Md5CaculateUtil {

    private Md5CaculateUtil(){

    }

    private static char[] hexChar = {
        ‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘,‘6‘,‘7‘,‘8‘,‘9‘,
        ‘a‘,‘b‘,‘c‘,‘d‘,‘e‘,‘f‘
    };

    public static String getHash(String fileName,String hashType)
    throws IOException, NoSuchAlgorithmException{

        File f = new File(fileName);
        System.out.println("---------------------------------");
        System.out.println("|当前文件名称:"+f.getName());
        System.out.println("|当前文件大小:"+f.length()/1024/1024+"MB");
        System.out.println("|当前文件路径[绝对]:"+f.getAbsolutePath());
        System.out.println("|当前文件路径[---]:"+f.getCanonicalPath());
        System.out.println("---------------------------------");

        InputStream ins = new FileInputStream(f);

        byte[] buffer = new byte[8192];
        MessageDigest md5 = MessageDigest.getInstance(hashType);

        int len;
        while ((len = ins.read(buffer)) != -1) {
            md5.update(buffer, 0, len);
        }

        ins.close();
        // 也可以用apache自带的计算MD5方法
        return DigestUtils.md5Hex(md5.digest());
        // 自己写的转计算MD5方法
        // return toHexString(md5.digest());
    }

    public static String getHash2(String fileName){
        File f = new File(fileName);
        return String.valueOf(f.lastModified());
    }

    protected static String toHexString(byte[] b){
        StringBuilder sb = new StringBuilder(b.length*2);
        for (int i = 0; i < b.length; i++) {
            sb.append(hexChar[(b[i] & 0xf0) >>> 4]);
            sb.append(hexChar[b[i] & 0x0f]);
        }
        return sb.toString();
    }

    /**
     * 获取MessageDigest支持几种加密算法
     */
    @SuppressWarnings({"rawtypes","unchecked"})
    private static String[] getCryptolmpls(String serviceType){

        Set result = new HashSet();
        // all prividers
        Provider[] providers = Security.getProviders();
        for (int i = 0; i < providers.length; i++) {
            // get services provided by each provider
            Set keys = providers[i].keySet();
            for (Iterator it = keys.iterator(); it.hasNext();) {
                String key = it.next().toString();
                key = key.split(" ")[0];

                if (key.startsWith(serviceType+".")) {
                    result.add(key.substring(serviceType.length()+1));
                } else if (key.startsWith("Alg.Alias."+serviceType+".")) {
                        result.add(key.substring(serviceType.length(), 11));
                    }
                }
            }
        return (String[]) result.toArray(new String[result.size()]);
    }

    public static void main(String[] args) throws NoSuchAlgorithmException, IOException {
        // 调用方法
        // String[] names = getCryptolmpls("MessageDigest");
        // for(String name : names){
        //   System.out.println(name);
    //        }
        long start = System.currentTimeMillis();
        System.out.println("开始计算文件MD5值,请稍后...");
        String fileName = "E:\\Office_2010_Tookit_2.2.3XiaZaiBa.zip";
        // String fileName = "E:\\SoTowerStudio-3.1.0.exe";
        String hashType = "MD5";
        String hash = getHash(fileName, hashType);
        System.out.println("MD5"+hash);
        long end = System.currentTimeMillis();
        System.out.println("一共耗时:"+(end-start)+"毫秒");
    }
}Java三行代码搞定MD5加密
package test;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import exception.SpeedException;

/**
 * Java三行代码搞定MD5加密
 *
 * 对字符串md5加密
 *
 * @param str
 * @return
 *
 */
public class MD5Demo {
    public static String getMD5(String str) throws SpeedException{
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值,返回值为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示,得到字符串形式的hash值
            return new BigInteger(1,md.digest()).toString(16);
        } catch (Exception e) {
            throw new SpeedException("MD5加密出现错误");
        }
    }

    public static void main(String[] args) throws SpeedException {
        System.out.println(getMD5("123"));;
    }
}利用Java自带的MD5加密
package test;

import java.security.MessageDigest;

/**
 * 利用Java自带的MD5加密
 *
 * @author Administrator
 *
 */
public class MD5Util {
    public final static String MD5(String s){
        char hexDigits[]={‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘,‘6‘,‘7‘,‘8‘,‘9‘,‘A‘,‘B‘,‘C‘,‘D‘,‘E‘,‘F‘};

        try {
            byte[] btInput = s.getBytes();
            //获得MD5摘要算法的 MessageDigest 对象
            MessageDigest mdInst = MessageDigest.getInstance("MD5");
            //使用指定的字节更新摘要
            mdInst.update(btInput);
            //获得密文
            byte[] md = mdInst.digest();
            //把密文转换成十六进制的字符串形式
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }
    public static void main(String[] args) {
        System.out.println(MD5Util.MD5("20121221"));
        System.out.println("加密");
    }
}Java读取文件MD5的两种方案
package test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.IOUtils;

/**
 * Java读取文件MD5的两种方案
 * 1.MessageDigest实现
 * 2.org.apache.commons.codec.digest实现
 *
 * @author Administrator
 *
 */
public class testMD5 {

    public static String getMd5ByFile(File file) throws FileNotFoundException{
        String value = null;
        FileInputStream in = new FileInputStream(file);

        try {
            MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(byteBuffer);
            BigInteger bi = new BigInteger(1,md5.digest());
            value = bi.toString(16);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return value;
    }

    public static void main(String[] args) throws IOException {

        String path ="E:\\commons-codec-1.10-bin.zip";

        String v = getMd5ByFile(new File(path));
        System.out.println("MD5:"+v.toUpperCase());

        FileInputStream fis = new FileInputStream(path);
        String md5 = DigestUtils.md5Hex(IOUtils.toByteArray(fis));
        IOUtils.closeQuietly(fis);
        System.out.println("MD5:"+md5);

//        System.out.println("MD5"+DigestUtils.md5Hex("WANGQIUYUN"));
    }
}

ToMain
package test;

import org.apache.commons.codec.digest.DigestUtils;

public class ToMain {
    public static void main(String[] args) {
        System.out.println(DigestUtils.md5Hex("baidu.com"));
    }
}

SpeedException
package exception;

public class SpeedException extends Exception {
    public SpeedException(String msg)
    {
        super(msg);
    }
}

基本的java加密算法MD5等等

简单的java加密算法有:
BASE64    严格地说,属于编码格式,而非加密算法
MD5     (Message Digest algorithm 5,信息摘要算法)
SHA        (Secure Hash Algorithm,安全散列算法)
HMAC    (Hash Message Authentication Code, 散列消息鉴别码)

Java中4大基本加密算法解析

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

代码实现:

package com.cn.单向加密;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * BASE64的加密解密是双向的,可以求反解。
 * BASE64Encoder和BASE64Decoder是非官方JDK实现类。虽然可以在JDK里能找到
 * 并使用,但是在API里查不到。
 * JRE中sun和com.sun 开头包的类都是未被文档化的,他们属于java,javax类库的基础,
 * 其中的实现大多数与底层平台有关,一般来说是不推荐使用的。
 * BASE64严格地说,属于编码格式,而非加密算法
 * 主要就是BASE64Encoder、BASE64Decoder两个类,我们只需要直到使用对应的方法即可。
 * 另外,BASE加密后产生的字节位数是8的倍数,如果不够位数以=符号填充。
 * BASE64
 * 按照RFC2045的定义,Base64被定义为:Base64内容传送编码被设计用来把任意序列的8位
 * 字节描述为一种不易被人直接识别的形式
 * (The Base64 Content-Transfer-Encoding is designed to represent
 * arbitrary sequences of octets in a form that need not be humanly
 * readable.)
 * 常见于邮件、http加密,截取http信息,你就会发现登录操作的用户名、密码字段通过BASE64加密的。
 *
 * @author Administrator
 *
 */
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) {

        String str = "12345678";

        try {
            String result1 = BASE64.encryptBASE64(str.getBytes());
            System.out.println("result1=====加密数据=====>> "+result1);

            byte result2[] = BASE64.decryptBASE64(result1);
            String str2 = new String(result2);
            System.out.println("str2=====解密数据=====>> "+str2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

2.MD5
MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整
一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程
语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4.广泛用于加密和解密技术,常用于文件校验。
校验?不管文件多大,经过MD5后都能生成唯一的MD5值。好比现在的ISO校验,都是
MD5校验。怎么用?当然是把ISO经过MD5后产生MD5的值。一般下载linux-ISO的朋友
都见过相爱在连接叛变放着的MD5的串。就是用来验证是否一致的。

代码实现:

package com.cn.单向加密;

import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

/**
 * MD5(Message Digest algorithm 5,信息摘要算法)
 * 通常我们不直接使用上述MD5加密。
 * 通常将MD5产生的字节数组交给BASE64再加密一把,得到相应的字符串
 *
 * Digest:汇编
 *
 */
public class MD5 {
    public static final String KEY_MD5 = "MD5";

    public static String getResult(String inputStr){
        System.out.println("=======加密前的数据:"+inputStr);
        BigInteger bigInteger = null;

        try {
            MessageDigest md = MessageDigest.getInstance(KEY_MD5);
            byte[] inputData = inputStr.getBytes();
            md.update(inputData);
            bigInteger = new BigInteger(md.digest());
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("MD5加密后:"+bigInteger.toString(16));
        return bigInteger.toString(16);
    }

    public static void main(String[] args) {
        try {
            String inputStr = "简单加密8888888888888888888";
            getResult(inputStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

MD5算法具有以下特点:

1.压缩性:任意长度的数据,算出的MD5值长度都是固定的。
2.容易计算:从原数据计算出MD5值很容易。
3.抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
4.弱抗碰撞:已知原数据和其MD5值,想到一个具有相同MD5值的数据(即伪造数据)是非常困难的。
5.强抗碰撞:想找到两个不同的数据,使它们具有相同的MD5值,是非常困难的。
MD5的作用是让大容量信息在用数字签名软件签署私人秘钥前被"压缩"成一种保密格式(就是把任意长度的字节串变换成一定长的十六进制数字串)。除了MD5以外,其中比较有名的还有sha-1、RIPEMD以及Haval等。

3.SHA
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2~64位的消息,SHA1会产生一个160位的消息摘要。该算法经过加密专家多年来的发展和改进已日益完善,并被广泛使用。该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。散列函数值可以说是对明文的一种"指纹"或是"摘要"所以对散列值的数字签名就可以视为对此明文的数字签名。

java实现:

package com.cn.单向加密;

import java.math.BigInteger;
import java.security.MessageDigest;

/**
 *
 * SHA(Secure Hash Algorithm,安全散列算法),数字签名等密码学应用中重要的工具,
 * 被广泛地应用与电子商务等信息安全领域。虽然,SHA与MD5通过碰撞法都被破解了,
 * 但是SHA仍然是公认的安全加密算法,较之MD5更为安全
 *
 * @author Administrator
 *
 */
public class SHA {
    public static final String KEY_SHA = "SHA";

    public static String getResult(String inputStr){
        BigInteger sha = null;
        System.out.println("=======加密前的数据:"+inputStr);
        byte[] inputData = inputStr.getBytes();

        try {
            MessageDigest messageDigest = MessageDigest.getInstance(KEY_SHA);
            messageDigest.update(inputData);
            sha = new BigInteger(messageDigest.digest());
            System.out.println("SHA加密后:"+sha.toString(32));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sha.toString(32);
    }

    public static void main(String[] args) {
        try {
            String inputStr = "简单加密";
            getResult(inputStr);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

SHA-1与MD5的比较
因为二者均由MD4导出,SHA-1和MD5彼此很相似。相应的,他们的强度和其他特性也是相似,但还有以下几点不同:
| 对强行攻击的安全性:最显著和最重要的区别是SHA-1摘要比MD5摘要长32位。使用强行技术,产生任何一个报文使其摘要等于给定报摘要的难度对MD5是2^128数量级的操作,而对SHA-1则是2^160数量级的操作。这样,SHA-1对强行攻击有更大的强度。
| 对密码分析的安全性:由于MD5的设计,易受密码分析的攻击,SHA-1显得不易受这样的攻击。
| 速度:在相同的硬件上,SHA-1的运行速度比MD5慢。

4.HMAC(Hash Message Authentication Code),散列消息鉴别码,基于秘钥的Hash算法的认证协议。消息鉴别实现鉴别的原理是,用公开函数和秘钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个秘钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的秘钥进行鉴别认证等。
中文名"散列消息鉴别码",主要是利用哈希算法,以一个秘钥和一个消息为输入,生成一个消息照耀作为输出。一般的,消息鉴别码用于验证传输于两个共同想有一个秘钥的单位之间的消息。HMAC可以与任何迭代散列函数捆绑使用。MD5和SHA-1就是这种散列函数。HMAC还可以使用一个用于计算和确认消息鉴别值的秘钥。

HMAC,散列消息鉴别码,是基于秘钥的Hash算法的认证协议。它的实现原理是,用公开函数和秘钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个秘钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的秘钥进行鉴别认证等。

这种结构的主要作用是:
    不用修改既可以使用适合的散列函数,而且散列函数在软件方面表现的很好,并且源码是公开的通用的。
    可以保持散列函数原有的性能而不致其退化。
    可以使得基于合理的关于底层散列函数假设的消息鉴别机制的加密强度分析,便于理解。
    当发现或需要运算速度更快或更安全的散列函数时,可以很容易的实现底层散列函数的替换。

定义HMAC需要一个加密用散列函数(表示H)和一个秘钥K。我们假设H是一个将数据块用一个基本的迭代压缩函数来加密的散列函数。我们用B来表示数据块的字长。(以上提到的散列函数的分割数据块字长B=64),用L来表示散列函数的输出数据字长(MD5中L=16,SHA-1中L=20)。鉴别秘钥的长度可以是小于等于数据块字长的任何正整数值。应用程序中使用的秘钥长度若是比B大,则首先使用散列函数H作用与它,然后用H输出的L长度字符串作为在HMAC中实际使用的秘钥。一般情况下,推荐的最小秘钥K长度是L个字长。(与H的输出数据长度相等)。

我们将定义两个固定且不同的字符串ipad,opad:(‘i‘,‘o‘表示内部与外部)
    ipad = the byte 0x36 repeated B times
    opad = the byte 0x5C repeated B times

计算‘text‘ 的HMAC;
    H(K XOR opad,H(K XOR ipad, text))

计算步骤:
    在秘钥K后面添加0创建一个字长为B的字符串。(例如,如果K的字长是20字节,则K后会加入44个零字节0x00)
    将上一步生成的B字长的字符串与ipad作疑惑运算
    将数据流text填充至第二步的结果字符串中
    用H作用于第三步生成的数据流
    将第一步生成的B字长字符串与opad作异或运算
    再将第四步的结果填充进第五步的结果中
    用H作用于第六步生成的数据流,输出最终结果

秘钥
    用于HMAC的秘钥可以是任意长度(比B长的秘钥将首先被H处理)。但当秘钥长度小于L时,会降低函数的安全强度。长度大于L的秘钥也是可以的,但额外的长度并不能显著的提高函数的安全强度。

秘钥必须随机选取(或使用强大的基于随机种子的伪随机生成方法),并且要周期性的更新。目前的攻击没有指出一个有效的更换秘钥的频率,因为那些攻击实际上并不可行。然而,周期性更新秘钥时一个对付函数和秘钥所存在的潜在缺陷的基本安全措施,并可以降低泄露秘钥带来的危害。

java实现代码:

package com.cn.单向加密;

import java.security.NoSuchAlgorithmException;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import com.google.common.base.Strings;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

/**
 * HMAC
 * HMAC(Hash Message Authentication Code),散列消息鉴别码,
 * 基于秘钥的Hash算法的认证协议。
 * 消息鉴别码实现鉴别的原理是,用公开的函数和秘钥产生一个固定长度的值作为认证标识,
 * 用这个标识鉴别消息的完整性。
 * 使用一个秘钥生成一个固定大小的小数据块,
 * 即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的秘钥进行鉴别认证等
 *
 *
 */

/**
 * 定义加密方式
 * MAC算法可选以下多种算法
 * HmacMD5
 * HmacSHA1
 * HmacSHA256
 * HmacSHA384
 * HmacSHA512
 */
public class HMAC {
    private final static String KEY_MAC = "HmacMD5";  

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

    /**
     * 构造函数
     */
    public HMAC() {  

    }  

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

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

    /**
     * 初始化HMAC密钥
     * @return
     */
    public static String init() {
        SecretKey key;
        String str = "";
        try {
            KeyGenerator generator = KeyGenerator.getInstance(KEY_MAC);
            key = generator.generateKey();
            str = encryptBase64(key.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return str;
    }  

    /**
     * HMAC加密
     * @param data 需要加密的字节数组
     * @param key 密钥
     * @return 字节数组
     */
    public static byte[] encryptHMAC(byte[] data, String key) {
        SecretKey secretKey;
        byte[] bytes = null;
        try {
            secretKey = new SecretKeySpec(decryptBase64(key), KEY_MAC);
            Mac mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
            bytes = mac.doFinal(data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return bytes;
    }  

    /**
     * HMAC加密
     * @param data 需要加密的字符串
     * @param key 密钥
     * @return 字符串
     */
    public static String encryptHMAC(String data, String key) {
        if (Strings.isNullOrEmpty(data)) {
            return null;
        }
        byte[] bytes = encryptHMAC(data.getBytes(), key);
        return byteArrayToHexString(bytes);
    }  

    /**
     * 将一个字节转化成十六进制形式的字符串
     * @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 args
     */
    public static void main(String[] args) throws Exception {
        String key = HMAC.init();
        System.out.println("Mac密钥:\n" + key);
        String word = "123";
        System.out.println(encryptHMAC(word, key));
    }
}
时间: 2024-08-08 13:30:21

快速学习MD5的方法的相关文章

快速学习命令的方法

概述:用户使用shell跟内核交互,Linux 中有很多命令,不同的命令有不同的功能.多个命令合起来可以完成一个大的功能.命令很多我们不可能记得每条命令的用法. 所以,我们必须有一种方法来快速知道一个命令是如何使用的,有什么作用.所以,几乎所有的命令都提供了帮助手册,告诉命令的使用者如何使用命令.命令 的作用等等.帮助手册页很长,我们不可能为了使用一个命令,而从头到尾把帮助手册读完,这时候需要一种快速读懂(有目的的去读)命令的帮助手册的方法.是如何实现的呢?管理整个计算硬件的其实是核心(kern

node快速计算md5

最近在做一个文件上传的项目,当上传文件达到几十GB,几百GB后在文件上传99%后,需要等待非常长的时间文件才能完成上传.通过埋点打印时间,发现md5计算时间非常长. 为了校验文件传输的完整性需要在文件上传结束后校验文件的完整性,md5值就用来校验完整性,所以这一步不能少. 解决方案 通过网上查找资料,MD5计算工具在计算大文件md5值时也不是一次性计算出来的,也是通过分片的方式累加计算出来的. 所以我们在上传大文件时,本来上传的思路就是分片上传,我们只需要对每块分片进行md5计算,最后累加计算m

STM32环境搭建/学习观点/自学方法 入门必看

文章转自armfly开发板V4软件开发手册,分享学习~ 今天有幸看到armfly的开发板软件开发手册,开头的基础知识,真的很有用,还好有看到,一切都不迟,感悟很多,摘抄部分,学习分享~ 关于开发环境的搭建 (个人认为,好用的工具,顺手的开发环境,对于编程是一种好的习惯,也是一种好的享受,所以,在环境搭建方面,我还是比较在意软件的互相联合使用,工程建立的规范化等等,这样可以尽量少的在后期更换不同的环境,变软会很浪费时间,一次到位,一路顺风顺水~) 个人偏好的环境搭建: 集成开发环境(IDE):Ke

第23篇 js快速学习知识

前面说了js的一些高级方面的基础知识,这些都是比较容易出错的和比较难理解的东西,除了这些之外其它的知识都比较简单了,基础学好了,扩展起来就是小意思.今天说说js方面可以快速学习和入门的知识. 1.闭包 对于闭包来说,很多人对它有误解,有的说的怎么怎么好,但是我觉得这个东西说的那么悬无非是忽悠人的,对于闭包我看到有一篇博客上面说的很好: (1)闭包是一种设计原则,它通过分析上下文,来简化用户的调用,让用户在不知晓的情况下,达到他的目的: (2)网上主流的对闭包剖析的文章实际上是和闭包原则反向而驰的

Bootstrap快速学习笔记(2)表单系列之二

欢迎收看大奥编写的Bootstrap快速学习笔记(2)表单系列之二 本学习笔记根据[慕课网]教程修改而来,用它学习Bootstrap,将会带来全新的体验哦: 表单控件大小 表单控件状态 按钮 图像 详细介绍 表单控件大小表单控件大小可以通过给表单控件添加class类来实现,如果想要比较大,则添加input-lg类,如果想要比较小, 则添加input-sm类,但这仅是对高度进行了处理,如果要对宽度进行处理,需要在每个input控件外围添加div容器并带有col-xs-4类,并 且要在这组控件的外围

60分钟Python快速学习(转)

60分钟Python快速学习(给发哥一个交代) 阅读目录 第一步:开发环境搭建: 第一个Python功能:初识Python 02.Python中定义变量不需要数据类型 03.在Pythod中定义方法 04.在Python中书写自己的类 60分钟Python快速学习 之前和同事谈到Python,每次下班后跑步都是在听他说,例如Python属于“胶水语言啦”,属于“解释型语言啦!”,是“面向对象的语言啦!”,另外没有数据类型,逻辑全靠空格缩进表示等. 今天自己用了60分钟快速学习了下Python的语

Java快速学习笔记01

这一波快速学习主要是应付校招笔面试用,功利性质不可避免. 学习网址: http://www.runoob.com/java/java-tutorial.html 执行命令解析: 以上我们使用了两个命令 javac 和 java. javac 命令用于将 java 源文件编译为 class 字节码文件,如: javac HelloWorld.java. 运行javac命令后,如果成功编译没有错误的话,会出现一个 HelloWorld.class 的文件. java 命令可以运行 class 字节码

【Java的JNI快速学习教程】

1. JNI简介 JNI是Java Native Interface的英文缩写,意为Java本地接口. 问题来源:由于Java编写底层的应用较难实现,在一些实时性要求非常高的部分Java较难胜任(实时性要求高的地方目前还未涉及,实时性这类话题有待考究). 解决办法:Java使用JNI可以调用现有的本地库(C/C++开发任何和系统相关的程序和类库),极大地灵活Java的开发. 2. JNI快速学习教程 2.1 问题: 使用JNI写一段代码,实现string_Java_Test_helloworld

快速学习六步

转载: 第一步:快速浏览大量相关信息(快速通读) 许多人试图慢慢地系统地吸收难懂的材料.他们阅读时划线做标记,并且反复阅读某些段落以求理解.这种方法可能最终能达到目的,但是大部分人会感到厌倦然 后在结束之前放弃努力.我们的大脑讨厌这种学习方式.更好的方法是,尽可能快速浏览材料.不要担心你不能理解所有内容,只管这样读下去.迫使自己读完“该 死的”书本,不用担心自己没记住多少内容:). 跳过任何练习或测验,只是尽力阅读. 有些人能够坐下来两三次就读完整本书,但我做不到.我喜欢看10到20页然后做点其