Argon2

パスワードハッシュ化セキュリティ暗号学認証PythonNode.jsJavaGoRustPHP

パスワードハッシュ化ライブラリ

Argon2

概要

Argon2は2015年Password Hashing Competition(PHC)の勝者として選出された最新の鍵導出関数で、2025年現在、パスワードハッシュ化の業界標準として確立されています。メモリハード設計により、GPU やASIC を用いた並列攻撃に対して高い耐性を持ち、設定可能なパラメータにより多様なセキュリティ要件に対応します。Argon2d、Argon2i、Argon2id の3つのバリアントを提供し、用途に応じて最適な実装を選択できます。Python、Node.js、Java、Go、Rust、PHP等の主要プログラミング言語での豊富な実装により、あらゆるアプリケーション環境で採用可能です。OWASP、NIST、ENISA等の主要セキュリティ組織によって推奨されており、現代的なWebアプリケーションにおけるパスワードセキュリティの基盤技術として広く採用されています。

詳細

Argon2は、メモリハード関数として設計されており、攻撃者がGPUやASICを使用した並列クラッキング攻撃を行うことを困難にします。メモリ使用量、並列度、実行時間の3つのパラメータを調整することで、ハードウェア環境とセキュリティ要件に応じた最適化が可能です。Argon2dはデータ依存メモリアクセスにより高速でGPU攻撃に強い一方、Argon2iはデータ独立メモリアクセスによりサイドチャネル攻撃に耐性があります。Argon2idは両者のハイブリッドとして、バランスの取れたセキュリティを提供します。ソルト自動生成、設定可能コスト、クロスプラットフォーム対応により、エンタープライズレベルのセキュリティ要件を満たします。

主な特徴

  • メモリハード設計: GPU/ASIC並列攻撃に対する高い耐性
  • 3つのバリアント: Argon2d、Argon2i、Argon2id で用途別最適化
  • 設定可能パラメータ: メモリ、並列度、時間コストの調整可能
  • マルチ言語対応: Python、Node.js、Java、Go、Rust、PHP等での実装
  • 業界標準認定: OWASP、NIST、ENISA推奨のセキュリティ標準
  • クロスプラットフォーム: Windows、Linux、macOS等での安定動作

メリット・デメリット

メリット

  • PHC勝者として業界最高水準のセキュリティを提供
  • メモリハード設計により現代的な攻撃手法に対して高い耐性
  • 設定可能パラメータで多様な環境とセキュリティ要件に対応
  • 豊富な言語実装でプラットフォーム制約なく採用可能
  • 主要セキュリティ組織による推奨で信頼性が保証
  • 将来的なハードウェア進歩に対応可能な柔軟な設計

デメリット

  • 従来のハッシュ関数と比較してメモリ使用量とCPU負荷が高い
  • パラメータ調整には暗号学とハードウェア性能の深い理解が必要
  • メモリ制約のある環境(組み込みシステム等)では利用困難
  • レガシーシステムからの移行に計画的なアプローチが必要
  • 不適切なパラメータ設定により性能問題やセキュリティ低下の可能性
  • 一部の古いプラットフォームでは実装が制限される場合がある

参考ページ

書き方の例

Python実装(argon2-cffi使用)

# requirements.txt
# argon2-cffi==23.1.0

import argon2
from argon2 import PasswordHasher
from argon2.exceptions import VerifyMismatchError, HashingError

class SecurePasswordManager:
    def __init__(self):
        # 推奨パラメータでPasswordHasherを初期化
        self.ph = PasswordHasher(
            time_cost=3,        # 3回の反復(推奨最小値)
            memory_cost=65536,  # 64 MiB メモリ使用
            parallelism=1,      # 1スレッド(必要に応じて調整)
            hash_len=32,        # 32バイトハッシュ出力
            salt_len=16         # 16バイトソルト
        )
    
    def hash_password(self, password: str) -> str:
        """パスワードをArgon2でハッシュ化"""
        try:
            # パスワードをハッシュ化(ソルトは自動生成)
            hash_value = self.ph.hash(password)
            print(f"パスワードハッシュ生成成功")
            return hash_value
        except HashingError as e:
            print(f"ハッシュ化エラー: {e}")
            raise
    
    def verify_password(self, hash_value: str, password: str) -> bool:
        """パスワードとハッシュを照合"""
        try:
            self.ph.verify(hash_value, password)
            print("パスワード照合成功")
            return True
        except VerifyMismatchError:
            print("パスワード照合失敗")
            return False
        except Exception as e:
            print(f"照合エラー: {e}")
            raise
    
    def check_needs_rehash(self, hash_value: str) -> bool:
        """ハッシュの再計算が必要かチェック"""
        return self.ph.check_needs_rehash(hash_value)

