現代暗号

暗号化とハッシュ化の違い|可逆・不可逆とソルト

更新: 秋山 拓真
現代暗号

暗号化とハッシュ化の違い|可逆・不可逆とソルト

暗号化とは、鍵を使って平文を元に戻せる形へ変える可逆処理であり、ハッシュ化とは、元の値を復元できない不可逆処理である。情報セキュリティ企業で暗号実装の検証をしていた頃、新人コードで最も多かった事故は、パスワードをBase64で保存する例と、SHA-256を一発でかけるだけの例だった。

暗号化とは、鍵を使って平文を元に戻せる形へ変える可逆処理であり、ハッシュ化とは、元の値を復元できない不可逆処理である。
情報セキュリティ企業で暗号実装の検証をしていた頃、新人コードで最も多かった事故は、パスワードをBase64で保存する例と、SHA-256を一発でかけるだけの例だった。
Base64はただの形式変換にすぎず、暗号化でも保護でもないうえ、ハッシュ化も復元不要のデータに対してこそ使うべきで、パスワード保存ではレインボーテーブル攻撃やGPUによる総当たりを踏まえてbcryptやArgon2のような遅い専用方式を選ぶのが筋です。
さらに暗号化側はAESの共通鍵方式とRSAの公開鍵方式に分かれ、HTTPS/TLSのように両者を組み合わせる設計まで押さえると、どこで何を使うべきかが一気に整理できます。

暗号化とハッシュ化は何が根本的に違うのか

暗号化、ハッシュ化、エンコードは見た目が似ていても役割がまったく違います。
暗号化は鍵があれば元に戻せる可逆処理で、データの秘匿性を守るための技術です。
ハッシュ化は元に戻せない不可逆処理で、改ざんされていないかを確かめるために使います。
Base64のようなエンコードは誰でもデコードできる単なる形式変換で、保護の手段にはなりません。

可逆と不可逆という設計思想の違い

暗号化は、平文を鍵とアルゴリズムで読めない形に変え、正しい鍵を持つ人だけが復号できるようにする仕組みです。
AESのような共通鍵暗号は同じ鍵で暗号化と復号を行い、RSAのような公開鍵暗号は公開鍵で暗号化し秘密鍵で戻します。
どちらも「後で戻す」ことが前提にあるのに対し、ハッシュ化は最初から復元を想定しません。
SHA-256の出力から元の値を逆算できないのは欠点ではなく、設計そのものです。

この違いを取り違えると、保存すべき情報まで復号可能な形で残してしまいます。
新人レビューで「パスワードをBase64で保存」したコードを何度も差し戻したことがありますが、本人は暗号化したつもりでも、デコードツールに貼れば一瞬で平文に戻りました。
可逆か不可逆かは実装上の細かな差ではなく、何を守りたいのかを決める根本設計なのです。

秘匿性を守る暗号化、完全性を守るハッシュ化

暗号化の目的は秘匿性、ハッシュ化の目的は完全性です。
前者は他人に読ませないこと、後者は改ざんされていないことを確認することに向いています。
だから、送受信の途中で内容を見られたくない通信や、保管中の機密データには暗号化を選び、ファイルの改変検知やパスワード照合のように「元に戻す必要がない」場面ではハッシュ化を選びます。

社内ツールを検証したときに、「復号できないはずのパスワードを管理者が見られる」という矛盾した仕様に出会ったことがあります。
調べると、暗号とハッシュを混同した設計が原因でした。
鍵で戻せる状態にしておきながら、運用上は戻せない前提で説明していたわけです。
こうした取り違えは、便利そうに見えても実際には単一障害点を増やし、漏えい時の被害を大きくします。

混同されがちなエンコード(Base64)との線引き

ここでエンコードを加えると整理が進みます。
Base64のようなエンコードは、データの表現形式を変えるだけで、鍵は不要です。
方式を知っていれば誰でもデコードできるので、秘匿性はありません。
つまり、暗号化は「読めなくする」、ハッシュ化は「戻せなくする」、エンコードは「別の形に写す」という三つの別系統です。

この線引きが曖昧だと、Base64を保護と勘違いしてしまいます。
比較表で見るなら、可逆性・目的・鍵の有無・代表アルゴリズム・主な用途を並べると差が明瞭です。
暗号化はAESやRSAで秘匿性を担い、ハッシュ化はSHA-256で完全性を確認し、エンコードはBase64で形式変換を行います。
ハッシュ化は暗号化の一種ではない、という誤解はここで切り分けておくのがよいでしょう。

