Argon2 - 暗号化全般

暗号化全般 | IT用語集

Argon2とは

Argon2は、2015年のPassword Hashing Competition(PHC)で優勝した、現在推奨されるパスワードハッシュアルゴリズムです。ルクセンブルク大学のAlex Biryukov、Daniel Dinu、Dmitry Khovratovichらによって設計され、2013年から約2年間かけて世界中の暗号研究者・実装者が参加したコンペティションを経て選ばれました。2021年にはIETFによりRFC 9106として標準化され、事実上の業界標準として扱われています。

Argon2が解決しようとした課題は明確です。従来のパスワードハッシュ関数(bcryptやSHA系ハッシュなど)は「計算コスト」を高めることで総当たり攻撃を遅らせる設計でしたが、GPUやFPGA、専用ASICを使えば同じ計算を大量に並列実行できてしまい、攻撃者側の実効コストは相対的に下がり続けていました。Argon2は「メモリハード関数(memory-hard function)」という設計思想を採用し、計算量だけでなく大量のメモリ確保を要求することで、専用ハードウェアによる並列化・高速化を難しくしています。GPUは演算コアの数は多い一方でコアあたりのメモリ帯域・容量は限られているため、メモリ使用量を攻撃の律速要因にすることが有効な対策になります。

Argon2には3つのバリアントがあります:

  • Argon2d:メモリの参照アドレスがそれまでに処理したデータに依存する(data-dependent)方式。GPU攻撃への耐性が最も高いが、キャッシュタイミングなどのサイドチャネル攻撃に理論上は弱い
  • Argon2i:メモリの参照アドレスが入力データに依存しない(data-independent)方式。サイドチャネル攻撃に強いが、Argon2dに比べるとGPU攻撃への耐性はやや劣る
  • Argon2id:✅ 推奨。処理の前半をArgon2i方式、後半をArgon2d方式で行うハイブリッド。RFC 9106でも既定の選択肢として明記されている

仕組み・詳細解説

メモリハード関数という設計思想

Argon2の核となる考え方は「攻撃者に不釣り合いなコストを強制する」ことです。パスワード認証のたびに正規のサーバーは1回分のメモリ確保(例えば64MiB)を行えばよいのに対し、攻撃者が候補パスワードを大量に試そうとすると、試行のたびに同量のメモリを確保する必要が生じます。CPUの演算コストは専用ハードウェア(ASIC)で桁違いに高速化できますが、大容量かつ高帯域のメモリはASIC化してもコストを大きく下げにくいため、Argon2は「メモリを食わせる」ことで攻撃コストの下限を引き上げています。

内部構造:メモリ行列と圧縮関数G

Argon2は、まず入力(パスワード、ソルト、各種パラメータ、任意のペッパー、関連データ)をBLAKE2bベースのハッシュ関数でまとめて初期ブロックH0を生成します。続いて、指定されたメモリサイズ(m KiB)を1024バイト単位のブロックに分割し、並列度pで指定された本数の「レーン(lane)」に配置した行列として確保します。各ブロックは、BLAKE2bの内部処理を基にした圧縮関数Gによって、直前のブロックと(バリアントごとの規則で選ばれる)参照ブロックから計算され、行列全体が埋まるまで繰り返されます。この一連の処理を、時間コスト(t)で指定された回数だけパス(周回)し、最終的に全レーンの最後のブロックを混合して最終的なハッシュ値を出力します。

Argon2i・Argon2d・Argon2idのアドレッシング方式の違い

3つのバリアントの本質的な違いは「次にどのブロックを参照するか」を決めるアドレッシング方式にあります。Argon2dは直前に計算した値そのものを使って参照先ブロックを決めるため、攻撃者は計算順序を事前に予測してメモリを節約する攻撃(time-memory trade-off攻撃)を仕掛けにくくなりますが、参照パターンがパスワードのデータに依存するため、理論上はキャッシュのアクセスタイミングから情報が漏れる可能性が指摘されています。Argon2iは参照先を入力に依存しない値(カウンタなど)から決めるためこの懸念がありませんが、参照パターンが事前に予測可能な分、time-memory trade-off攻撃への耐性はArgon2dより下がります。Argon2idは最初のパスの前半をArgon2i方式、それ以降をArgon2d方式で処理することで、サイドチャネルの影響を受けやすい局面はi方式で守りつつ、全体としての攻撃コストはd方式に近い水準を維持する設計になっています。

並列度(レーン構造)とマルチコアの活用

並列度パラメータpは、メモリ行列をp本の独立したレーンに分割し、各レーンを個別のスレッドで並列処理できるようにするためのものです。各パスの終わりにレーン間でブロックを同期する仕組みがあるため、pを増やすと処理時間そのものは短縮できますが、消費メモリの総量(m)自体は変わりません。つまりpは「同じメモリ量をどれだけ速く処理できるか」を左右するパラメータであり、耐攻撃強度は主にmとtによって決まる点に注意が必要です。