# 使用例
password_manager = SecurePasswordManager()

# ユーザー登録時
user_password = "secure_password_123!"
password_hash = password_manager.hash_password(user_password)
print(f"生成されたハッシュ: {password_hash}")

# ログイン時
if password_manager.verify_password(password_hash, user_password):
    print("ログイン成功")
else:
    print("ログイン失敗")

# ハッシュアップグレードチェック
if password_manager.check_needs_rehash(password_hash):
    print("ハッシュの再計算を推奨")
    new_hash = password_manager.hash_password(user_password)
    print(f"新しいハッシュ: {new_hash}")

Node.js実装(argon2パッケージ使用)

// package.json依存関係
// "argon2": "^0.31.2"

const argon2 = require('argon2');

class NodePasswordManager {
    constructor() {
        // Argon2id設定(推奨バリアント)
        this.options = {
            type: argon2.argon2id,  // Argon2id使用
            memoryCost: 2 ** 16,    // 64 MiB
            timeCost: 3,            // 3回の反復
            parallelism: 1,         // 1並列スレッド
            hashLength: 32,         // 32バイト出力
            saltLength: 16,         // 16バイトソルト
        };
    }

    async hashPassword(password) {
        try {
            console.log('パスワードハッシュ化開始...');
            const hash = await argon2.hash(password, this.options);
            console.log('ハッシュ化完了');
            return hash;
        } catch (error) {
            console.error('ハッシュ化エラー:', error);
            throw error;
        }
    }

    async verifyPassword(hash, password) {
        try {
            console.log('パスワード照合開始...');
            const isValid = await argon2.verify(hash, password);
            console.log(`照合結果: ${isValid ? '成功' : '失敗'}`);
            return isValid;
        } catch (error) {
            console.error('照合エラー:', error);
            return false;
        }
    }

    async needsRehash(hash) {
        try {
            return await argon2.needsRehash(hash, this.options);
        } catch (error) {
            console.error('リハッシュ判定エラー:', error);
            return false;
        }
    }

    // Express.jsミドルウェア例
    createAuthMiddleware() {
        return async (req, res, next) => {
            const { password, hash } = req.body;
            
            if (!password || !hash) {
                return res.status(400).json({ 
                    error: 'パスワードとハッシュが必要です' 
                });
            }

            try {
                const isValid = await this.verifyPassword(hash, password);
                if (isValid) {
                    // ハッシュアップグレードチェック
                    if (await this.needsRehash(hash)) {
                        const newHash = await this.hashPassword(password);
                        req.newHash = newHash;
                    }
                    next();
                } else {
                    res.status(401).json({ error: '認証失敗' });
                }
            } catch (error) {
                res.status(500).json({ error: '認証エラー' });
            }
        };
    }
}

// 使用例
async function main() {
    const passwordManager = new NodePasswordManager();
    
    const password = 'user_secure_password_2025!';
    
    // パスワードハッシュ化
    const hash = await passwordManager.hashPassword(password);
    console.log('生成ハッシュ:', hash);
    
    // パスワード照合
    const isValid = await passwordManager.verifyPassword(hash, password);
    console.log('照合結果:', isValid);
    
    // 間違ったパスワードのテスト
    const isInvalid = await passwordManager.verifyPassword(hash, 'wrong_password');
    console.log('間違ったパスワード結果:', isInvalid);
    
    // リハッシュ必要性チェック
    const needsRehash = await passwordManager.needsRehash(hash);
    console.log('リハッシュ必要:', needsRehash);
}

main().catch(console.error);

Java実装(argon2-jvm使用)

// build.gradle または pom.xml
// implementation 'de.mkammerer:argon2-jvm:2.12'

import de.mkammerer.argon2.Argon2;
import de.mkammerer.argon2.Argon2Factory;
import de.mkammerer.argon2.Argon2Helper;

public class JavaPasswordManager {
    private final Argon2 argon2;
    private final int iterations;
    private final int memory;
    private final int parallelism;

