| 一般的な | |
|---|---|
| デザイナー | ロナルド・リベスト |
| 初版 | 1992年4月 |
| シリーズ | MD2、MD4、MD5、MD6 |
| 暗号の詳細 | |
| ダイジェストサイズ | 128ビット |
| ブロックサイズ | 512ビット |
| 構造 | メルクル・ダムガルド建設 |
| ラウンド | 4 [ 1 ] |
| 最高の公開暗号解読 | |
| 2013年に謝涛、劉凡宝、馮登果による攻撃は、MD5の衝突耐性を2の18乗倍で破りました。この攻撃は、通常のコンピュータでは1秒未満で実行されます。[ 2 ] MD5は長さ拡張攻撃 を受けやすいです。 | |
MD5メッセージダイジェストアルゴリズムは、 128ビットのハッシュ値を生成する広く使用されているハッシュ関数です。MD5は、以前のハッシュ関数MD4を置き換えるために1991年にロナルド・リベストによって設計され、[ 3 ] 1992年にRFC 1321として仕様化されました。
MD5は、意図しない破損に対するデータの整合性を検証するためのチェックサムとして使用できます。歴史的には暗号ハッシュ関数として広く使用されていましたが、広範な脆弱性があることが判明しています。暗号化以外の用途、例えばパーティションデータベース内の特定のキーのパーティションを決定する用途にも適しており、最近のセキュアハッシュアルゴリズムよりも計算量が少ないため、MD5が好まれる場合があります。[ 4 ]
MD5は、 MITのロナルド・リベスト教授によって設計された一連のメッセージダイジェストアルゴリズムの一つです(Rivest, 1992)。MD5の前身であるMD4が安全でない可能性が高いことが分析によって示されたため、リベスト教授は1991年に安全な代替としてMD5を設計しました。(その後、ハンス・ドッベルティン教授がMD4の脆弱性を発見しました。)
1993 年、Den Boer と Bosselaers は、MD5圧縮関数の「疑似衝突」 、つまり同一のダイジェストを生成する 2 つの異なる初期化ベクトルを発見するという、限定的ではあるものの初期結果を発表しました。
1996年、DobbertinはMD5の圧縮関数の衝突を発表しました(Dobbertin, 1996)。これはMD5ハッシュ関数全体に対する攻撃ではありませんでしたが、暗号学者がSHA-1(その後も侵害を受けています)やRIPEMD-160などの代替関数への移行を推奨するほど、かなり深刻なものでした。
ハッシュ値のサイズ(128 ビット)は、誕生日攻撃が想定されるほど小さい。MD5CRKは、誕生日攻撃を使用して衝突を検出することにより、MD5 が実質的に安全ではないことを実証するために 2004 年 3 月に開始された 分散プロジェクトである。
MD5CRKは、2004年8月17日、 Xiaoyun Wang、Dengguo Feng、Xuejia Lai、Hongbo Yuによって完全なMD5の衝突が発表された直後に終了しました。 [ 5 ] [ 6 ]彼らの解析攻撃は、 IBM p690クラスターでわずか1時間しかかからなかったと報告されています。[ 7 ]
2005年3月1日、アルジェン・レンストラ、シャオユン・ワン、ベネ・デ・ウェガーは、異なる公開鍵と同じMD5ハッシュ値を持つ2つのX.509証明書の構築を実証しました。これは、実際に衝突が発生する可能性を実証しました。 [ 8 ]この構築には、両方の公開鍵の秘密鍵が含まれていました。数日後、ヴラスティミル・クリマは、1台のノートパソコンで数時間でMD5の衝突を構築できる改良アルゴリズムを発表しました。[ 9 ] 2006年3月18日、クリマはトンネリングと呼ばれる手法を用いて、1台のノートパソコンで1分以内に衝突を検出できるアルゴリズムを発表しました。[ 10 ]
MD5関連のRFC正誤表は数多く公開されている。2009年には、米国サイバーコマンドが、そのミッションステートメントのMD5ハッシュ値を公式エンブレムの一部として使用した。[ 11 ]
2010年12月24日、タオ・シェ氏とデングオ・フェン氏は、MD5の単一ブロック(512ビット)衝突を初めて公開したと発表した[ 12 ] 。 (これまでの衝突発見は、複数ブロック攻撃に依存していた。)シェ氏とフェン氏は「セキュリティ上の理由」から、この新しい攻撃手法を公表しなかった。彼らは暗号コミュニティに挑戦状を叩きつけ、2013年1月1日までに異なる64バイト衝突を最初に発見した者に1万ドルの報奨金を出すことを発表した。マーク・スティーブンス氏はこの挑戦に応え、衝突する単一ブロックメッセージと、その構築アルゴリズムと情報源を公開した[ 13 ] 。
2011年にMD5 [ 15 ]とHMAC-MD5のセキュリティに関する考慮事項を更新するための情報RFC 6151 [ 14 ]が承認されました。 [ 16 ]
暗号ハッシュ関数の基本要件の一つは、ハッシュ値が同じ2つの異なるメッセージを見つけることが計算的に不可能であることです。MD5はこの要件を壊滅的に満たしていません。2008年12月31日、 CMUソフトウェア工学研究所は、MD5は本質的に「暗号的に破られており、今後の使用には適さない」と結論付けました。[ 17 ] MD5の脆弱性は現場で悪用されており、最も悪名高いのは2012年のFlameマルウェアです。2019年現在、MD5は、その脆弱性が十分に文書化され、セキュリティ専門家によって非推奨とされているにもかかわらず、広く使用され続けています。[ 18 ]
2.6GHzのPentium 4プロセッサを搭載したコンピュータで数秒以内に衝突を発見できる衝突攻撃が存在する(複雑度は2の24.1倍)。[ 19 ]さらに、市販の計算ハードウェアを使用して、指定されたプレフィックスを持つ2つの入力に対して数秒以内に衝突を発生させることができる選択プレフィックス衝突攻撃も存在する(複雑度は2の39倍)。[ 20 ] 衝突を発見する能力は、市販のGPUの使用によって大幅に向上した。NVIDIA GeForce 8400GSグラフィックプロセッサでは、1秒あたり1600万~1800万のハッシュを計算できる。NVIDIA GeForce 8800 Ultraは、1秒あたり2億以上のハッシュを計算できる。[ 21 ]
これらのハッシュ攻撃と衝突攻撃は、文書ファイル[ 22 ] [ 23 ]やデジタル証明書[ 24 ]の衝突など、様々な状況で公開されています。2015年時点で、MD5は依然としてかなり広く使用されており、特にセキュリティ研究やウイルス対策企業によって広く使用されていることが実証されています。[ 25 ]
2019年時点では、広く使用されているコンテンツ管理システムの4分の1が、依然としてパスワードハッシュにMD5を使用していると報告されています。[ 18 ]
1996年、MD5の設計に欠陥が見つかりました。当時は致命的な弱点とはみなされていませんでしたが、暗号学者たちはSHA-1など他のアルゴリズムの使用を推奨し始めましたが、SHA-1もその後脆弱であることがわかりました。[ 26 ] 2004年には、MD5は衝突耐性が ないことが示されました。[ 27 ]そのため、MD5は、デジタルセキュリティのためにこの特性に依存するSSL証明書やデジタル署名などのアプリケーションには適していません。研究者たちはさらに、MD5のより深刻な欠陥を発見し、実行可能な衝突攻撃、つまりMD5が同一のチェックサムを生成する一対の入力を作成する方法を説明しました。[ 5 ] [ 28 ] 2005年、2006年、2007年には、MD5を破るさらなる進歩がありました。[ 29 ] 2008年12月、研究者グループがこの手法を使用してSSL証明書の有効性を偽装しました。[ 24 ] [ 30 ]
2010年時点で、CMUソフトウェア工学研究所はMD5を「暗号的に破られており、今後の使用には不適切」とみなしており[ 17 ]、現在、ほとんどの米国政府のアプリケーションではSHA-2ファミリーのハッシュ関数が必須となっている[ 31 ] 。 2012年には、FlameマルウェアがMD5の脆弱性を悪用してMicrosoftのデジタル署名を偽造した[ 32 ]。
1996年にMD5の圧縮関数に衝突が発見され、ハンス・ドッベルティンはRSA研究所の技術ニュースレターで「提示された攻撃はまだMD5の実用化を脅かすものではないが、かなり近いところにある…将来的には衝突耐性のあるハッシュ関数が必要な場所ではMD5は実装されるべきではない」と書いている。[ 33 ]
2005年、研究者たちはPostScript文書[ 34 ]とX.509証明書[ 35 ]のペアを同じハッシュ値で作成することに成功しました。同年後半、MD5の設計者であるロン・リベストは、「MD5とSHA1はどちらも(衝突耐性の観点から)明らかに破綻している」と記しました。[ 36 ]
2008年12月30日、研究者グループが第25回カオスコミュニケーション会議で、MD5衝突を利用して、MD5ハッシュでチェックすると正当に見える中間証明機関証明書を作成する方法を発表しました。[ 24 ]研究者はスイスのローザンヌにあるEPFLのPS3クラスターを使用して[ 37 ]、 RapidSSLが発行した通常のSSL証明書をその発行者の機能するCA証明書に変換し、それを使用してRapidSSLが発行した正当に見える別の証明書を作成しました。RapidSSL証明書の発行元であるVerisignは、脆弱性が発表されて以来、RapidSSLのチェックサムアルゴリズムとしてMD5を使用した新しい証明書の発行を停止したと述べています。[ 38 ]ベリサインはMD5で署名された既存の証明書の失効を拒否しましたが、その対応は脆弱性の作者(アレクサンダー・ソティロフ、マーク・スティーブンス、ジェイコブ・アッペルバウム、アルジェン・レンストラ、デビッド・モルナー、ダグ・アーネ・オスヴィク、ベネ・デ・ウェーガー)によって適切であるとみなされました。[ 24 ]ブルース・シュナイアーはこの攻撃について、「MD5が壊れたハッシュ関数であることは既に分かっていた」と述べ、「誰もMD5を使うべきではない」としました。[ 39 ] SSL研究者は、「私たちが望むのは、認証局が新しい証明書を発行する際にMD5の使用をやめることです。また、他のアプリケーションにおけるMD5の使用についても再考されることを願っています」と書いています。[ 24 ]
マイクロソフトによると、2012年にFlameマルウェアの作成者はMD5衝突を利用してWindowsのコード署名証明書を偽造した。[ 32 ]
MD5 はMerkle–Damgård 構造を使用するため、同じハッシュを持つ 2 つのプレフィックスを構成できる場合、共通のサフィックスを両方に追加して、それを使用するアプリケーションで衝突が有効なデータとして受け入れられる可能性を高めることができます。 さらに、現在の衝突検出手法では任意のプレフィックスを指定できるため、攻撃者は同じコンテンツで始まる 2 つの衝突ファイルを作成できます。 攻撃者が 2 つの衝突ファイルを生成するために必要なのは、64 バイト境界に揃えられた 128 バイトのデータ ブロックを持つテンプレート ファイルだけです。このテンプレート ファイルは衝突検出アルゴリズムによって自由に変更できます。2 つのメッセージが 6 バイト異なる MD5 衝突の例を次に示します。
d131dd02c5e6eec4 693d9a0698aff95c 2fcab5 8 712467eab 4004583eb8fb7f89 55ad340609f4b302 83e4888325 7 1415a 085125e8f7cdc99f d91dbd f 280373c5b d8823e3156348f5b ae6dacd436c919c6 dd53e2 b 487da03fd 02396306d248cda0 e99f33420f577ee8 ce54b67080 a 80d1e c69821bcb6a88393 96f965 2 b6ff72a70
d131dd02c5e6eec4 693d9a0698aff95c 2fcab5 0 712467eab 4004583eb8fb7f89 55ad340609f4b302 83e4888325 f 1415a 085125e8f7cdc99f d91dbd 7 280373c5b d8823e3156348f5b ae6dacd436c919c6 dd53e2 3 487da03fd 02396306d248cda0 e99f33420f577ee8 ce54b67080 2 80d1e c69821bcb6a88393 96f965 a b6ff72a70
どちらもMD5ハッシュを生成します79054025255fb1a26e4bc422aef54eb4。[ 40 ] 2つのサンプルの違いは、各ニブルの先頭ビットが反転されている点です。例えば、上のサンプルの20番目のバイト(オフセット0x13)である0x87は、2進数では10000111です。バイトの先頭ビット(最初のニブルの先頭ビットでもある)が反転されて00000111となり、下のサンプルに示すように0x07になります。
その後、別々に選択されたプレフィックスを持つ2つのファイル間で衝突を構築することも可能であることが判明しました。この手法は、2008年に不正なCA証明書の作成に使用されました。 2014年には、Anton KuznetsovによってMPIを用いた並列衝突探索の新しい変種が提案され、計算クラスター上で11時間で衝突を発見できるようになりました。[ 41 ]
2009年4月、MD5の原像暗号耐性を破る攻撃が公開されました。この攻撃は理論上のものであり、完全な原像暗号を解くには計算量が2の123.4乗に上ります。[ 42 ] [ 43 ]
MD5ダイジェストは、転送されたファイルが完全な状態で届いたことを保証するために、ソフトウェアの世界で広く利用されている。例えば、ファイルサーバーは、ユーザーがダウンロードしたファイルのチェックサムと比較できるように、事前に計算されたMD5( md5sumと呼ばれる)チェックサムをファイルに対して提供することが多い。ほとんどのUnixベースのオペレーティングシステムでは、配布パッケージにMD5サムユーティリティが含まれている。Windowsユーザーは、同梱のPowerShell関数「Get-FileHash」、同梱のコマンドライン関数「certutil -hashfile <filename> md5」を使用するか、[ 44 ] [ 45 ] Microsoftユーティリティをインストールするか、[ 46 ] [ 47 ]サードパーティ製アプリケーションを使用する。Android ROMもこのタイプのチェックサムを使用している。