Argon2idのパラメータ

Argon2idの強度は、以下の5項目(および2つの任意項目)の組み合わせで決まります。パラメータ設計はハードウェア性能とサービスの許容レイテンシとのトレードオフであり、「大きくすればするほど安全」ではあるものの、認証APIのレスポンスタイムやサーバーの同時ログイン処理能力とのバランスが実務上の焦点になります。

  • メモリサイズ(m):使用するメモリ量(KiB単位)。攻撃コストに最も直接的に効くパラメータで、GPU/ASIC攻撃への耐性はほぼこの値の大小で決まる
  • 反復回数(t):同じメモリ行列を何パス処理するかという時間コスト。メモリ量を増やせない制約下で強度を補うために調整する
  • 並列度(p):並列に処理するレーン数。サーバーのCPUコア数に応じて処理速度を調整する目的で使われ、強度そのものへの寄与は限定的
  • ソルト(salt):最低16バイト(128ビット)以上のランダム値を推奨。ユーザーごと・ハッシュごとに一意にすることで、レインボーテーブル攻撃や同一パスワードを使う複数ユーザーへの一括攻撃を防ぐ
  • ハッシュ長:出力長。パスワード認証用途では32バイト(256ビット)が一般的な推奨値
  • シークレット値(pepper、任意):アプリケーション側だけが知る追加の秘密値。データベースが漏えいした場合でもハッシュ単体からの解読を難しくする効果があるが、鍵管理の負担が増える
  • 関連データ(associated data、任意):ハッシュ計算に組み込める追加コンテキスト情報。用途は限定的で、多くの実装ではデフォルトのまま使わないことが多い

実装例(Python)

Pythonではargon2-cffiライブラリが広く使われており、内部でC言語のリファレンス実装(libargon2)をラップしています。以下はArgon2idを明示的に指定して利用する例です:

from argon2 import PasswordHasher, Type

# Argon2idハッシャーの初期化
ph = PasswordHasher(
    time_cost=3,        # 反復回数
    memory_cost=65536,  # 64MB
    parallelism=4,      # 4スレッド
    hash_len=32,        # 32バイト出力
    type=Type.ID        # Argon2id
)

# パスワードのハッシュ化
hash = ph.hash("my_secure_password")

# パスワードの検証
try:
    ph.verify(hash, "my_secure_password")
    print("認証成功")
except:
    print("認証失敗")

実務上は、PasswordHasher()のデフォルト値(OWASP推奨に近い設定)をそのまま使い、パラメータを独自に緩める変更は避けるのが定石です。またハッシュ文字列自体に使用したパラメータ・ソルト・バージョン情報がエンコードされているため(例:$argon2id$v=19$m=65536,t=3,p=4$...)、後からパラメータを引き上げても既存ハッシュの検証に支障は出ません。ライブラリによっては「このハッシュは現在の推奨パラメータより弱いか」を判定する関数(例:check_needs_rehash())を提供しているため、ログイン成功時にハッシュを段階的に引き上げる運用が可能です。

Python以外でも、Node.jsはargon2パッケージ、JavaはBouncy CastleやSpring SecurityのArgon2PasswordEncoder、Goはgolang.org/x/crypto/argon2、Rustはargon2クレートなど、主要言語向けに成熟した実装が提供されています。

メリット・デメリット(注意点)

メリット

  • メモリハード設計により、GPU・FPGA・ASICを用いた並列総当たり攻撃のコストを大幅に引き上げられる
  • メモリ量・反復回数・並列度を独立して調整でき、将来のハードウェア性能向上に応じて強度を段階的に引き上げられる
  • Argon2i/Argon2d/Argon2idの3方式から用途に応じて選択でき、サイドチャネル対策とGPU対策のどちらを優先するか設計者側で判断できる
  • Password Hashing Competitionという公開コンペティションを経て選定されたアルゴリズムであり、選定過程・実装ともに世界中の暗号研究者による監査を受けている
  • RFC 9106として標準化されており、主要言語向けの実装が成熟し、相互運用性・保守性が高い

デメリット・注意点

  • 大量のメモリを消費するため、同時ログインが多いサービスではサーバー側のメモリ枯渇リスクがある。認証APIのスケーリング設計にメモリ使用量を織り込む必要がある
  • コンテナやサーバーレス環境ではメモリ上限に抵触しやすく、想定外のOOM(Out of Memory)エラーの原因になりやすい
  • モバイル端末や組み込み機器などメモリに制約のある環境では、推奨パラメータをそのまま適用できない場合がある
  • 実装(言語・ライブラリ・バージョン)によってはパラメータのデフォルト値や挙動に差があり、環境間で移行する際は事前の相互検証が必要
  • 強度はパラメータ設定次第であり、「Argon2を使っている」こと自体が安全の保証にはならない。パラメータが弱ければbcryptより弱くなる場合もある