    public JavaPasswordManager() {
        this.argon2 = Argon2Factory.create();
        this.memory = 65536;      // 64 MiB
        this.parallelism = 1;     // 1並列スレッド
        
        // 最適な反復回数を動的計算(1秒以内で完了する回数)
        this.iterations = Argon2Helper.findIterations(
            argon2, 1000, memory, parallelism
        );
        
        System.out.println("最適反復回数: " + iterations);
    }

    public String hashPassword(String password) {
        char[] passwordChars = password.toCharArray();
        try {
            System.out.println("パスワードハッシュ化開始...");
            String hash = argon2.hash(iterations, memory, parallelism, passwordChars);
            System.out.println("ハッシュ化完了");
            return hash;
        } finally {
            // セキュリティのため機密データを消去
            argon2.wipeArray(passwordChars);
        }
    }

    public boolean verifyPassword(String hash, String password) {
        char[] passwordChars = password.toCharArray();
        try {
            System.out.println("パスワード照合開始...");
            boolean isValid = argon2.verify(hash, passwordChars);
            System.out.println("照合結果: " + (isValid ? "成功" : "失敗"));
            return isValid;
        } finally {
            // セキュリティのため機密データを消去
            argon2.wipeArray(passwordChars);
        }
    }

    public void close() {
        // リソースクリーンアップ
        if (argon2 != null) {
            // 必要に応じてクリーンアップ処理
        }
    }

    // Spring Security統合例
    public static class Argon2PasswordEncoder 
            implements org.springframework.security.crypto.password.PasswordEncoder {
        
        private final JavaPasswordManager passwordManager;

        public Argon2PasswordEncoder() {
            this.passwordManager = new JavaPasswordManager();
        }

        @Override
        public String encode(CharSequence rawPassword) {
            return passwordManager.hashPassword(rawPassword.toString());
        }

        @Override
        public boolean matches(CharSequence rawPassword, String encodedPassword) {
            return passwordManager.verifyPassword(encodedPassword, rawPassword.toString());
        }
    }

    // 使用例
    public static void main(String[] args) {
        JavaPasswordManager manager = new JavaPasswordManager();
        
        try {
            String password = "enterprise_password_2025!";
            
            // パスワードハッシュ化
            String hash = manager.hashPassword(password);
            System.out.println("生成ハッシュ: " + hash);
            
            // パスワード照合
            boolean isValid = manager.verifyPassword(hash, password);
            System.out.println("照合成功: " + isValid);
            
            // 間違ったパスワードテスト
            boolean isInvalid = manager.verifyPassword(hash, "wrong_password");
            System.out.println("間違ったパスワード: " + isInvalid);
            
        } finally {
            manager.close();
        }
    }
}

Go実装(golang.org/x/crypto/argon2使用)

// go.mod
// require golang.org/x/crypto v0.17.0

package main

import (
    "crypto/rand"
    "crypto/subtle"
    "encoding/base64"
    "errors"
    "fmt"
    "strings"

    "golang.org/x/crypto/argon2"
)

type Argon2Params struct {
    Memory      uint32
    Iterations  uint32
    Parallelism uint8
    SaltLength  uint32
    KeyLength   uint32
}

type GoPasswordManager struct {
    params Argon2Params
}

func NewGoPasswordManager() *GoPasswordManager {
    return &GoPasswordManager{
        params: Argon2Params{
            Memory:      64 * 1024, // 64 MiB
            Iterations:  3,         // 3回反復
            Parallelism: 1,         // 1並列スレッド
            SaltLength:  16,        // 16バイトソルト
            KeyLength:   32,        // 32バイトキー
        },
    }
}

func (pm *GoPasswordManager) HashPassword(password string) (string, error) {
    fmt.Println("パスワードハッシュ化開始...")
    
    // ランダムソルト生成
    salt := make([]byte, pm.params.SaltLength)
    if _, err := rand.Read(salt); err != nil {
        return "", fmt.Errorf("ソルト生成エラー: %w", err)
    }

    // Argon2idでハッシュ計算
    hash := argon2.IDKey(
        []byte(password),
        salt,
        pm.params.Iterations,
        pm.params.Memory,
        pm.params.Parallelism,
        pm.params.KeyLength,
    )

    // エンコード形式: $argon2id$v=19$m=65536,t=3,p=1$salt$hash
    encodedHash := fmt.Sprintf(
        "$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s",
        argon2.Version,
        pm.params.Memory,
        pm.params.Iterations,
        pm.params.Parallelism,
        base64.RawStdEncoding.EncodeToString(salt),
        base64.RawStdEncoding.EncodeToString(hash),
    )

    fmt.Println("ハッシュ化完了")
    return encodedHash, nil
}