MD5衝突は発生しやすいため、ファイルを作成した人が同じチェックサムを持つ別のファイルを作成する可能性があり、この技術では一部の悪意のある改ざんから保護することはできません。場合によっては、チェックサムが信頼できないこともあります(例えば、ダウンロードしたファイルと同じチャネルで取得された場合など)。その場合、MD5はエラーチェック機能のみを提供します。つまり、破損または不完全なダウンロードを認識しますが、これは大きなファイルをダウンロードする場合に起こりやすくなります。
歴史的に、MD5はパスワードの一方向ハッシュを保存するために使用されてきました。多くの場合、キーストレッチングが使用されています。 [ 48 ] [ 49 ] NISTは、パスワード保存用の推奨ハッシュのリストにMD5を含めていません。[ 50 ]
MD5は電子情報開示の分野でも利用されており、法的証拠開示手続きで交換される各文書に一意の識別子を提供します。この方式は、紙文書の交換において数十年にわたり使用されてきたベイツスタンプ番号方式の代替として使用できます。ただし、前述の通り、衝突攻撃が発生しやすいため、この方式の使用は推奨されません。

MD5は可変長メッセージを128ビットの固定長出力に変換します。入力メッセージは512ビットのブロック(32ビットワード16個)に分割され、メッセージの長さが512で割り切れるようにパディングされます。パディングは次のように機能します。まず、メッセージの末尾に1ビット(1)が追加されます。その後、メッセージの長さが512の倍数より64ビット短くなるまで、必要な数のゼロが続きます。残りのビットは、元のメッセージの長さを表す64ビット(2 64を法とする)で埋められます。
メインのMD5アルゴリズムは、128ビットの状態を操作します。この状態は、A、B、C、Dと表記される4つの32ビットワードに分割されます。これらのワードは、特定の固定定数に初期化されます。その後、メインアルゴリズムは、512ビットのメッセージブロックを順番に使用して状態を変更します。メッセージブロックの処理は、ラウンドと呼ばれる4つの類似した段階で構成されています。各ラウンドは、非線形関数F、モジュラー加算、および左回転に基づく16の類似した演算で構成されています。図1は、ラウンド内の1つの演算を示しています。4つの可能な関数があり、各ラウンドで異なる関数が使用されます。
MD5ハッシュはこのアルゴリズムに従って計算されます。[ 51 ]すべての値はリトルエンディアンです。
// : すべての変数は符号なし32ビットで、計算時に2^32を法としてラップされます。var int s [64], K[64] var int i // sはラウンドごとのシフト量を指定します s[ 0..15] := { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22 } s[16..31] := { 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20 } s[32..47] := { 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23 } s[48..63] := { 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 } //整数の正弦の2進整数部分(ラジアン)を定数として使用します。 for i from 0 to 63 do K[i] := floor(2 32 × abs(sin(i + 1))) end for // (または、次の計算済みテーブルを使用します): K[ 0.. 3] := { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee } K[ 4.. 7] := { 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501 } K[8..11] := {0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be} K[12..15] := { 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821 } K[16..19] := { 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa } K[20..23] := { 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8 } K[24..27] := { 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed } K[28..31] := { 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a } K[32..35] := { 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c } K[36..39] := { 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70 } K[40..43] := { 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05 } K[44..47] := { 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665 } K[48..51] := { 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039 } K[52..55] := { 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1 } K[56..59] := { 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1 } K[60..63] := { 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 } //変数を初期化します: var int a0 := 0x67452301 // A var int b0 := 0xefcdab89 // B var int c0 := 0x98badcfe // C var int d0 := 0x10325476 // D//前処理: 1ビットを1つ追加するメッセージに「1」ビットを追加します< // 注意: 入力バイトはビット文字列として扱われます。 // 最初のビットはバイトの最上位ビットです。[ 52 ]//前処理: ゼロで埋め、 メッセージ長がビット単位で ≡ 448 (mod 512) になるまで「0」ビットを追加します// 注意: 上記の 2 つのパディング手順はより単純な方法で実装されています // 完全なバイトでのみ動作する実装の場合: 0x80 を追加 // メッセージの長さ(バイト)が ≡ 56(mod 64)になるように、0x00 バイトで埋め込みます。元の長さをビット単位で264で割った ものをメッセージに追加する//メッセージを連続する512ビットのチャンクで処理します。 パディングされたメッセージの512ビットのチャンクごとに、 チャンクを16個の32ビットワードM[j]に分割する(0 ≤ j ≤ 15) //このチャンクのハッシュ値を初期化します: var int A := a0 var int B := b0 var int C := c0 var int D := d0 //メインループ: iが0から63までの場合、 var int F, g を実行し、 0 ≤ i ≤ 15の場合、 F := (B and C)または(( not B) and D)を実行します g := i そうでなければ、 16 ≤ i ≤ 31の場合、 F := (DかつB)または(( D以外)かつC) g := (5×i + 1) mod 16 そうでなければ32 ≤ i ≤ 47なら F := B xor C xor D g := (3×i + 5) mod 16 そうでなければ48 ≤ i ≤ 63ならば F := C xor (Bまたは( Dでない)) g := (7×i) mod 16 //以下のa,b,c,dの定義に注意してください F := F + A + K[i] + M[g] // M[g]は32ビットブロックである必要があります A := D D := C C := B B := B + leftrotate (F, s[i]) end for //このチャンクのハッシュをこれまでの結果に追加します。 a0 := a0 + A b0 := b0 + B c0 := c0 + C d0 := d0 + D 終わりのためにvar char digest[16] := a0 append b0 append c0 append d0 // (出力はリトルエンディアンです)
RFC 1321 で示した元の定式化の代わりに、効率性を向上させるために次の式を使用できます (アセンブリ言語を使用している場合に便利です。そうでない場合、コンパイラは通常上記のコードを最適化します。これらの定式化では各計算が他の計算に依存しているため、NAND/AND を並列化できる上記の方法よりも遅くなることがよくあります)。
( 0 ≤ i ≤ 15 ): F := D xor (Bと(C xor D)) (16 ≤ i ≤ 31): F := C xor (D and (B xor C))
128ビット(16バイト)のMD5ハッシュ(メッセージダイジェストとも呼ばれます)は、通常、32桁の16進数で表されます。以下は、43バイトのASCII入力とそれに対応するMD5ハッシュを示しています。
MD5("素早い茶色のキツネは怠け者の犬を飛び越える") = 9e107d9d372bb6826bd81d3542a419d6 たとえメッセージに小さな変更があっても、雪崩効果により(圧倒的な確率で)ハッシュはほぼ変化します。例えば、文末にピリオドを追加すると、次のようになります。
MD5("素早い茶色のキツネは怠け者の犬を飛び越えます。 ") = e4d909c290d0fb1ca068ffaddf22cbd0 長さゼロの文字列のハッシュは次のとおりです。
MD5("") = d41d8cd98f00b204e9800998ecf8427e MD5アルゴリズムは、任意のビット数で構成されるメッセージに対応しており、8ビットの倍数(オクテット、バイト)に限定されません。md5sumなどの一部のMD5実装では、オクテットに制限されていたり、長さが初期値として未確定のメッセージの ストリーミングをサポートしていない場合があります。
以下は MD5 をサポートする暗号化ライブラリのリストです。
提示された攻撃は、MD5の実用化を脅かすほどではないものの、かなり近い状況にある。…[
原文ママ
] 将来、
衝突耐性ハッシュ関数が必要な状況では、MD5は実装されるべきではない。 …[
原文ママ]
(ドキュメントを表示するには、ヘルプ:FTPを参照してください)