4.Java復号技術シリーズのHMAC

10110 ワード

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)は、ハッシュ関数の出力データワード長(MD 5ではL=16、SHA-1ではL=20)をLで表す.認証鍵の長さは、データブロックの文字長以下の任意の正の整数値であってもよい.アプリケーションで使用される鍵の長さが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

  • H (K XOR opad, H (K XOR ipad, text))
    計算手順
    バイト、B=60バイトであればK後に44個のゼロバイト0 x 00を加える)
  • 前回生成したB字長の文字列をipadと異ならせるまたは演算
  • データストリームtextを第2ステップの結果文字列
  • に埋め込む.
  • は、第3ステップで生成するデータストリーム
  • にHで作用する.
  • 最初のステップで生成されたB字長文字列をopadと排他的または演算
  • する.
  • さらに第4ステップの結果を第5ステップの結果の
  • に充填する.
  • は、第6ステップで生成するデータストリームにHで作用する、最終結果
  • を出力する.
    キー#キー#
    HMACに使用される鍵は、任意の長さであってもよい(Bより長い鍵は、最初にHによって処理される).鍵が
    長さがLより小さい場合、関数の安全強度が低下します.Lよりも長い鍵も可能であるが、余分な長さでは関数のセキュリティ強度を著しく向上させることはできない.
    鍵はランダムに選択し(または強力なランダムシードベースの擬似ランダム生成方法を使用する)、周期的に更新する必要があります.現在の攻撃では、それらの攻撃は実際には実行できないため、鍵を交換するのに有効な頻度は示されていない.しかしながら、周期的に鍵を更新することは、関数および鍵に存在する潜在的な欠陥に対処する基本的なセキュリティ措置であり、鍵の漏洩による危害を低減することができる.
    コード実装
    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)); } }

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