func (pm *GoPasswordManager) VerifyPassword(encodedHash, password string) (bool, error) {
    fmt.Println("パスワード照合開始...")
    
    // ハッシュをパース
    params, salt, hash, err := pm.decodeHash(encodedHash)
    if err != nil {
        return false, fmt.Errorf("ハッシュデコードエラー: %w", err)
    }

    // 入力パスワードでハッシュ再計算
    computedHash := argon2.IDKey(
        []byte(password),
        salt,
        params.Iterations,
        params.Memory,
        params.Parallelism,
        params.KeyLength,
    )

    // 定数時間比較でタイミング攻撃を防止
    isValid := subtle.ConstantTimeCompare(hash, computedHash) == 1
    fmt.Printf("照合結果: %t\n", isValid)
    return isValid, nil
}

func (pm *GoPasswordManager) decodeHash(encodedHash string) (*Argon2Params, []byte, []byte, error) {
    parts := strings.Split(encodedHash, "$")
    if len(parts) != 6 {
        return nil, nil, nil, errors.New("無効なハッシュ形式")
    }

    if parts[1] != "argon2id" {
        return nil, nil, nil, errors.New("サポートされていないArgon2バリアント")
    }

    var version int
    if _, err := fmt.Sscanf(parts[2], "v=%d", &version); err != nil {
        return nil, nil, nil, err
    }

    params := &Argon2Params{}
    if _, err := fmt.Sscanf(parts[3], "m=%d,t=%d,p=%d", 
        &params.Memory, &params.Iterations, &params.Parallelism); err != nil {
        return nil, nil, nil, err
    }

    salt, err := base64.RawStdEncoding.DecodeString(parts[4])
    if err != nil {
        return nil, nil, nil, err
    }

    hash, err := base64.RawStdEncoding.DecodeString(parts[5])
    if err != nil {
        return nil, nil, nil, err
    }

    params.SaltLength = uint32(len(salt))
    params.KeyLength = uint32(len(hash))

    return params, salt, hash, nil
}

// HTTPハンドラー例
func (pm *GoPasswordManager) AuthenticationHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "POSTメソッドのみ許可", http.StatusMethodNotAllowed)
        return
    }

    var authReq struct {
        Password string `json:"password"`
        Hash     string `json:"hash"`
    }

    if err := json.NewDecoder(r.Body).Decode(&authReq); err != nil {
        http.Error(w, "無効なJSON", http.StatusBadRequest)
        return
    }

    isValid, err := pm.VerifyPassword(authReq.Hash, authReq.Password)
    if err != nil {
        http.Error(w, "認証エラー", http.StatusInternalServerError)
        return
    }

    response := map[string]interface{}{
        "authenticated": isValid,
        "timestamp":     time.Now().Unix(),
    }

    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(response)
}

// 使用例
func main() {
    manager := NewGoPasswordManager()
    
    password := "golang_secure_2025!"
    
    // パスワードハッシュ化
    hash, err := manager.HashPassword(password)
    if err != nil {
        fmt.Printf("ハッシュ化エラー: %v\n", err)
        return
    }
    fmt.Printf("生成ハッシュ: %s\n", hash)
    
    // パスワード照合
    isValid, err := manager.VerifyPassword(hash, password)
    if err != nil {
        fmt.Printf("照合エラー: %v\n", err)
        return
    }
    fmt.Printf("照合成功: %t\n", isValid)
    
    // 間違ったパスワードテスト
    isInvalid, err := manager.VerifyPassword(hash, "wrong_password")
    if err != nil {
        fmt.Printf("照合エラー: %v\n", err)
        return
    }
    fmt.Printf("間違ったパスワード: %t\n", isInvalid)
}

Rust実装(argon2クレート使用)

// Cargo.toml
// [dependencies]
// argon2 = "0.5.2"
// rand = "0.8.5"
// thiserror = "1.0.50"