混同されやすい用語・類似技術との違い

パスワードハッシュ関数・鍵導出関数(KDF)は名称が似ているものが多く、目的や強度の前提が混同されがちです。代表的な比較を整理します。

名称メモリハード特徴・注意点
bcrypt✕(固定・小容量)1999年発表。Blowfish暗号ベース。実装によってはパスワード長が72バイトまでに制限され、メモリ使用量が固定的なためGPU攻撃への耐性はArgon2に劣る
scrypt2009年発表。Argon2と同様メモリハードだが、パラメータ(N・r・p)の関係が複雑で調整が難しく、PHCではArgon2に敗れた
PBKDF2反復回数のみで強度を調整する方式で、メモリハードではないためGPU/ASICによる並列化に弱い。FIPS準拠が必要な環境では依然として選択肢になる
SHA-256などの汎用ハッシュ高速計算を目的に設計されているため、そのままパスワード保存に使うと総当たり攻撃に極めて弱い。パスワード用途には設計上不向き
HKDFなどの鍵導出関数既に十分なエントロピーを持つ鍵材料から派生鍵を作る用途であり、低エントロピーなパスワードの保護を目的とするArgon2とは前提が異なる

特に注意したいのは「メモリハードかどうか」という軸です。bcryptやPBKDF2は計算コストの調整はできてもメモリ使用量を増やせないため、専用ハードウェアによる並列攻撃に対する耐性の伸びしろがArgon2やscryptに比べて小さくなります。一方で、bcryptは20年以上の実運用実績があり枯れている、PBKDF2はFIPS 140などの認定が必要な環境で採用実績があるなど、それぞれの用途・制約に応じた合理的な採用理由が残っている点も実務では押さえておく必要があります。

実務でのパラメータ選定:OWASP・RFC 9106・NISTの考え方

OWASP Password Storage Cheat Sheetでは、Argon2idについて用途別に複数のパラメータ構成が示されています(数値はガイドラインの改訂で変わり得るため、実装時は必ず最新版を確認してください)。

用途メモリ反復並列度
最小構成19MiB21
推奨構成46MiB11
高セキュリティ64MiB34

一方、RFC 9106自体は本文の中で2種類の推奨パラメータセットを挙げています。1つは2GiB(m=2^21 KiB)のメモリ、反復回数1、並列度4という高メモリ構成で、サーバー側に十分なメモリ余力がある場合に推奨されます。もう1つは64MiB(m=2^16 KiB)のメモリ、反復回数3、並列度4という中程度の構成で、高メモリ構成が現実的でない環境向けの代替案とされています。OWASPの推奨値がRFC本文の値よりやや軽めなのは、Webサービスの認証APIとして許容できるレイテンシ(一般に数十〜数百ミリ秒程度)を重視した実務的な折衷案だからです。

NIST(米国国立標準技術研究所)は、SP 800-63B「Digital Identity Guidelines」でパスワード(記憶シークレット)の保存に「承認された一方向鍵導出関数」を要求しており、歴史的にはPBKDF2が例示の中心でした。近年の改訂の方向性では、Argon2やscryptのようなメモリハード関数も適切な選択肢として扱う記述が拡充される傾向にありますが、版によって記載内容が異なるため、コンプライアンス要件がある場合は必ず対象バージョンの原文を確認する必要があります。出力ハッシュ長(鍵長)については、Argon2の出力をそのまま保存用ハッシュとして使うか、暗号化鍵など他の鍵を導出する用途で使うかによって、32バイト(256ビット)を基準に用途に応じて調整するのが一般的です。

トラブル事例と対策

⚠️ メモリ不足エラー

症状:コンテナ環境でメモリ不足によりハッシュ処理が失敗する、またはコンテナごと強制終了(OOM Kill)される。

対策:コンテナのメモリ制限を確認し、Argon2のメモリパラメータ(m)を、コンテナが確保できる上限に対して十分な余裕を残す値に調整する。同時実行数の上限も併せて見直す。

⚠️ 認証APIのレイテンシ増大・タイムアウト

症状:ログインAPIのレスポンスが遅くなり、負荷試験でタイムアウトが多発する。

対策:反復回数(t)やメモリ量(m)をむやみに下げるのではなく、まず並列度(p)とサーバーのCPUコア配分を見直す。ログイン処理を専用のワーカープール・キューで隔離し、他のリクエスト処理への影響を避ける構成も有効。

⚠️ 同時ログイン集中によるメモリひっ迫

症状:キャンペーンやリリース直後などアクセスが集中するタイミングで、認証サーバー全体のメモリ使用量が急増する。