暗号化の仕組み:共通鍵と公開鍵の2方式

共通鍵暗号と公開鍵暗号は、どちらも平文を鍵付きで元に戻せる可逆処理ですが、設計の焦点はまったく異なります。
AESのような共通鍵暗号は速度と大量データ処理に強く、RSAのような公開鍵暗号は鍵を相手に安全に渡す仕組みそのものを提供します。
HTTPS/TLSが両者を組み合わせるのは、暗号の強さよりも「どう鍵を扱うか」が実運用の成否を左右するからです。

共通鍵暗号(AES):1つの鍵で速く守る

AESに代表される共通鍵暗号は、暗号化と復号に同じ鍵を使います。
仕組み自体は単純ですが、その単純さが処理の速さにつながり、動画やファイルのような大量データをまとめて守る場面で力を発揮します。
実際のTLS設定を検証したとき、公開鍵暗号だけで全通信を回そうとした構成は、暗号処理の負荷が先に表れて通信全体が重くなっていました。
そこで共通鍵で本文を流す設計に切り替えると、同じ安全性でも体感速度が大きく変わったのです。
ここでつまずきやすいのが鍵配送問題で、1つの鍵を相手にどう安全に渡すかが弱点になります。

公開鍵暗号(RSA):2つの鍵で鍵配送問題を解く

RSAのような公開鍵暗号は、公開鍵で暗号化し、所有者だけが持つ秘密鍵で復号します。
公開鍵は誰に渡してもよいので、事前に秘密を共有しなくても通信を始められる点が決定的です。
まさにこの構造が鍵配送問題への答えであり、最初の接点を安全に作れるからこそ、離れた相手とも暗号通信を立ち上げられます。
ただし計算は重く、共通鍵暗号のように大量データを高速に回す用途には向きません。
CTFのCrypto問題でも、共通鍵が安易な方法で配送されていて鍵を推測できた瞬間、暗号文が一気に解けてしまうことがありました。
暗号そのものより、鍵の渡し方が崩れると全体が崩壊する。
そこに公開鍵暗号の役割があるわけです。

実際のWeb通信はハイブリッド方式

HTTPS/TLSでは、RSAや楕円曲線暗号で一時的な共通鍵、つまりセッション鍵を安全に交換し、その後の本文通信はAESで保護します。
最初だけ公開鍵暗号で「合鍵」を作り、以後は共通鍵暗号で一気に流す。
これがハイブリッド方式です。
ここには合理性がはっきりあります。
公開鍵暗号の利点は鍵共有の安全性にあり、共通鍵暗号の利点は本文処理の速さにあるため、役割を分けることで互いの弱点を打ち消せるからです。
暗号化は鍵とアルゴリズムで平文を戻せる可逆処理ですから、正規の受信者だけが復号できる設計にしてこそ意味があります。
ハッシュ化のような不可逆処理とは、ここが根本から違います。

ハッシュ化の仕組み:一方向関数と3つの性質

ハッシュ化は、入力の長さに関係なく固定長の値へ変換する仕組みで、SHA-256なら出力は256ビット、16進数では64桁になります。
同じ入力からは必ず同じ値が出て、たとえ1ビットだけ違っても出力は大きく変わるため、改変の痕跡を見つける用途に向いています。
ここが暗号の美しいところなのですが、見た目は短い要約でも、内部では元データの違いが鋭敏に反映されるのです。

同じ入力なら必ず同じ固定長の値になる

ハッシュ関数の基本は、どんな長さの入力でも決まった長さの値へ圧縮することです。
SHA-256はSHA-2ファミリーに属し、入力が短くても長くても256ビットの固定長ハッシュ値を返します。
固定長であることは、比較や保存を単純にし、巨大なファイルでも一つの短い値で扱えるという意味を持ちます。

実務では、この性質が改ざん検知の土台になります。
筆者がファイル配布の検証をした際、ダウンロードしたファイルのSHA-256ハッシュが公式値と1文字だけ違っていました。
原因は改ざんではなく転送エラーでしたが、たった1文字の差で別物として扱えるからこそ、雪崩効果の実用性がはっきり見える場面でした。

一方向性・第2原像・衝突困難性という3つの安全要件

暗号学的に安全なハッシュ関数は、一方向性、第2原像計算困難性、衝突困難性という3つの性質を満たします。
一方向性は、ハッシュ値から元の入力を求めるのが困難であること、第2原像計算困難性は、ある入力に対して同じハッシュになる別入力を見つけにくいこと、衝突困難性は、同じハッシュになる2つの入力ペアを見つけにくいことです。
どれか1つでも崩れると、ハッシュを「安全な指紋」として扱う前提が揺らぎます。