use argon2::{
    Argon2, PasswordHash, PasswordHasher, PasswordVerifier, 
    Algorithm, Version, Params
};
use rand::{rngs::OsRng, RngCore};
use std::time::Instant;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum PasswordError {
    #[error("ハッシュ化エラー: {0}")]
    HashingError(#[from] argon2::password_hash::Error),
    #[error("ソルト生成エラー")]
    SaltGenerationError,
    #[error("パスワード照合失敗")]
    VerificationFailed,
}

pub struct RustPasswordManager {
    argon2: Argon2<'static>,
    params: Params,
}

impl RustPasswordManager {
    pub fn new() -> Result<Self, PasswordError> {
        println!("Rustパスワードマネージャー初期化...");
        
        // Argon2idパラメータ設定
        let params = Params::new(
            65536,  // 64 MiB メモリコスト
            3,      // 3回反復
            1,      // 1並列スレッド
            Some(32) // 32バイトハッシュ出力
        ).map_err(PasswordError::HashingError)?;

        let argon2 = Argon2::new(
            Algorithm::Argon2id,
            Version::V0x13,
            params.clone(),
        );

        Ok(Self { argon2, params })
    }

    pub fn hash_password(&self, password: &str) -> Result<String, PasswordError> {
        println!("パスワードハッシュ化開始...");
        let start = Instant::now();

        // ソルト生成
        let mut salt = [0u8; 16];
        OsRng.fill_bytes(&mut salt);

        // パスワードハッシュ化
        let password_hash = self.argon2
            .hash_password(password.as_bytes(), &salt)
            .map_err(PasswordError::HashingError)?;

        let duration = start.elapsed();
        println!("ハッシュ化完了 (所要時間: {:?})", duration);

        Ok(password_hash.to_string())
    }

    pub fn verify_password(&self, hash: &str, password: &str) -> Result<bool, PasswordError> {
        println!("パスワード照合開始...");
        let start = Instant::now();

        // ハッシュをパース
        let parsed_hash = PasswordHash::new(hash)
            .map_err(PasswordError::HashingError)?;

        // パスワード照合
        let result = self.argon2
            .verify_password(password.as_bytes(), &parsed_hash);

        let duration = start.elapsed();
        
        match result {
            Ok(()) => {
                println!("照合成功 (所要時間: {:?})", duration);
                Ok(true)
            }
            Err(_) => {
                println!("照合失敗 (所要時間: {:?})", duration);
                Ok(false)
            }
        }
    }

    pub fn get_params_info(&self) -> String {
        format!(
            "Argon2id - メモリ: {} KiB, 反復: {}, 並列: {}",
            self.params.m_cost(),
            self.params.t_cost(),
            self.params.p_cost()
        )
    }
}

// 非同期Web フレームワーク(Axum)との統合例
#[cfg(feature = "axum")]
use axum::{
    extract::Json,
    http::StatusCode,
    response::Json as ResponseJson,
    routing::post,
    Router,
};

#[cfg(feature = "axum")]
#[derive(serde::Deserialize)]
struct AuthRequest {
    password: String,
    hash: String,
}

#[cfg(feature = "axum")]
#[derive(serde::Serialize)]
struct AuthResponse {
    authenticated: bool,
    message: String,
    timestamp: u64,
}

#[cfg(feature = "axum")]
async fn authenticate_password(
    Json(payload): Json<AuthRequest>,
) -> Result<ResponseJson<AuthResponse>, StatusCode> {
    let password_manager = RustPasswordManager::new()
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    match password_manager.verify_password(&payload.hash, &payload.password) {
        Ok(is_valid) => {
            let response = AuthResponse {
                authenticated: is_valid,
                message: if is_valid { 
                    "認証成功".to_string() 
                } else { 
                    "認証失敗".to_string() 
                },
                timestamp: std::time::SystemTime::now()
                    .duration_since(std::time::UNIX_EPOCH)
                    .unwrap()
                    .as_secs(),
            };
            Ok(ResponseJson(response))
        }
        Err(_) => Err(StatusCode::INTERNAL_SERVER_ERROR),
    }
}

#[cfg(feature = "axum")]
fn create_app() -> Router {
    Router::new()
        .route("/authenticate", post(authenticate_password))
}

// 使用例とテスト
fn main() -> Result<(), Box<dyn std::error::Error>> {
    let password_manager = RustPasswordManager::new()?;
    
    println!("設定情報: {}", password_manager.get_params_info());
    
    let password = "rust_secure_password_2025!";
    
    // パスワードハッシュ化
    let hash = password_manager.hash_password(password)?;
    println!("生成ハッシュ: {}", hash);
    
    // パスワード照合
    let is_valid = password_manager.verify_password(&hash, password)?;
    println!("照合成功: {}", is_valid);
    
    // 間違ったパスワードテスト
    let is_invalid = password_manager.verify_password(&hash, "wrong_password")?;
    println!("間違ったパスワード: {}", is_invalid);
    
    // パフォーマンステスト
    println!("\nパフォーマンステスト開始...");
    let iterations = 5;
    let mut total_time = std::time::Duration::new(0, 0);
    
    for i in 1..=iterations {
        let start = Instant::now();
        let test_hash = password_manager.hash_password(&format!("test_password_{}", i))?;
        let duration = start.elapsed();
        total_time += duration;
        
        println!("テスト {}: {:?}", i, duration);
    }
    
    let average_time = total_time / iterations;
    println!("平均ハッシュ化時間: {:?}", average_time);
    
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_password_hashing_and_verification() {
        let manager = RustPasswordManager::new().unwrap();
        let password = "test_password_123!";
        
        let hash = manager.hash_password(password).unwrap();
        assert!(manager.verify_password(&hash, password).unwrap());
        assert!(!manager.verify_password(&hash, "wrong_password").unwrap());
    }

    #[test]
    fn test_different_passwords_different_hashes() {
        let manager = RustPasswordManager::new().unwrap();
        
        let hash1 = manager.hash_password("password1").unwrap();
        let hash2 = manager.hash_password("password2").unwrap();
        
        assert_ne!(hash1, hash2);
    }

    #[test]
    fn test_same_password_different_hashes() {
        let manager = RustPasswordManager::new().unwrap();
        let password = "same_password";
        
        let hash1 = manager.hash_password(password).unwrap();
        let hash2 = manager.hash_password(password).unwrap();
        
        // 異なるソルトにより異なるハッシュが生成される
        assert_ne!(hash1, hash2);
        
        // 両方とも同じパスワードで照合成功
        assert!(manager.verify_password(&hash1, password).unwrap());
        assert!(manager.verify_password(&hash2, password).unwrap());
    }
}

PHP実装(PHP 7.2+ネイティブ対応)

<?php
// PHP 7.2以降でArgon2ネイティブサポート

class PHPPasswordManager {
    private $options;
    
    public function __construct() {
        // Argon2id推奨設定
        $this->options = [
            'memory_cost' => 65536,  // 64 MiB
            'time_cost' => 3,        // 3回反復
            'threads' => 1,          // 1並列スレッド
        ];
        
        echo "PHPパスワードマネージャー初期化完了\n";
        echo "設定: " . json_encode($this->options) . "\n";
    }
    
    public function hashPassword($password) {
        echo "パスワードハッシュ化開始...\n";
        $start = microtime(true);
        
        try {
            // PASSWORD_ARGON2IDを使用(PHP 7.2+)
            $hash = password_hash($password, PASSWORD_ARGON2ID, $this->options);
            
            $duration = (microtime(true) - $start) * 1000;
            echo "ハッシュ化完了 (所要時間: {$duration}ms)\n";
            
            return $hash;
        } catch (Exception $e) {
            echo "ハッシュ化エラー: " . $e->getMessage() . "\n";
            throw $e;
        }
    }
    
    public function verifyPassword($hash, $password) {
        echo "パスワード照合開始...\n";
        $start = microtime(true);
        
        try {
            $isValid = password_verify($password, $hash);
            
            $duration = (microtime(true) - $start) * 1000;
            echo "照合結果: " . ($isValid ? "成功" : "失敗") . " (所要時間: {$duration}ms)\n";
            
            return $isValid;
        } catch (Exception $e) {
            echo "照合エラー: " . $e->getMessage() . "\n";
            return false;
        }
    }
    
    public function needsRehash($hash) {
        return password_needs_rehash($hash, PASSWORD_ARGON2ID, $this->options);
    }
    
    public function getInfo($hash) {
        return password_get_info($hash);
    }
    
    // Laravel統合例
    public function laravelHasher() {
        return new class($this->options) extends \Illuminate\Hashing\AbstractHasher {
            private $options;
            
            public function __construct($options) {
                $this->options = $options;
            }
            
            public function make($value, array $options = []) {
                return password_hash($value, PASSWORD_ARGON2ID, array_merge($this->options, $options));
            }
            
            public function check($value, $hashedValue, array $options = []) {
                return password_verify($value, $hashedValue);
            }
            
            public function needsRehash($hashedValue, array $options = []) {
                return password_needs_rehash($hashedValue, PASSWORD_ARGON2ID, array_merge($this->options, $options));
            }
        };
    }
}

// Symfony統合例
class SymfonyArgon2PasswordHasher implements \Symfony\Component\PasswordHasher\PasswordHasherInterface {
    private $options;
    
    public function __construct(array $options = []) {
        $this->options = array_merge([
            'memory_cost' => 65536,
            'time_cost' => 3,
            'threads' => 1,
        ], $options);
    }
    
    public function hash(#[\SensitiveParameter] string $plainPassword): string {
        return password_hash($plainPassword, PASSWORD_ARGON2ID, $this->options);
    }
    
    public function verify(string $hashedPassword, #[\SensitiveParameter] string $plainPassword): bool {
        return password_verify($plainPassword, $hashedPassword);
    }
    
    public function needsRehash(string $hashedPassword): bool {
        return password_needs_rehash($hashedPassword, PASSWORD_ARGON2ID, $this->options);
    }
}

// 使用例
try {
    $passwordManager = new PHPPasswordManager();
    
    $password = 'php_secure_password_2025!';
    
    // パスワードハッシュ化
    $hash = $passwordManager->hashPassword($password);
    echo "生成ハッシュ: $hash\n";
    
    // パスワード照合
    $isValid = $passwordManager->verifyPassword($hash, $password);
    echo "照合成功: " . ($isValid ? 'true' : 'false') . "\n";
    
    // 間違ったパスワードテスト
    $isInvalid = $passwordManager->verifyPassword($hash, 'wrong_password');
    echo "間違ったパスワード: " . ($isInvalid ? 'true' : 'false') . "\n";
    
    // ハッシュ情報表示
    $info = $passwordManager->getInfo($hash);
    echo "ハッシュ情報: " . json_encode($info, JSON_PRETTY_PRINT) . "\n";
    
    // リハッシュ必要性チェック
    $needsRehash = $passwordManager->needsRehash($hash);
    echo "リハッシュ必要: " . ($needsRehash ? 'true' : 'false') . "\n";
    
    // パフォーマンステスト
    echo "\nパフォーマンステスト開始...\n";
    $iterations = 5;
    $totalTime = 0;
    
    for ($i = 1; $i <= $iterations; $i++) {
        $start = microtime(true);
        $testHash = $passwordManager->hashPassword("test_password_$i");
        $duration = (microtime(true) - $start) * 1000;
        $totalTime += $duration;
        
        echo "テスト $i: {$duration}ms\n";
    }
    
    $averageTime = $totalTime / $iterations;
    echo "平均ハッシュ化時間: {$averageTime}ms\n";
    
} catch (Exception $e) {
    echo "エラー: " . $e->getMessage() . "\n";
}

// Web API例(シンプルなREST API)
function handlePasswordAPI() {
    header('Content-Type: application/json');
    
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
        http_response_code(405);
        echo json_encode(['error' => 'POSTメソッドのみ許可']);
        return;
    }
    
    $input = json_decode(file_get_contents('php://input'), true);
    
    if (!isset($input['action'])) {
        http_response_code(400);
        echo json_encode(['error' => 'actionが必要です']);
        return;
    }
    
    $passwordManager = new PHPPasswordManager();
    
    try {
        switch ($input['action']) {
            case 'hash':
                if (!isset($input['password'])) {
                    http_response_code(400);
                    echo json_encode(['error' => 'passwordが必要です']);
                    return;
                }
                
                $hash = $passwordManager->hashPassword($input['password']);
                echo json_encode([
                    'success' => true,
                    'hash' => $hash,
                    'timestamp' => time()
                ]);
                break;
                
            case 'verify':
                if (!isset($input['password']) || !isset($input['hash'])) {
                    http_response_code(400);
                    echo json_encode(['error' => 'passwordとhashが必要です']);
                    return;
                }
                
                $isValid = $passwordManager->verifyPassword($input['hash'], $input['password']);
                echo json_encode([
                    'success' => true,
                    'valid' => $isValid,
                    'timestamp' => time()
                ]);
                break;
                
            default:
                http_response_code(400);
                echo json_encode(['error' => '無効なaction']);
        }
    } catch (Exception $e) {
        http_response_code(500);
        echo json_encode(['error' => 'サーバーエラー: ' . $e->getMessage()]);
    }
}

// API使用時は以下を有効化
// handlePasswordAPI();
?>