1. 程式人生 > >快速學習MD5的方法

快速學習MD5的方法

協議 環境 sequence 保存 bst close 之間 原理 兩種

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));  
    }  
}

快速學習MD5的方法