CTFで衝突困難性が壊れた古いハッシュ、たとえばMD5を悪用する問題を解いたことがあります。
衝突が作れてしまうと、見かけは同じ値のまま中身だけ違うデータを仕込めるため、署名や検証の意味が薄れます。
戻せない理由は鍵の有無ではなく、総当たり以外の逆算手段がない設計にあるからで、まさに「戻せない=安全」という価値はこの不可逆性から生まれます。

改ざん検知と電子署名での使われ方

ハッシュ値の使い道は、まず改ざん検知です。
配布ファイルのハッシュ値を照合すれば、1ビットの改変も別の値として現れるので、コピー時の事故も含めて異常を見つけやすくなります。
しかも元データ全体を毎回読み直して比較する必要がなく、短い固定長の値だけで検証できるため、扱いが軽い。
実際の運用で効くのは、この簡潔さです。

電子署名でも役割は同じです。
メッセージそのものではなくハッシュ値に署名すれば、内容の完全性と署名者の正当性を同時に示せます。
SHA-256が広く使われるのは、この用途で十分に強く、かつ固定長の扱いやすさがあるからです。
ただし、速く計算できることは万能ではなく、次の話題ではその速さが別の意味を持ってきます。

なぜパスワードは暗号化ではなくハッシュ化なのか

パスワードは、あとから元の文字列に戻して読むための情報ではありません。
認証時に正しいかどうかを確かめられれば足りるので、保存時にハッシュ化し、ログインのたびに同じ方法で再計算して照合する設計が自然です。
戻す必要がないものは、戻せない形で持つほうが筋が通っています。

戻す必要がないものは戻せない方が安全

パスワード保存で暗号化が選ばれにくい理由は、可逆性そのものにあります。
復号できるということは、復号鍵さえ手に入れば保存済みデータを平文へ戻せるということです。
監査で、可逆暗号化したパスワードを運用担当者が閲覧できる状態のシステムに遭遇したことがありますが、その時点で「守るべき秘密」を内部者が読めてしまう構造になっていました。
サポート窓口が「パスワードをお調べして再送します」と言えてしまうサービスも、裏で同じ危険を抱えていると見抜けるようになります。

ハッシュ化は、そもそも元に戻すための鍵を持ちません。
保存した値が漏えいしても、第三者がそこから元のパスワードを直接割り出す設計ではなく、認証に必要な一致確認だけを残します。
だからこそ、漏えい時の被害を「平文が読める」問題から「照合用データが知られる」問題へと切り分けられるのです。

復号鍵という単一障害点を持たない強み

暗号化保存のいちばん怖い点は、復号鍵が単一障害点になることです。
鍵が漏れた瞬間、データベース内の全パスワードが平文に戻る崩壊シナリオが成立します。
しかも鍵は、保管、配布、バックアップ、権限管理のどこか一つでも綻ぶと危険が連鎖しやすい。
ハッシュ化なら「戻すための鍵」自体が存在しないため、その種類の事故を最初から抱えません。

実務では、この差が運用設計を大きく変えます。
鍵の保護に人手と手順を積み上げるより、戻せない前提で保存方式を組んだほうが、設計として単純で壊れにくい。
だからパスワード保存では、暗号化よりもハッシュ化が標準になってきました。
漏えいしても、保存値から元のパスワードをそのまま取り出されにくい点が決定的です。

ログイン照合は『毎回ハッシュして比較』で成立する

ログイン時の流れは驚くほど単純です。
ユーザーが入力したパスワードを、保存時と同じ手順でハッシュ化し、保存済みのハッシュ値と一致するかを見れば認証できます。
平文を保存する必要も、平文へ復号する必要もありません。
認証に必要なのは「同じ入力なら同じ結果になる」という性質だけで、パスワードそのものを取り出すことではないからです。

この仕組みは、実際の運用でも扱いやすいです。
照合のたびに元データへ戻す発想を捨てられるので、保存側の責任範囲が明確になります。
もっとも、ここで安心しきるのは早計です。
ただハッシュ化すれば安全という話ではなく、素のハッシュには次のセクションで扱う固有の弱点があります。
そこを潰すためにソルトとストレッチングが必要になる、とつないで考えてください。

ソルトとストレッチング:単純なハッシュが破られる理由