対策:Argon2の1リクエストあたりのメモリ使用量(例:64MiB)×想定同時実行数を事前に見積もり、オートスケーリングの閾値やリクエストキューの上限に反映する。認証処理を他のサービスから独立したコンテナ・プロセスに切り出す設計も有効。

⚠️ ライブラリ・バージョン間の非互換

症状:異なる言語・ライブラリ間でハッシュ文字列の検証に失敗する。

対策:Argon2のハッシュ文字列はパラメータやバージョン情報(例:v=19)を含むエンコード形式(PHC string format)に従うため、多くの場合は仕様に忠実な実装であれば相互運用できる。移行前に必ず双方のライブラリで生成したハッシュを相互検証するテストを行う。

最新動向(2026年)

RFC 9106の標準化とエコシステムの成熟

2021年にArgon2はRFC 9106として標準化されました。多くのプログラミング言語でライブラリが提供されており、Djangoは3.1以降Argon2PasswordHasher(argon2-cffi依存)を標準サポートしていて、設定を追加するだけで既定のパスワードハッシュ方式をArgon2idに切り替えられます。Node.jsエコシステムでもargon2パッケージの更新が継続しており、2026年時点でも新規プロジェクトの多くがデフォルト候補としてArgon2idを検討する状況が続いています。

bcryptからの移行

既存のbcryptハッシュは、ユーザーのログイン時にArgon2idで再ハッシュすることで段階的に移行できます。パスワードの平文はログイン成功時にしかサーバー側で得られないため、バッチ処理による一括移行はできず、「次回ログイン時に再ハッシュする」という段階的な移行が現実的な手法になります。

耐量子性に関する議論

Argon2はハッシュ関数ベースの構成であり、RSAや楕円曲線暗号のように量子コンピュータによる直接的な解読アルゴリズムが知られているわけではありません。ただし、長期的な安全マージンを確保する観点から、出力長やパラメータの見直しを継続的に検討する議論は今後も続くと見られます。

📝 関連ブログ記事

【2026年最新】OpenSSLの深刻な問題とは?

よくある質問(FAQ)

Q. Argon2とは何ですか?

Argon2は2015年のPassword Hashing Competition(PHC)で優勝したパスワードハッシュアルゴリズムです。メモリハード設計により、専用ASICやGPUを使ったブルートフォース攻撃を困難にします。バリアントとしてArgon2i(サイドチャネル攻撃対策)、Argon2d(GPU攻撃対策)、Argon2id(両方対策の推奨版)があります。

Q. ArgOn2とbcrypt・scryptの違いは何ですか?

bcryptは1999年から使われる古典的アルゴリズムで、メモリ使用量が固定(4KB)のため現代のGPU攻撃に対して弱くなっています。scryptはメモリハードですが、パラメータ設定が複雑です。Argon2idはメモリ使用量・並列度・イテレーション数を柔軟に設定でき、OWASPが2024年時点で第一推奨するアルゴリズムです。

Q. Argon2のパスワードハッシュをPythonで実装するには?

pip install argon2-cffiでインストール後、from argon2 import PasswordHasherでPasswordHasherクラスを使います。ph = PasswordHasher(); hash = ph.hash('パスワード'); ph.verify(hash, '入力パスワード') という形で利用できます。デフォルトパラメータはOWASPの推奨値に設定されているため、特別な理由がなければデフォルトのまま使用を推奨します。

Q. bcryptからArgon2へ移行すべきですか?

既存システムのbcryptが最新コストパラメータで動作していれば、直ちに移行する必要はありません。新規システムや大規模リファクタリングの機会があればArgon2idへの移行を推奨します。移行時は、ユーザーの次回ログイン時にパスワードを再ハッシュする段階的移行が一般的です。

Q. Argon2のメモリ使用量はサーバー運用にどう影響しますか?

Argon2はパラメータで指定したメモリ量(例:64MiB)をログイン処理のたびに確保するため、同時ログインが多いサービスではその合計がサーバーのメモリを圧迫しやすくなります。コンテナ環境ではメモリ上限に達してOOM Killが発生することもあるため、想定同時実行数×1リクエストあたりのメモリ量を事前に見積もり、オートスケーリングやキューイングの設計に反映することが実務上重要です。

Q. NISTはArgon2をどのように扱っていますか?

NISTのSP 800-63B「Digital Identity Guidelines」は、パスワード保存に承認された一方向鍵導出関数を使うことを求めており、歴史的にはPBKDF2が中心的に例示されてきました。近年の改訂の方向性ではArgon2やscryptのようなメモリハード関数も選択肢として扱う記述が拡充される傾向にありますが、版によって内容が異なるため、コンプライアンス要件がある場合は対象バージョンの原文を必ず確認してください。

セキュリティ実装のご相談