Java復号技術シリーズのHMAC


シーケンス
前回の記事では,第2の一方向暗号化アルゴリズムであるSHAを簡単に紹介し,SHA−1のJavaコードも与えた.この方面の需要がある子供靴は参考にすることができます.今日この文章は第3の一方向暗号化アルゴリズム--HMACを紹介します.実は、この暗号化アルゴリズムはそんなによく使われていません.少なくとも、私がシリーズのブログを書く前に、私はそれを聞いたことがありません.もちろん、これはHMACが有名ではないというわけではありません.きっと私が寡聞になったに違いありません.
背景
一方向暗号化アルゴリズムでHMACという「一般的ではない」アルゴリズムを紹介するのは、一つは「見たことがない」ためであり、二つ目は、結局、同じ一方向暗号化アルゴリズムの一つであり、鍵ベースのハッシュアルゴリズムの認証プロトコルであるからである.そこで、簡単に紹介することにしました.
本文
HMACは、「Hash Message Authentication Code」と呼ばれ、中国語名の「ハッシュメッセージ識別コード」であり、主にハッシュアルゴリズムを用いて、1つの鍵と1つのメッセージを入力として、1つのメッセージ要約を出力として生成する.一般的に、メッセージ識別コードは、2つの共通の送信を検証するために使用される. 
1つの鍵を共有する単位間のメッセージ.HMACは任意の反復ハッシュ関数にバンドルして使用することができる.MD 5とSHA−1がこのハッシュ関数である.
HMACはまた、メッセージ識別値の計算および確認のための鍵を使用することができる.
HMACは、ハッシュメッセージ識別コードであり、鍵に基づくHashアルゴリズムの認証プロトコルである.その実現原理は,公開関数と鍵を用いて一定長の値を認証識別として生成し,この識別でメッセージの整合性を識別することである.1つの鍵を使用して、固定サイズの小さなデータブロック、すなわちMACを生成し、メッセージに追加して送信する.受信者は、送信者と共有する鍵を用いて認証等を行う. 
この構造の主な役割は、
修正せずに適切なハッシュ関数を使用でき、ハッシュ関数はソフトウェア面でよく表現されています. そしてソースコードは公開され、汎用されています.
ハッシュ関数の本来の性能を劣化させることなく維持することができる.
下位ハッシュ関数の仮定に基づいた合理的なメッセージ識別機構の暗号化強度解析を可能にすることができる. 分かりやすい.
より高速またはより安全なハッシュ関数を発見または必要とする場合、下位レベルを容易に実現することができる. ハッシュ関数の置換.
HMACを定義するには、暗号化用ハッシュ関数(Hとして表される)と鍵Kが必要である.Hは 
データブロックを基本的な反復圧縮関数で暗号化するハッシュ関数.我々はBでデータブロックを表す
と入力します.(以上述べたハッシュ関数の分割データブロックワード長B=64)は、Lでハッシュ関数の
出力データワード長(MD 5でL=16、SHA-1でL=20).認証鍵の長さは、等しい数以下であってもよい
ブロックの長さに基づいた任意の正の整数値.アプリケーションで使用される鍵の長さがBよりも大きい場合は、まずハッシュの使用
関数Hが作用し、HMACで実際に使用される鍵としてH出力L長文字列が使用される.
一般に、推奨される最小鍵Kの長さはL文字長である.(Hの出力データ長と等しい).
固定された2つの異なる文字列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であれば バイト、B=60バイトであれば、K後に44個のゼロバイト0 x 00)が加わる.
前回生成したB字長の文字列をipadと異ならせるか演算ステップ2の結果文字列にデータストリームtextを入力第3ステップで生成するデータストリームにHが作用する.
第1ステップで生成されたB字長文字列をopadと排他的または演算するさらに、ステップ4の結果をステップ5の結果に埋め込む.
ステップ6で生成するデータストリームにHが作用する、最終結果が出力される.
キー#キー#
HMACに使用される鍵は、任意の長さであってもよい(Bより長い鍵は、最初にHによって処理される).鍵が 
長さがLより小さい場合、関数の安全強度が低下します.長さが大きい 
Lの鍵も可能であるが,余分な長さでは関数のセキュリティ強度を著しく向上させることはできない.
鍵はランダムに選択する必要があります(または、強力なランダムシードベースの擬似ランダム生成方法を使用します).
性の更新.現在の攻撃では、鍵を交換するのに有効な頻度は示されていません.なぜなら、それらの攻撃は実際には
いけません.しかしながら、周期的な更新鍵は、関数および鍵に存在する潜在的な欠陥に対処する基本である.
セキュリティ対策を講じ、鍵の漏洩による危害を低減することができます.
コード実装
<span style="font-family:Comic Sans MS;font-size:12px;">package com.sica.hmac;

import com.google.common.base.Strings;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;

/**
 * Created by xiang.li on 2015/2/27.
 */
public class HMAC {
    /**
     *       
     * MAC          
     * <pre>
     * HmacMD5
     * HmacSHA1
     * HmacSHA256
     * HmacSHA384
     * HmacSHA512
     * </pre>
     */
    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  :
" + key); String word = "123"; System.out.println(encryptHMAC(word, key)); } }</span>

終わりの言葉
この文章を読んだ後、HMACはすでに多くのことを知っていて、後でこの名詞に出会って、もちろんあなたも1、2、3を言うことができます.しかし、アプリケーションでは、一般的には使用できないかもしれませんが、セキュリティ上の要因を考慮すると、このような不可逆的な暗号化アルゴリズムは悪くないと思います.鍵のセットを追加で提供する必要があるので、この鍵は外部の人にはわかりません.そのため、安全性は比較的信頼できます.