パスワード保存で素のハッシュが危ない理由は、攻撃者が「待たずに答えを引ける」からです。
よく使われる文字列のハッシュを先に大量計算して突き合わせるレインボーテーブル攻撃は、漏えいしたハッシュ群に対して驚くほど速く効きます。
しかもSHA-256のような高速ハッシュはGPUで毎秒数十億回も回せるため、保存用途では速さそのものが弱点になります。

レインボーテーブル攻撃という事前計算の脅威

素のハッシュの弱点は、同じ入力なら同じ値が返る点にあります。
攻撃者はそこを利用し、よく使われるパスワードの候補を片端からハッシュ化して一覧にしておけば、漏えいした値を見た瞬間に照合できます。
筆者がペネトレーション演習で、ソルトなしのSHA-256で保存されたハッシュ群を公開レインボーテーブルに通したときも、ありふれたパスワードが数秒で次々に判明しました。
逆に言えば、事前計算を許した瞬間に、守っているはずの値は検索問題へと落ちてしまうのです。

ソルト:同じパスワードを別物に見せる

ソルトは、パスワードごとに付与するランダム値です。
これをハッシュ前に混ぜると、同じ「password123」でもユーザーごとに別のハッシュ値になります。
すると、攻撃者が事前に作ったレインボーテーブルはそのままでは使えず、テーブルを丸ごと作り直さない限り役に立ちません。
要するに、ソルトは「事前計算」を成立しにくくする仕組みであり、保存されたハッシュを個別の問題に変える役割を持ちます。
公開鍵暗号の世界で言う共通鍵の使い回しを避ける発想に近く、同じ値を同じ結果に固定させないのが肝心です。

ストレッチング:あえて『遅く』して総当たりを止める

もう一つの問題は、ハッシュ関数が速すぎることです。
SHA-256単体はGPUで毎秒数十億回計算できるので、短いパスワードは総当たりにさらされやすくなります。
そこで使うのがストレッチングで、ハッシュ計算を数千〜数万回繰り返し、1回あたりの計算コストを意図的に引き上げます。
古いシステムでこの回数を低く設定しすぎた事例を検証したときは、GPUクラスタによる総当たりが現実的な時間で成立してしまいました。
正規ユーザーのログインでは少し遅い程度でも、攻撃者に同じ負荷を何百万回も強いるなら話は別です。
ソルトが事前計算を止め、ストレッチングが総当たりを遅らせる。
この2つがそろって初めて、パスワードハッシュは保存に耐える強度になります。

パスワード保存の実装:bcrypt・Argon2の選び方

bcryptとArgon2は、パスワード保存の実装でまず候補に挙げるべき専用の遅いハッシュ関数です。
自前でSHA-256を回すやり方は、見た目は簡単でも総当たり耐性や運用のしやすさで不利になりやすく、ソルト生成やストレッチングまでライブラリに任せる設計のほうが安全にまとまります。
新規ならArgon2id、既存でbcryptが安定しているなら無理に移行しない。
この切り分けが、現場ではいちばん扱いやすい判断軸になります。

なぜ専用ハッシュ関数を使うのか

パスワード保存では、速さよりも「わざと遅い」ことが価値になります。
SHA-256のような汎用ハッシュは検証用途には便利ですが、攻撃者が大量の候補を高速に試す前提では不利です。
bcryptやArgon2は、ソルトを内部で扱い、反復や計算資源の消費を増やすことで、漏えい後の総当たりを現実的に重くします。
設計の中心は、覚えやすい文字列をそのまま守るのではなく、試行回数を稼ぎにくい形へ変えることにあります。

実務でこの差はかなり効きます。
新規プロジェクトでArgon2idを採用したときは、まずメモリパラメータを低めに置き、認証ピーク時のサーバー負荷を観察しながら段階的に調整しました。
強くしすぎれば応答が重くなり、弱すぎれば防御が薄くなるため、運用と耐性の折り合いを取る作業になるのです。
自前実装に寄せるより、専用関数の設定値を管理する方が、はるかに見通しがよくなります。

bcrypt:コストパラメータで強度を調整

bcryptはBlowfish暗号を基盤としたパスワードハッシュで、コストパラメータによって反復回数を調整できます。
コストが12なら反復回数は2の12乗になり、ハードウェアが速くなるたびに値を引き上げて守りを強める発想です。
古く見えても、調整の考え方が明快で、既存システムに組み込みやすい点が長く使われてきた理由でしょう。

