はじめに
ファイルを受け取ったとき、保存後や送信中に内容が変わっていないかを確かめたい場面があります。見た目では同じでも、内部の1文字や1ビットが変わっている可能性はあります。
ハッシュ関数は、データから一定の長さのハッシュ値を作る仕組みです。同じデータへ同じハッシュ関数を使えば同じハッシュ値になり、データが変われば通常は異なるハッシュ値になります。この性質を利用して、現在のデータと信頼できる時点のデータが同じかを確認できます。
この記事では、ハッシュ関数とハッシュ値の意味、改ざんを検出する流れ、一致・不一致から分かる範囲、暗号化や電子署名との違いを解説します。読み終えると、ハッシュ関数が何を確認でき、何を保証しないのかを説明できるようになります。
ハッシュ関数とは
ハッシュ関数とは、文字列やファイルなどの入力データから、一定の長さの値を計算する関数です。入力するデータが短くても長くても、同じ方式で生成するハッシュ値の長さは一定です。
ハッシュ値は、入力データを短く圧縮して後から元へ戻すためのデータではありません。元のデータを保管する代わりにもなりません。入力データの特徴を計算結果として表し、同じデータかを比較するために利用します。
情報セキュリティでは、データが正確で変更されていない状態を完全性と呼びます。完全性を含む三つの保護目標は「情報セキュリティの3要素(CIA)とは?機密性・完全性・可用性を解説」で整理しています。
ハッシュ値の主な性質
改ざん検出などの安全性を目的とする場合は、暗号学的ハッシュ関数を使用します。主な性質は次のとおりです。
| 性質 | 意味 |
|---|---|
| 固定長 | 入力データの長さにかかわらず、同じ方式では一定の長さのハッシュ値を生成する |
| 再現性 | 同じ入力へ同じ方式を使うと、同じハッシュ値になる |
| 一方向性 | 与えられたハッシュ値に対応する入力を、現実的な計算量で見つけることが難しい |
| 衝突耐性 | 異なる二つの入力から同じハッシュ値になる組み合わせを見つけることが難しい |
ハッシュ値の長さが一定でも、入力できるデータの種類や長さは多様です。そのため、理論上は異なる入力が同じハッシュ値になる「衝突」が存在します。安全な方式では、攻撃者が意図的な衝突を現実的な計算量で見つけることを困難にしています。
ハッシュ値で改ざんを検出する流れ
ハッシュ値を比較するだけで改ざんを検出できるわけではありません。比較元となるハッシュ値が、信頼できる状態で取得・保存されていることが前提です。
- 正しいと確認できる元データからハッシュ値を生成する
- 生成したハッシュ値を、改ざんされにくい場所や信頼できる経路で保管・公開する
- 確認したいデータから、同じハッシュ関数で新しいハッシュ値を生成する
- 基準のハッシュ値と新しいハッシュ値を比較する
例えば、ソフトウェアの提供元が公式サイトでファイルのハッシュ値を公開している場合、ダウンロードしたファイルから同じ方式でハッシュ値を計算します。公式に確認した値と一致すれば、取得したファイルが基準となるファイルと同じ内容である可能性が高いと判断できます。
一致・不一致から分かること
二つのハッシュ値が一致した場合、同じハッシュ関数で計算した入力データは同じであると実用上判断できます。ただし、これは比較元のハッシュ値が信頼でき、使用した方式が用途に対して十分な衝突耐性を持つことが前提です。
不一致の場合は、二つの入力データが異なります。途中での改ざんだけでなく、保存や転送の失敗、別の版のファイル、文字コードや改行コードの違い、比較に使った方式の違いでも不一致になります。ハッシュ値の不一致だけで、誰かが悪意を持って改ざんしたと断定することはできません。
ハッシュ関数だけでは確認できないこと
通常のハッシュ関数には秘密の鍵を使いません。そのため、データとハッシュ値の両方を変更できる第三者は、変更後のデータから新しいハッシュ値を作り直せます。元データとハッシュ値を同じ経路で受け取るだけでは、その値を誰が作ったのか、正しい提供元から届いたのかを確認できません。
共通の秘密鍵を共有する当事者間で、認証値が正しい鍵で生成され、データが変わっていないことを確認する場合は、HMACなどのメッセージ認証方式を使います。公開鍵と署名者の結び付きを証明書などで確認したうえで、署名値と署名後のデータ変更を確認する場合は、ハッシュ関数と公開鍵暗号を組み合わせた電子署名を利用します。電子署名の仕組みは「電子署名とは?署名・検証の仕組みと改ざんを検出できる理由」で解説しています。
ハッシュ関数は内容を読めなくする処理でもありません。データの機密性を守る暗号化とは、次のように目的が異なります。
| 項目 | ハッシュ関数 | 暗号化 |
|---|---|---|
| 主な目的 | データの変更を確認する | 内容を読めない形にして機密性を守る |
| 元のデータ | ハッシュ値から元へ戻す処理ではない | 正しい鍵を使って復号する |
| 鍵 | 通常のハッシュ計算では使わない | 暗号化と復号に鍵を使う |
暗号化の仕組みは「暗号化と復号とは?鍵を使ってデータを守る仕組みを解説」で確認できます。
ハッシュ関数の主な利用例
代表的な利用例は、ファイルの完全性確認、電子署名、パスワード保存です。
ファイル確認では、信頼できる提供元が示す基準値と、手元のファイルから計算した値を比較します。電子署名では、データから作ったハッシュ値を署名処理へ利用し、公開鍵による検証と組み合わせて、対応する秘密鍵で署名されたことと署名後の変更を確認します。公開鍵と秘密鍵の役割は「公開鍵暗号とは?公開鍵・秘密鍵の役割と共通鍵暗号との違いを解説」で整理しています。
パスワードは、通常のハッシュ関数を一度適用するだけでは十分に保護できません。保存時には、パスワードごとに異なるソルトと、推測を繰り返す処理を高コストにする設定を使う、専用のパスワードハッシュ方式を利用します。
安全に使うための基本
安全性が確認されていない独自方式や、衝突を意図的に作れることが知られている古い方式を、セキュリティ用途へ新規採用しません。利用するOS、ライブラリ、プロトコルが提供する標準機能を使い、用途に合う現行の方式を選びます。
改ざん検出では、基準となるハッシュ値をどこから取得し、誰が変更できるかを確認します。ハッシュ関数の計算自体が正しくても、比較元の値を攻撃者が書き換えられる構成では、期待する確認はできません。
また、HMAC、電子署名、パスワードハッシュはハッシュ計算を利用しますが、通常のハッシュ関数や暗号化とは目的と必要な鍵が異なります。確認したいことに合わせて標準的な仕組みを選ぶことが重要です。
まとめ
ハッシュ関数は、入力データから一定の長さのハッシュ値を生成する仕組みです。同じ入力からは同じ値を生成し、安全な暗号学的ハッシュ関数では、与えられたハッシュ値に対応する入力や、意図的な衝突を見つけることが難しくなるよう設計されています。
データの変更を検出するには、正しいと確認できる時点のハッシュ値を信頼できる状態で保持し、確認時に同じ方式で計算した値と比較します。一致は同じ内容であることを実用上示し、不一致は内容が異なることを示しますが、不一致の原因が悪意ある改ざんかどうかまでは判断できません。
通常のハッシュ値だけでは送信者や提供元を確認できず、改ざんそのものも防止しません。必要に応じてHMAC、電子署名、暗号化、専用のパスワードハッシュ方式と役割分担することが、安全に利用する基本です。