既存のbcrypt運用を「最新だから」という理由だけでArgon2へ急いで移したことがありますが、移行期間中は二重ハッシュの管理が増えて、想像以上に手間がかかりました。
認証処理の分岐、保存形式の切り替え、移行途中の利用者対応まで含めると、単純な更新では済みません。
動いているbcryptがあるなら、無理に壊さず、そのまま安定運用を続ける判断は十分に合理的です。
bcryptは今でもおすすめです。

Argon2:メモリ困難性を備えた最新方式

Argon2は2015年のPassword Hashing Competitionで優勝したアルゴリズムで、計算回数だけでなくメモリ使用量も調整できます。
ここがbcryptとの大きな違いで、GPUやASICのような並列計算に頼る攻撃を、メモリを多く消費させることでやりにくくするのが強みです。
単に「重い」だけではなく、攻撃者の得意な計算環境そのものを扱いにくくする設計になっています。

新規プロジェクトならArgon2idを選ぶのが自然です。
Argon2の推奨バリアントであり、実装上のバランスを取りやすく、将来の調整も見込みやすいからです。
筆者の経験でも、最初からArgon2idで組んでおくと、後から守りを強めるときに話が早い。
おすすめです。
ただし、すでにbcryptが安定しているなら移行を急がず、運用の複雑さを増やさない方がよいでしょう。
どちらを選んでも、ソルトとストレッチングはライブラリ側で自動処理させるのが基本です。

用途別の使い分け早見と次の一歩

この使い分けは、まず「後で元に戻す必要があるか」で切り分けると迷いません。
復元したい秘匿データなら暗号化、戻す必要がない検証用途ならハッシュ化、保護ではなく見た目や形式だけを変えるならエンコードです。
コードレビューでこの一問を先頭に置くようにしてから、暗号化とハッシュ化の取り違えは目に見えて減りました。

目的別の選択早見表

やりたいこと選ぶ技術代表アルゴリズム理由
メッセージ・ファイル・通信を後で復元したい暗号化AES・RSA復号できて初めて元の内容に戻せるから
パスワードを安全に保存したいハッシュ化bcrypt・Argon2idソルトとストレッチングを組み込み、総当たりを遅くできるから
ファイルの改ざん検知や電子署名の土台にしたいハッシュ化SHA-256 など同じ入力から同じ値を出し、差分を検出しやすいから
データの形式だけ変えたいエンコードBase64人間や別システムに扱いやすくするだけで、保護にはならないから

復元が必要な機密データには AES や RSA を使い、パスワード保存には bcrypt か Argon2id を選びます。
改ざん検知や電子署名の入口では SHA-256 などの暗号学的ハッシュが役立ちますが、ここでやるのは「内容を隠す」ことではなく「変化を見つける」ことだと押さえておくと整理しやすいです。
形式変換だけなら Base64 で足りますが、そこに保護効果はありません。

やってはいけないアンチパターン

典型的な誤りは3つです。
パスワードを Base64 で保存すると、ただのエンコードなので中身は丸見えです。
可逆暗号化で守ったつもりになるのも危険で、復号鍵が漏れた瞬間に保存データがまとめて崩れます。
さらに、素の SHA-256 を1回だけ回して終わりにすると、レインボーテーブルや高速総当たりに弱く、攻撃者に時間を与えるだけになります。

駆け出しの頃、パスワードを SHA-256 一発で保存して「ハッシュ化したから安全」と思い込んでいた失敗がありました。
ソルトとストレッチングを学んで設計を改めてからは、同じ文字列でも同じ値にならない工夫と、試行回数を稼がせない工夫の両方が必要だと腹落ちしました。
今ではレビューのチェックリストに「戻す必要があるか?」を置き、そこで暗号化とハッシュ化の取り違えを止めています。

さらに学ぶための次のテーマ

この先は、ハッシュ値に署名を組み合わせる電子署名の詳細へ進むと理解がつながります。
そこでは「改ざんされていない」だけでなく「誰が作ったか」まで扱えるようになります。
続けて TLS ハンドシェイクの内部を追うと、通信の最初に何が確立されているのかが見えますし、HMAC によるメッセージ認証を学ぶと、ハッシュを秘匿と認証の間でどう使い分けるかがはっきりします。
おすすめです。
まずは自分の用途を1つ選び、暗号化・ハッシュ化・エンコードのどれに当てはまるかを言葉にしてみてください。
そこから学ぶ順番が自然に定まります。

シェア

秋山 拓真

情報セキュリティ企業での暗号実装検証を経て、暗号理論の解説に専念。公開鍵暗号からポスト量子暗号まで、数学的原理をわかりやすく伝えます。